Skip to content

Commit

Permalink
Make provider holdable
Browse files Browse the repository at this point in the history
  • Loading branch information
root-expert committed Sep 14, 2024
1 parent 60f45f5 commit 9f6a313
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 20 deletions.
46 changes: 42 additions & 4 deletions lib/puppet/provider/package/snap.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# frozen_string_literal: true

require 'date'
require 'puppet/provider/package'
require 'puppet_x/snap/api'

Expand All @@ -13,22 +14,27 @@
"

commands snap_cmd: '/usr/bin/snap'
has_feature :installable, :versionable, :install_options, :uninstallable, :purgeable, :upgradeable
has_feature :installable, :versionable, :install_options, :uninstallable, :purgeable, :upgradeable, :holdable
confine feature: %i[net_http_unix_lib snapd_socket]

mk_resource_methods

def self.instances
installed_snaps.map do |snap|
new(name: snap['name'], ensure: snap['tracking-channel'], provider: 'snap')
mark = snap['hold'].nil? ? 'none' : 'hold'
Puppet.info("refresh-inhibit = #{mark}")
new(name: snap['name'], ensure: snap['tracking-channel'], mark: mark, hold_time: snap['hold'], provider: 'snap')
end
end

def query
{ ensure: @property_hash[:ensure], name: @resource[:name] } unless @property_hash.empty?
Puppet.info('called query')
Puppet.info("@property_hash #{@property_hash}")
{ ensure: @property_hash[:ensure], name: @resource[:name], mark: @property_hash[:mark] } unless @property_hash.empty?
end

def install
Puppet.info('called install')
current_ensure = query&.dig(:ensure)

# Refresh the snap if we changed the channel
Expand Down Expand Up @@ -56,6 +62,16 @@ def purge
modify_snap('remove', ['purge'])
end

def hold
Puppet.info('called hold')
modify_snap('hold') unless @property_hash[:mark].equal?('hold') && @property_hash[:hold_time] != @resource[:install_options]
end

def unhold
Puppet.info('called unhold')
modify_snap('unhold') unless @property_hash[:mark].equal?('none')
end

def modify_snap(action, options = @resource[:install_options])
body = self.class.generate_request(action, determine_channel, options)
response = PuppetX::Snap::API.post("/v2/snaps/#{@resource[:name]}", body)
Expand All @@ -73,6 +89,7 @@ def determine_channel
def self.generate_request(action, channel, options)
request = { 'action' => action }
request['channel'] = channel unless channel.nil?
request['hold-level'] = 'general' if action.equal?('hold')

if options
# classic, devmode and jailmode params are only
Expand All @@ -84,9 +101,17 @@ def self.generate_request(action, channel, options)
request['jailmode'] = true if options.include?('jailmode')
when 'remove'
request['purge'] = true if options.include?('purge')
when 'hold'
time = parse_time_from_options(options)
request['time'] = time
end
elsif action.equal?('hold')
# If no options defined assume hold time forever
request['time'] = 'forever'
end

Puppet.info("request = #{request}")

request
end

Expand All @@ -100,6 +125,19 @@ def self.channel_from_ensure(value)
end
end

def self.parse_time_from_options(options)
time = options&.find { |opt| %r{hold_time} =~ opt }&.split('=')&.last

# Assume forever if not hold_time was specified
return 'forever' if time.nil? || time.equal?('forever')

begin
DateTime.parse(time).rfc3339
rescue Date::Error
raise Puppet::Error, 'Date not in correct format.'
end
end

def self.channel_from_options(options)
options&.find { |e| %r{channel} =~ e }&.split('=')&.last&.tap do |ch|
Puppet.warning("Install option 'channel' is deprecated, use ensure => '#{ch}' instead.")
Expand All @@ -110,6 +148,6 @@ def self.installed_snaps
res = PuppetX::Snap::API.get('/v2/snaps')
raise Puppet::Error, "Could not find installed snaps (code: #{res['status-code']})" unless [200, 404].include?(res['status-code'])

res['status-code'] == 200 ? res['result'].map { |hash| hash.slice('name', 'tracking-channel') } : []
res['status-code'] == 200 ? res['result'].map { |hash| hash.slice('name', 'tracking-channel', 'hold') } : []
end
end
120 changes: 104 additions & 16 deletions spec/acceptance/01_snapd_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,35 +96,123 @@
end
end
end
end

describe 'purges the package' do
let(:manifest) do
<<-PUPPET
describe 'holds the package (prevents refresh)' do
let(:manifest) do
<<-PUPPET
package { 'hello-world':
ensure => 'latest/beta',
mark => 'hold',
provider => 'snap',
}
PUPPET
end

it_behaves_like 'an idempotent resource'

