Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make provider holdable #35

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 42 additions & 3 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,26 @@
"

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
Puppet.info('called query')
{ ensure: @property_hash[:ensure], name: @resource[:name] } 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 +61,18 @@ def purge
modify_snap('remove', ['purge'])
end

def hold
Puppet.info('called hold')
Puppet.info("@property_hash = #{@property_hash}")
Puppet.info("install_options = #{@resource[:install_options]}")
modify_snap('hold') unless @property_hash[:mark].equal?('hold') && @property_hash[:hold_time] == self.class.parse_time_from_options(@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 +90,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 +102,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 +126,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 +149,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 - 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 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 - 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 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 - 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 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 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 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 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

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 - 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 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 - 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 - 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 - 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
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
Loading