diff --git a/REFERENCE.md b/REFERENCE.md index d7173cf7e4..219bd1aad6 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -211,6 +211,7 @@ Options: * **:sources.list.d** `Boolean`: Specifies whether to purge any unmanaged entries from sources.list.d. Default false. * **:preferences** `Boolean`: Specifies whether to purge any unmanaged entries from preferences. Default false. * **:preferences.d.** `Boolean`: Specifies whether to purge any unmanaged entries from preferences.d. Default false. +* **:keyrings** `Boolean`: Specifies whether to purge any unmanaged entries from keyrings. Default false. Default value: `{}` @@ -230,6 +231,7 @@ Default value: 'preferences.d' => false, 'apt.conf.d' => false, 'auth.conf.d' => false, + 'keyrings' => false, } ``` @@ -797,11 +799,11 @@ The following parameters are available in the `apt::keyring` defined type: ##### `dir` -Data type: `Stdlib::Absolutepath` +Data type: `Optional[Stdlib::Absolutepath]` Path to the directory where the keyring will be stored. -Default value: `'/etc/apt/keyrings'` +Default value: `undef` ##### `filename` diff --git a/manifests/init.pp b/manifests/init.pp index c144bcf525..c82c05de6e 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -75,6 +75,9 @@ # @option purge [Boolean] :preferences.d. # Specifies whether to purge any unmanaged entries from preferences.d. Default false. # +# @option purge [Boolean] :keyrings +# Specifies whether to purge any unmanaged entries from keyrings. Default false. +# # @param purge_defaults # The default purge settings that are combined and merged with the passed `purge` value # @@ -168,6 +171,7 @@ 'preferences.d' => false, 'apt.conf.d' => false, 'auth.conf.d' => false, + 'keyrings' => false, }, Hash $proxy_defaults = { 'ensure' => undef, @@ -276,6 +280,9 @@ if $purge['auth.conf.d'] { assert_type(Boolean, $purge['auth.conf.d']) } + if $purge['keyrings'] { + assert_type(Boolean, $purge['keyrings']) + } $_purge = $apt::purge_defaults + $purge @@ -401,6 +408,17 @@ notify => Class['apt::update'], } + file { 'keyrings': + ensure => directory, + path => "${root}/keyrings", + owner => root, + group => root, + mode => '0755', + purge => $_purge['keyrings'], + recurse => $_purge['keyrings'], + notify => Class['apt::update'], + } + $confs.each |$key, $value| { apt::conf { $key: * => $value, diff --git a/manifests/keyring.pp b/manifests/keyring.pp index c1617e17d7..95223fefe0 100644 --- a/manifests/keyring.pp +++ b/manifests/keyring.pp @@ -33,21 +33,32 @@ # Ensure presence or absence of the resource. # define apt::keyring ( - Stdlib::Absolutepath $dir = '/etc/apt/keyrings', + Optional[Stdlib::Absolutepath] $dir = undef, String[1] $filename = $name, Stdlib::Filemode $mode = '0644', Optional[Stdlib::Filesource] $source = undef, Optional[String[1]] $content = undef, Enum['present','absent'] $ensure = 'present', ) { - ensure_resource('file', $dir, { ensure => 'directory', mode => '0755', }) + include apt + + # Use the keyrings directory managed by apt class if default is used + $_dir = pick($dir, "${apt::root}/keyrings") + + if $_dir == "${apt::root}/keyrings" { + $require_dir = File['keyrings'] + } else { + ensure_resource('file', $_dir, { ensure => 'directory', mode => '0755', }) + $require_dir = File[$_dir] + } + if $source and $content { fail("Parameters 'source' and 'content' are mutually exclusive") } elsif $ensure == 'present' and ! $source and ! $content { fail("One of 'source' or 'content' parameters are required") } - $file = "${dir}/${filename}" + $file = "${_dir}/${filename}" case $ensure { 'present': { @@ -58,6 +69,7 @@ group => 'root', source => $source, content => $content, + require => $require_dir, } } 'absent': { diff --git a/spec/classes/apt_spec.rb b/spec/classes/apt_spec.rb index 13bf907880..556792d0b4 100644 --- a/spec/classes/apt_spec.rb +++ b/spec/classes/apt_spec.rb @@ -46,6 +46,15 @@ recurse: false, notify: 'Class[Apt::Update]' } +keyrings = { ensure: 'directory', + path: '/etc/apt/keyrings', + owner: 'root', + group: 'root', + mode: '0755', + purge: false, + recurse: false, + notify: 'Class[Apt::Update]' } + describe 'apt' do let(:facts) do { @@ -89,6 +98,10 @@ is_expected.to contain_file('auth.conf.d').that_notifies('Class[Apt::Update]').only_with(auth_conf_d) } + it { + is_expected.to contain_file('keyrings').that_notifies('Class[Apt::Update]').only_with(keyrings) + } + it { is_expected.to contain_file('/etc/apt/auth.conf').with_ensure('absent') } it 'lays down /etc/apt/apt.conf.d/15update-stamp' do @@ -252,7 +265,7 @@ update: { 'frequency' => 'always', 'timeout' => 1, 'tries' => 3 }, purge: { 'sources.list' => false, 'sources.list.d' => false, 'preferences' => false, 'preferences.d' => false, - 'apt.conf.d' => false } + 'apt.conf.d' => false, 'keyrings' => false } } end @@ -279,6 +292,11 @@ recurse: false) } + it { + expect(subject).to contain_file('keyrings').with(purge: false, + recurse: false) + } + it { expect(subject).to contain_exec('apt_update').with(refreshonly: false, timeout: 1, @@ -292,7 +310,7 @@ update: { 'frequency' => 'always', 'timeout' => 1, 'tries' => 3 }, purge: { 'sources.list' => true, 'sources.list.d' => true, 'preferences' => true, 'preferences.d' => true, - 'apt.conf.d' => true } + 'apt.conf.d' => true, 'keyrings' => true } } end @@ -319,6 +337,11 @@ recurse: true) } + it { + expect(subject).to contain_file('keyrings').with(purge: true, + recurse: true) + } + it { expect(subject).to contain_exec('apt_update').with(refreshonly: false, timeout: 1, @@ -724,5 +747,13 @@ expect(subject).to raise_error(Puppet::Error) end end + + context "with purge['keyrings']=>'banana'" do + let(:params) { { purge: { 'keyrings' => 'banana' } } } + + it do + expect(subject).to raise_error(Puppet::Error) + end + end end end diff --git a/spec/defines/keyring_spec.rb b/spec/defines/keyring_spec.rb index 6b3c65e1ef..d1ac2cfbaa 100644 --- a/spec/defines/keyring_spec.rb +++ b/spec/defines/keyring_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'apt::keyring' do - let(:title) { 'namevar' } + let(:title) { 'puppetlabs-keyring.gpg' } let(:params) do { source: 'http://apt.puppetlabs.com/pubkey.gpg', @@ -15,6 +15,115 @@ let(:facts) { os_facts } it { is_expected.to compile } + + context 'with default directory' do + it { + expect(subject).to contain_file('/etc/apt/keyrings/puppetlabs-keyring.gpg').with( + ensure: 'file', + mode: '0644', + owner: 'root', + group: 'root', + source: 'http://apt.puppetlabs.com/pubkey.gpg', + ).that_requires('File[keyrings]') + } + + it { + expect(subject).to contain_class('apt') + } + end + + context 'with custom directory' do + let(:params) do + { + source: 'http://apt.puppetlabs.com/pubkey.gpg', + dir: '/usr/share/keyrings', + } + end + + it { + expect(subject).to contain_file('/usr/share/keyrings/puppetlabs-keyring.gpg').with( + ensure: 'file', + mode: '0644', + owner: 'root', + group: 'root', + source: 'http://apt.puppetlabs.com/pubkey.gpg', + ).that_requires('File[/usr/share/keyrings]') + } + + it { + expect(subject).to contain_file('/usr/share/keyrings').with( + ensure: 'directory', + mode: '0755', + ) + } + end + + context 'with content parameter' do + let(:params) do + { + content: 'GPG KEY CONTENT', + } + end + + it { + expect(subject).to contain_file('/etc/apt/keyrings/puppetlabs-keyring.gpg').with( + ensure: 'file', + content: 'GPG KEY CONTENT', + ) + } + end + + context 'with custom filename' do + let(:params) do + { + source: 'http://apt.puppetlabs.com/pubkey.gpg', + filename: 'custom-name.gpg', + } + end + + it { + expect(subject).to contain_file('/etc/apt/keyrings/custom-name.gpg') + } + end + + context 'with ensure absent' do + let(:params) do + { + ensure: 'absent', + } + end + + it { + expect(subject).to contain_file('/etc/apt/keyrings/puppetlabs-keyring.gpg').with( + ensure: 'absent', + ) + } + end + + context 'with both source and content' do + let(:params) do + { + source: 'http://apt.puppetlabs.com/pubkey.gpg', + content: 'GPG KEY CONTENT', + } + end + + it { + expect(subject).to raise_error(%r{Parameters 'source' and 'content' are mutually exclusive}) + } + end + + context 'without source or content and ensure present' do + let(:params) do + { + ensure: 'present', + } + end + + it { + expect(subject).to raise_error(%r{One of 'source' or 'content' parameters are required}) + } + end end end end