describe command('snap list --unicode=never --color=never') do
its(:stdout) do
is_expected.to match(%r{hello-world})
is_expected.to match(%r{beta})
is_expected.to match(%r{held})
end
end
end

describe 'can change channel while held' do
let(:manifest) do
<<-PUPPET
package { 'hello-world':
ensure => 'latest/candidate',
mark => 'hold',
provider => 'snap',
}
PUPPET
end

it_behaves_like 'an idempotent resource'

describe command('snap list --unicode=never --color=never') do
its(:stdout) do
is_expected.to match(%r{hello-world})
is_expected.to match(%r{candidate})
is_expected.to match(%r{held})
end
end
end

describe 'hold until specified date' do
let(:manifest) do
<<-PUPPET
package { 'hello-world':
ensure => 'latest/candidate',
mark => 'hold',
install_options => 'hold_time=2025-10-10', # Non RFC3339, it should be parsed correctly
provider => 'snap',
}
PUPPET
end

it_behaves_like 'an idempotent resource'

describe command('snap list --unicode=never --color=never') do
its(:stdout) do
is_expected.to match(%r{hello-world})
is_expected.to match(%r{candidate})
is_expected.to match(%r{held})
end
end
end

describe 'unholds the package' do
let(:manifest) do
<<-PUPPET
package { 'hello-world':
ensure => 'latest/candidate',
provider => 'snap',
}
PUPPET
end

it_behaves_like 'an idempotent resource'

describe command('snap list --unicode=never --color=never') do
its(:stdout) do

Check failure on line 180 in spec/acceptance/01_snapd_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Puppet 8 - Debian 12

snapd class package resource unholds the package Command "snap list --unicode=never --color=never" stdout is expected not to match /held/ Failure/Error: is_expected.not_to match(%r{held}) expected "Name Version Rev Tracking Publisher Notes\ncore 16-2.61.4... canonical** core\nhello-world 6.4 29 latest/candidate canonical** held\n" not to match /held/ Diff: @@ -1,3 +1,5 @@ -/held/ +Name Version Rev Tracking Publisher Notes +core 16-2.61.4-20240607 17200 latest/stable canonical** core +hello-world 6.4 29 latest/candidate canonical** held

Check failure on line 180 in spec/acceptance/01_snapd_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Puppet 8 - Fedora 40

snapd class package resource unholds the package Command "snap list --unicode=never --color=never" stdout is expected not to match /held/ Failure/Error: is_expected.not_to match(%r{held}) expected "Name Version Rev Tracking Publisher Notes\ncore 16-2.61.4... canonical** core\nhello-world 6.4 29 latest/candidate canonical** held\n" not to match /held/ Diff: @@ -1,3 +1,5 @@ -/held/ +Name Version Rev Tracking Publisher Notes +core 16-2.61.4-20240607 17200 latest/stable canonical** core +hello-world 6.4 29 latest/candidate canonical** held

Check failure on line 180 in spec/acceptance/01_snapd_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Puppet 8 - Ubuntu 22.04

snapd class package resource unholds the package Command "snap list --unicode=never --color=never" stdout is expected not to match /held/ Failure/Error: is_expected.not_to match(%r{held}) expected "Name Version Rev Tracking Publisher Notes\ncore 16-2.61.4... canonical** core\nhello-world 6.4 29 latest/candidate canonical** held\n" not to match /held/ Diff: @@ -1,3 +1,5 @@ -/held/ +Name Version Rev Tracking Publisher Notes +core 16-2.61.4-20240607 17200 latest/stable canonical** core +hello-world 6.4 29 latest/candidate canonical** held

Check failure on line 180 in spec/acceptance/01_snapd_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Puppet 8 - Ubuntu 24.04

snapd class package resource unholds the package Command "snap list --unicode=never --color=never" stdout is expected not to match /held/ Failure/Error: is_expected.not_to match(%r{held}) expected "Name Version Rev Tracking Publisher Notes\ncore 16-2.61.4... canonical** core\nhello-world 6.4 29 latest/candidate canonical** held\n" not to match /held/ Diff: @@ -1,3 +1,5 @@ -/held/ +Name Version Rev Tracking Publisher Notes +core 16-2.61.4-20240607 17200 latest/stable canonical** core +hello-world 6.4 29 latest/candidate canonical** held

Check failure on line 180 in spec/acceptance/01_snapd_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Puppet 7 - Debian 12

snapd class package resource unholds the package Command "snap list --unicode=never --color=never" stdout is expected not to match /held/ Failure/Error: is_expected.not_to match(%r{held}) expected "Name Version Rev Tracking Publisher Notes\ncore 16-2.61.4... canonical** core\nhello-world 6.4 29 latest/candidate canonical** held\n" not to match /held/ Diff: @@ -1,3 +1,5 @@ -/held/ +Name Version Rev Tracking Publisher Notes +core 16-2.61.4-20240607 17200 latest/stable canonical** core +hello-world 6.4 29 latest/candidate canonical** held

