+##2014-06-04 - Release 1.5.0
+###Summary
+
+This release adds support for Ubuntu 14.04. It also includes many new features
+and important bugfixes. One huge change is that apt::key was replaced with
+apt_key, which allows you to use puppet resource apt_key to inventory keys on
+your system.
+
+Special thanks to daenney, our intrepid unofficial apt maintainer!
+
+####Features
+- Add support for Ubuntu Trusty!
+- Add apt::hold define
+- Generate valid *.pref files in apt::pin
+- Made pin_priority configurable for apt::backports
+- Add apt_key type and provider
+- Rename "${apt_conf_d}/proxy" to "${apt_conf_d}/01proxy"
+- apt::key rewritten to use apt_key type
+- Add support for update_tries to apt::update
+
+####Bugfixes
+- Typo fixes
+- Fix unattended upgrades
+- Removed bogus line when using purge_preferences
+- Fix apt::force to upgrade allow packages to be upgraded to the pacakge from the specified release
+
##2014-03-04 - Supported Release 1.4.2
###Summary
name 'puppetlabs-apt'
-version '1.4.2'
+version '1.5.0'
source 'https://github.com/puppetlabs/puppetlabs-apt'
author 'Evolving Web / Puppet Labs'
license 'Apache License 2.0'
key_server => 'pgp.mit.edu',
}
+### Facts
+
+There are a few facts included within the apt module describing the state of the apt system:
+
+* `apt_updates` - the number of updates available on the system
+* `apt_security_updates` - the number of updates which are security updates
+* `apt_package_updates` - the package names that are available for update. On Facter 2.0 and newer this will be a list type, in earlier versions it is a comma delimitered string.
#### Hiera example
<pre>
--- /dev/null
+Facter.add("apt_package_updates") do
+ confine :osfamily => 'Debian'
+ setcode do
+ if File.executable?("/usr/lib/update-notifier/apt-check")
+ packages = Facter::Util::Resolution.exec('/usr/lib/update-notifier/apt-check -p 2>&1')
+ packages = packages.split("\n")
+ if Facter.version < '2.0.0'
+ packages = packages.join(',')
+ end
+ packages
+ end
+ end
+end
--- /dev/null
+Facter.add("apt_security_updates") do
+ confine :osfamily => 'Debian'
+ setcode do
+ if File.executable?("/usr/lib/update-notifier/apt-check")
+ updates = Facter::Util::Resolution.exec('/usr/lib/update-notifier/apt-check 2>&1')
+ Integer(updates.strip.split(';')[1])
+ end
+ end
+end
--- /dev/null
+Facter.add("apt_updates") do
+ confine :osfamily => 'Debian'
+ setcode do
+ if File.executable?("/usr/lib/update-notifier/apt-check")
+ updates = Facter::Util::Resolution.exec('/usr/lib/update-notifier/apt-check 2>&1')
+ Integer(updates.strip.split(';')[0])
+ end
+ end
+end
commands :apt_key => 'apt-key'
def self.instances
+ if RUBY_VERSION > '1.8.7'
+ key_output = apt_key('list').encode('UTF-8', 'binary', :invalid => :replace, :undef => :replace, :replace => '')
+ else
+ key_output = apt_key('list')
+ end
key_array = apt_key('list').split("\n").collect do |line|
line_hash = key_line_hash(line)
next unless line_hash
end
newparam(:server) do
- desc 'The key server to fetch the key from based on the ID.'
+ desc 'The key server to fetch the key from based on the ID. It can either be a domain name or url.'
defaultto :'keyserver.ubuntu.com'
- # Need to validate this, preferably through stdlib is_fqdn
- # but still working on getting to that.
+
+ newvalues(/\A((hkp|http|https):\/\/)?([a-z\d])([a-z\d-]{0,61}\.)+[a-z\d]+(:\d{2,4})?$/)
end
newparam(:keyserver_options) do
owner => root,
group => root,
}
-
+
file { 'old-proxy-file':
ensure => absent,
path => "${apt_conf_d}/proxy",
# [*key_server*]
# _default_: +undef+
#
-# The keyserver from where to fetch our GPG key. It defaults to
+# The keyserver from where to fetch our GPG key. It can either be a domain
+# name or url. It defaults to
# undef which results in apt_key's default keyserver being used,
# currently +keyserver.ubuntu.com+.
#
}
if $key_server {
- if !is_domain_name($key_server) {
- fail('$key_server must be a valid domain name')
- }
+ validate_re($key_server,['\A((hkp|http|https):\/\/)?([a-z\d])([a-z\d-]{0,61}\.)+[a-z\d]+(:\d{2,4})?$'])
}
if $key_options {
$backports_location = 'http://backports.debian.org/debian-backports'
$legacy_origin = true
$origins = ['${distro_id} oldstable',
- '${distro_id} ${distro_codename}-security']
+ '${distro_id} ${distro_codename}-security',
+ '${distro_id} ${distro_codename}-lts']
}
'wheezy': {
$backports_location = 'http://ftp.debian.org/debian/'
}
if $::operatingsystem != 'Ubuntu' {
- fail("apt::ppa is currently supported on Ubuntu only.")
+ fail('apt::ppa is currently supported on Ubuntu only.')
}
$filename_without_slashes = regsubst($name, '/', '-', 'G')
class apt::unattended_upgrades (
$origins = $::apt::params::origins,
$blacklist = [],
- $update = "1",
- $download = "1",
- $upgrade = "1",
- $autoclean = "7",
+ $update = '1',
+ $download = '1',
+ $upgrade = '1',
+ $autoclean = '7',
$auto_fix = true,
$minimal_steps = false,
$install_on_shutdown = false,
- $mail_to = "NONE",
+ $mail_to = 'NONE',
$mail_only_on_error = false,
$remove_unused = true,
$auto_reboot = false,
- $dl_limit = "NONE",
- $enable = "1",
- $backup_interval = "0",
- $backup_level = "3",
- $max_age = "0",
- $min_age = "0",
- $max_size = "0",
- $download_delta = "0",
- $verbose = "0",
+ $dl_limit = 'NONE',
+ $enable = '1',
+ $backup_interval = '0',
+ $backup_level = '3',
+ $max_age = '0',
+ $min_age = '0',
+ $max_size = '0',
+ $download_delta = '0',
+ $verbose = '0',
) inherits ::apt::params {
validate_bool(
{
"name": "puppetlabs-apt",
- "version": "1.4.1",
+ "version": "1.5.0",
"source": "https://github.com/puppetlabs/puppetlabs-apt",
"author": "Puppet Labs",
"license": "Apache-2.0",
"operatingsystem": "Ubuntu",
"operatingsystemrelease": [
"10.04",
- "12.04"
+ "12.04",
+ "14.04"
]
}
],
"requirements": [
- { "name": "pe", "version_requirement": "3.2.x" },
+ { "name": "pe", "version_requirement": ">= 3.2.0 < 3.4.0" },
{ "name": "puppet", "version_requirement": "3.x" }
],
"dependencies": []
end
end
+ context 'hkp://pgp.mit.edu:80' do
+ it 'works' do
+ pp = <<-EOS
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_ID}',
+ ensure => 'present',
+ server => 'hkp://pgp.mit.edu:80',
+ }
+ EOS
+
+ apply_manifest(pp, :catch_failures => true)
+ expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
+ shell("apt-key list | grep #{PUPPETLABS_GPG_KEY_ID}")
+ end
+ end
+
context 'nonexistant.key.server' do
it 'fails' do
pp = <<-EOS
end
end
end
+
+ context 'key server start with dot' do
+ it 'fails' do
+ pp = <<-EOS
+ apt_key { 'puppetlabs':
+ id => '#{PUPPETLABS_GPG_KEY_ID}',
+ ensure => 'present',
+ server => '.pgp.key.server',
+ }
+ EOS
+
+ apply_manifest(pp, :expect_failures => true) do |r|
+ expect(r.stderr).to match(/Invalid value \".pgp.key.server\"/)
+ end
+ end
+ end
end
describe 'source =>' do
it { should contain_file('puppetlabs.list').with_content(/^deb http:\/\/apt.puppetlabs.com precise main$/) }
it { should contain_file('puppetlabs.list').with_content(/^deb-src http:\/\/apt.puppetlabs.com precise main$/) }
end
+
+ context 'with unsupported osfamily' do
+ let :facts do
+ { :osfamily => 'Darwin', }
+ end
+
+ it do
+ expect {
+ should compile
+ }.to raise_error(Puppet::Error, /This module only works on Debian or derivatives like Ubuntu/)
+ end
+ end
end
it {
should contain_file(file_unattended).with_content(
/^Unattended-Upgrade::Allowed-Origins/
+ ).with_content(
+ /"\${distro_id} \${distro_codename}-lts";/
).with_content(
/"\${distro_id} \${distro_codename}-security";/
).with_content(
end
describe 'key_server =>' do
- let :params do {
- :key_server => 'pgp.mit.edu',
- } end
+ context 'domain name' do
+ let :params do {
+ :key_server => 'pgp.mit.edu',
+ } end
- it 'contains the apt::key' do
- should contain_apt__key(title).with({
- :key => title,
- :ensure => 'present',
- :key_server => 'pgp.mit.edu',
- })
+ it 'contains the apt::key' do
+ should contain_apt__key(title).with({
+ :key => title,
+ :ensure => 'present',
+ :key_server => 'pgp.mit.edu',
+ })
+ end
+ it 'contains the apt_key' do
+ should contain_apt_key(title).with({
+ :id => title,
+ :ensure => 'present',
+ :source => nil,
+ :server => params[:key_server],
+ :content => nil,
+ :keyserver_options => nil,
+ })
+ end
+ it 'contains the apt_key present anchor' do
+ should contain_anchor("apt_key #{title} present")
+ end
+ end
+
+ context "domain with dash" do
+ let(:params) do{
+ :key_server => 'p-gp.m-it.edu',
+ } end
+ it "should contain apt::key" do
+ should contain_apt__key(title).with({
+ :key => title,
+ :ensure => 'present',
+ :key_server => 'p-gp.m-it.edu',
+ })
+ end
end
- it 'contains the apt_key' do
- should contain_apt_key(title).with({
- :id => title,
- :ensure => 'present',
- :source => nil,
- :server => params[:key_server],
- :content => nil,
- :keyserver_options => nil,
- })
+
+ context "domain begin with dash" do
+ let(:params) do{
+ :key_server => '-pgp.mit.edu',
+ } end
+ it 'fails' do
+ expect { subject } .to raise_error(/does not match/)
+ end
end
- it 'contains the apt_key present anchor' do
- should contain_anchor("apt_key #{title} present")
+
+ context "domain begin with dot" do
+ let(:params) do{
+ :key_server => '.pgp.mit.edu',
+ } end
+ it 'fails' do
+ expect { subject } .to raise_error(/does not match/)
+ end
end
- end
+
+ context "domain end with dot" do
+ let(:params) do{
+ :key_server => "pgp.mit.edu.",
+ } end
+ it 'fails' do
+ expect { subject } .to raise_error(/does not match/)
+ end
+ end
+
+ context "url" do
+ let (:params) do{
+ :key_server => 'hkp://pgp.mit.edu',
+ } end
+ it "should contain apt::key" do
+ should contain_apt__key(title).with({
+ :key => title,
+ :ensure => 'present',
+ :key_server => 'hkp://pgp.mit.edu',
+ })
+ end
+ end
+ context "url with port number" do
+ let (:params) do{
+ :key_server => 'hkp://pgp.mit.edu:80',
+ } end
+ it "should contain apt::key" do
+ should contain_apt__key(title).with({
+ :key => title,
+ :ensure => 'present',
+ :key_server => 'hkp://pgp.mit.edu:80',
+ })
+ end
+ end
+
+ context "incorrect port number url" do
+ let (:params) do{
+ :key_server => 'hkp://pgp.mit.edu:8008080'
+ } end
+ it 'fails' do
+ expect { subject }.to raise_error(/does not match/)
+ end
+ end
+ context "incorrect protocol for url" do
+ let (:params) do{
+ :key_server => 'abc://pgp.mit.edu:80'
+ } end
+ it 'fails' do
+ expect { subject }.to raise_error(/does not match/)
+ end
+ end
+ context "missing port number url" do
+ let (:params) do{
+ :key_server => 'hkp://pgp.mit.edu:'
+ } end
+ it 'fails' do
+ expect { subject }.to raise_error(/does not match/)
+ end
+ end
+ context "url ending with a dot" do
+ let (:params) do{
+ :key_server => 'hkp://pgp.mit.edu.'
+ } end
+ it 'fails' do
+ expect { subject }.to raise_error(/does not match/)
+ end
+ end
+ context "url begin with a dash" do
+ let(:params) do{
+ :key_server => "hkp://-pgp.mit.edu",
+ } end
+ it 'fails' do
+ expect { subject }.to raise_error(/does not match/)
+ end
+ end
+ context "url with dash" do
+ let(:params) do{
+ :key_server => 'hkp://p-gp.m-it.edu',
+ } end
+ it "should contain apt::key" do
+ should contain_apt__key(title).with({
+ :key => title,
+ :ensure => 'present',
+ :key_server => 'hkp://p-gp.m-it.edu',
+ })
+ end
+ end
+ context "exceed characher url" do
+ let (:params) do{
+ :key_server => 'hkp://pgpiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii.mit.edu'
+ } end
+ it 'fails' do
+ expect { subject }.to raise_error(/does not match/)
+ end
+ end
+ end
describe 'key_options =>' do
let :params do {
:key_server => 'two bottles of rum',
} end
it 'fails' do
- expect { subject }.to raise_error(/must be a valid domain name/)
+ expect { subject }.to raise_error(/does not match/)
end
end
--- /dev/null
+require 'spec_helper'
+
+describe 'apt_package_updates fact' do
+ subject { Facter.fact(:apt_package_updates).value }
+ after(:each) { Facter.clear }
+
+ describe 'on Debian based distro missing update-notifier-common' do
+ before {
+ Facter.fact(:osfamily).stubs(:value).returns 'Debian'
+ File.stubs(:executable?).returns false
+ }
+ it { should == nil }
+ end
+
+ describe 'on Debian based distro' do
+ before {
+ Facter.fact(:osfamily).stubs(:value).returns 'Debian'
+ File.stubs(:executable?).returns true
+ Facter::Util::Resolution.stubs(:exec).returns "puppet-common\nlinux-generic\nlinux-image-generic"
+ }
+ it {
+ if Facter.version < '2.0.0'
+ should == 'puppet-common,linux-generic,linux-image-generic'
+ else
+ should == ['puppet-common', 'linux-generic', 'linux-image-generic']
+ end
+ }
+ end
+end
--- /dev/null
+require 'spec_helper'
+
+describe 'apt_security_updates fact' do
+ subject { Facter.fact(:apt_security_updates).value }
+ after(:each) { Facter.clear }
+
+ describe 'on Debian based distro missing update-notifier-common' do
+ before {
+ Facter.fact(:osfamily).stubs(:value).returns 'Debian'
+ File.stubs(:executable?).returns false
+ }
+ it { should == nil }
+ end
+
+ describe 'on Debian based distro' do
+ before {
+ Facter.fact(:osfamily).stubs(:value).returns 'Debian'
+ File.stubs(:executable?).returns true
+ Facter::Util::Resolution.stubs(:exec).returns '14;7'
+ }
+ it { should == 7 }
+ end
+
+end
--- /dev/null
+require 'spec_helper'
+
+describe 'apt_updates fact' do
+ subject { Facter.fact(:apt_updates).value }
+ after(:each) { Facter.clear }
+
+ describe 'on Debian based distro missing update-notifier-common' do
+ before {
+ Facter.fact(:osfamily).stubs(:value).returns 'Debian'
+ File.stubs(:executable?).returns false
+ }
+ it { should == nil }
+ end
+
+ describe 'on Debian based distro' do
+ before {
+ Facter.fact(:osfamily).stubs(:value).returns 'Debian'
+ File.stubs(:executable?).returns true
+ Facter::Util::Resolution.stubs(:exec).returns '14;7'
+ }
+ it { should == 14 }
+ end
+
+end