Check failure on line 180 in spec/acceptance/01_snapd_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Puppet 8 - Debian 11

snapd class package resource unholds the package Command "snap list --unicode=never --color=never" stdout is expected not to match /held/ Failure/Error: is_expected.not_to match(%r{held}) expected "Name Version Rev Tracking Publisher Notes\ncore 16-2.61.4... canonical** core\nhello-world 6.4 29 latest/candidate canonical** held\n" not to match /held/ Diff: @@ -1,3 +1,5 @@ -/held/ +Name Version Rev Tracking Publisher Notes +core 16-2.61.4-20240607 17200 latest/stable canonical** core +hello-world 6.4 29 latest/candidate canonical** held

Check failure on line 180 in spec/acceptance/01_snapd_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Puppet 7 - Debian 11

snapd class package resource unholds the package Command "snap list --unicode=never --color=never" stdout is expected not to match /held/ Failure/Error: is_expected.not_to match(%r{held}) expected "Name Version Rev Tracking Publisher Notes\ncore 16-2.61.4... canonical** core\nhello-world 6.4 29 latest/candidate canonical** held\n" not to match /held/ Diff: @@ -1,3 +1,5 @@ -/held/ +Name Version Rev Tracking Publisher Notes +core 16-2.61.4-20240607 17200 latest/stable canonical** core +hello-world 6.4 29 latest/candidate canonical** held

Check failure on line 180 in spec/acceptance/01_snapd_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Puppet 7 - Ubuntu 22.04

snapd class package resource unholds the package Command "snap list --unicode=never --color=never" stdout is expected not to match /held/ Failure/Error: is_expected.not_to match(%r{held}) expected "Name Version Rev Tracking Publisher Notes\ncore 16-2.61.4... canonical** core\nhello-world 6.4 29 latest/candidate canonical** held\n" not to match /held/ Diff: @@ -1,3 +1,5 @@ -/held/ +Name Version Rev Tracking Publisher Notes +core 16-2.61.4-20240607 17200 latest/stable canonical** core +hello-world 6.4 29 latest/candidate canonical** held

Check failure on line 180 in spec/acceptance/01_snapd_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Puppet 8 - Ubuntu 20.04

snapd class package resource unholds the package Command "snap list --unicode=never --color=never" stdout is expected not to match /held/ Failure/Error: is_expected.not_to match(%r{held}) expected "Name Version Rev Tracking Publisher Notes\ncore 16-2.61.4... canonical** core\nhello-world 6.4 29 latest/candidate canonical** held\n" not to match /held/ Diff: @@ -1,3 +1,5 @@ -/held/ +Name Version Rev Tracking Publisher Notes +core 16-2.61.4-20240607 17200 latest/stable canonical** core +hello-world 6.4 29 latest/candidate canonical** held

Check failure on line 180 in spec/acceptance/01_snapd_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Puppet 7 - Fedora 40

snapd class package resource unholds the package Command "snap list --unicode=never --color=never" stdout is expected not to match /held/ Failure/Error: is_expected.not_to match(%r{held}) expected "Name Version Rev Tracking Publisher Notes\ncore 16-2.61.4... canonical** core\nhello-world 6.4 29 latest/candidate canonical** held\n" not to match /held/ Diff: @@ -1,3 +1,5 @@ -/held/ +Name Version Rev Tracking Publisher Notes +core 16-2.61.4-20240607 17200 latest/stable canonical** core +hello-world 6.4 29 latest/candidate canonical** held

Check failure on line 180 in spec/acceptance/01_snapd_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Puppet 8 - CentOS 9

snapd class package resource unholds the package Command "snap list --unicode=never --color=never" stdout is expected not to match /held/ Failure/Error: is_expected.not_to match(%r{held}) expected "Name Version Rev Tracking Publisher Notes\ncore 16-2.61.4... canonical** core\nhello-world 6.4 29 latest/candidate canonical** held\n" not to match /held/ Diff: @@ -1,3 +1,5 @@ -/held/ +Name Version Rev Tracking Publisher Notes +core 16-2.61.4-20240607 17200 latest/stable canonical** core +hello-world 6.4 29 latest/candidate canonical** held

Check failure on line 180 in spec/acceptance/01_snapd_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Puppet 7 - OracleLinux 9

snapd class package resource unholds the package Command "snap list --unicode=never --color=never" stdout is expected not to match /held/ Failure/Error: is_expected.not_to match(%r{held}) expected "Name Version Rev Tracking Publisher Notes\ncore 16-2.61.4... canonical** core\nhello-world 6.4 29 latest/candidate canonical** held\n" not to match /held/ Diff: @@ -1,3 +1,5 @@ -/held/ +Name Version Rev Tracking Publisher Notes +core 16-2.61.4-20240607 17200 latest/stable canonical** core +hello-world 6.4 29 latest/candidate canonical** held

Check failure on line 180 in spec/acceptance/01_snapd_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Puppet 7 - Ubuntu 24.04

snapd class package resource unholds the package Command "snap list --unicode=never --color=never" stdout is expected not to match /held/ Failure/Error: is_expected.not_to match(%r{held}) expected "Name Version Rev Tracking Publisher Notes\ncore 16-2.61.4... canonical** core\nhello-world 6.4 29 latest/candidate canonical** held\n" not to match /held/ Diff: @@ -1,3 +1,5 @@ -/held/ +Name Version Rev Tracking Publisher Notes +core 16-2.61.4-20240607 17200 latest/stable canonical** core +hello-world 6.4 29 latest/candidate canonical** held

Check failure on line 180 in spec/acceptance/01_snapd_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Puppet 7 - Ubuntu 20.04

snapd class package resource unholds the package Command "snap list --unicode=never --color=never" stdout is expected not to match /held/ Failure/Error: is_expected.not_to match(%r{held}) expected "Name Version Rev Tracking Publisher Notes\ncore 16-2.61.4... canonical** core\nhello-world 6.4 29 latest/candidate canonical** held\n" not to match /held/ Diff: @@ -1,3 +1,5 @@ -/held/ +Name Version Rev Tracking Publisher Notes +core 16-2.61.4-20240607 17200 latest/stable canonical** core +hello-world 6.4 29 latest/candidate canonical** held

Check failure on line 180 in spec/acceptance/01_snapd_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Puppet 7 - CentOS 9

snapd class package resource unholds the package Command "snap list --unicode=never --color=never" stdout is expected not to match /held/ Failure/Error: is_expected.not_to match(%r{held}) expected "Name Version Rev Tracking Publisher Notes\ncore 16-2.61.4... canonical** core\nhello-world 6.4 29 latest/candidate canonical** held\n" not to match /held/ Diff: @@ -1,3 +1,5 @@ -/held/ +Name Version Rev Tracking Publisher Notes +core 16-2.61.4-20240607 17200 latest/stable canonical** core +hello-world 6.4 29 latest/candidate canonical** held

Check failure on line 180 in spec/acceptance/01_snapd_spec.rb

View workflow job for this annotation

GitHub Actions / Puppet / Puppet 8 - OracleLinux 9

snapd class package resource unholds the package Command "snap list --unicode=never --color=never" stdout is expected not to match /held/ Failure/Error: is_expected.not_to match(%r{held}) expected "Name Version Rev Tracking Publisher Notes\ncore 16-2.61.4... canonical** core\nhello-world 6.4 29 latest/candidate canonical** held\n" not to match /held/ Diff: @@ -1,3 +1,5 @@ -/held/ +Name Version Rev Tracking Publisher Notes +core 16-2.61.4-20240607 17200 latest/stable canonical** core +hello-world 6.4 29 latest/candidate canonical** held
is_expected.to match(%r{hello-world})
is_expected.to match(%r{candidate})
is_expected.not_to match(%r{held})
end
end
end

describe 'purges the package' do
let(:manifest) do
<<-PUPPET
package { 'hello-world':
ensure => purged,
provider => snap,
}
PUPPET
end
PUPPET
end

it_behaves_like 'an idempotent resource'
it_behaves_like 'an idempotent resource'

describe command('snap list --unicode=never --color=never') do
its(:stdout) { is_expected.not_to match(%r{hello-world}) }
describe command('snap list --unicode=never --color=never') do
its(:stdout) { is_expected.not_to match(%r{hello-world}) }
end
end
end

# rubocop:disable RSpec/EmptyExampleGroup
describe 'Raises error when ensure => latest' do
manifest = <<-PUPPET
# rubocop:disable RSpec/EmptyExampleGroup
describe 'Raises error when ensure => latest' do
manifest = <<-PUPPET
package { 'hello-world':
ensure => latest,
provider => snap,
}
PUPPET
PUPPET

apply_manifest(manifest, expect_failures: true)
apply_manifest(manifest, expect_failures: true)
end
# rubocop:enable RSpec/EmptyExampleGroup
end
# rubocop:enable RSpec/EmptyExampleGroup
end
1 change: 1 addition & 0 deletions spec/unit/puppet/provider/package/snap_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
it { is_expected.to be_uninstallable }
it { is_expected.to be_purgeable }
it { is_expected.to be_upgradeable }
it { is_expected.to be_holdable }
end

context 'should respond to' do
Expand Down

0 comments on commit 9f6a313

Please sign in to comment.