Merge pull request #153 from drbop/drbop_unattended_upgrades
authorAshley Penney <ashley.penney@puppetlabs.com>
Mon, 16 Sep 2013 23:18:41 +0000 (16:18 -0700)
committerAshley Penney <ashley.penney@puppetlabs.com>
Mon, 16 Sep 2013 23:18:41 +0000 (16:18 -0700)
Class for managing unattended-upgrades

manifests/unattended_upgrades.pp [new file with mode: 0644]
spec/classes/unattended_upgrades_spec.rb [new file with mode: 0644]
templates/10periodic.erb [new file with mode: 0644]
templates/50unattended-upgrades.erb [new file with mode: 0644]
tests/unattended-upgrades.pp [new file with mode: 0644]

diff --git a/manifests/unattended_upgrades.pp b/manifests/unattended_upgrades.pp
new file mode 100644 (file)
index 0000000..f006bd5
--- /dev/null
@@ -0,0 +1,68 @@
+# Class: apt::unattended_upgrades
+#
+# This class manages the unattended-upgrades package and related configuration
+# files for ubuntu
+#
+# origins are the repositories to automatically upgrade included packages
+# blacklist is a list of packages to not automatically upgrade
+# update is how often to run "apt-get update" in days
+# download is how often to run "apt-get upgrade --download-only" in days
+# upgrade is how often to upgrade packages included in the origins list in days
+# autoclean is how often to run "apt-get autoclean" in days
+#
+# information on the other options can be found in the 50unattended-upgrades
+# file and in /etc/cron.daily/apt
+#
+class apt::unattended_upgrades (
+  $origins = ['${distro_id}:${distro_codename}-security'],
+  $blacklist = [],
+  $update = "1",
+  $download = "1",
+  $upgrade = "1",
+  $autoclean = "7",
+  $auto_fix = true,
+  $minimal_steps = false,
+  $install_on_shutdown = false,
+  $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",
+) {
+
+  validate_bool(
+    $auto_fix,
+    $minimal_steps,
+    $install_on_shutdown,
+    $mail_only_on_error,
+    $remove_unused,
+    $auto_reboot
+  )
+
+  package { 'unattended-upgrades':
+    ensure => present,
+  }
+
+  File {
+    ensure  => file,
+    owner   => 'root',
+    group   => 'root',
+    mode    => '0644',
+    require => Package['unattended-upgrades'],
+  }
+
+  file {
+    '/etc/apt/apt.conf.d/50unattended-upgrades':
+      content => template('apt/50unattended-upgrades.erb');
+    '/etc/apt/apt.conf.d/10periodic':
+      content => template('apt/10periodic.erb');
+  }
+}
diff --git a/spec/classes/unattended_upgrades_spec.rb b/spec/classes/unattended_upgrades_spec.rb
new file mode 100644 (file)
index 0000000..8abc603
--- /dev/null
@@ -0,0 +1,204 @@
+require 'spec_helper'
+describe 'apt::unattended_upgrades', :type => :class do
+  let(:file_unattended) { '/etc/apt/apt.conf.d/50unattended-upgrades' }
+  let(:file_periodic) { '/etc/apt/apt.conf.d/10periodic' }
+
+  it { should contain_package("unattended-upgrades") }
+
+  it {
+    should create_file("/etc/apt/apt.conf.d/50unattended-upgrades").with({
+      "owner"   => "root",
+      "group"   => "root",
+      "mode"    => "0644",
+      "require" => "Package[unattended-upgrades]",
+    })
+  }
+
+  it {
+    should create_file("/etc/apt/apt.conf.d/10periodic").with({
+      "owner"   => "root",
+      "group"   => "root",
+      "mode"    => "0644",
+      "require" => "Package[unattended-upgrades]",
+    })
+  }
+
+  describe "origins" do
+    describe "with param defaults" do
+      let(:params) {{ }}
+      it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Allowed-Origins \{\n\t"\${distro_id}:\${distro_codename}-security";\n\};$/) }
+    end
+
+    describe "with origins => ['ubuntu:precise-security']" do
+      let :params do
+        { :origins => ['ubuntu:precise-security'] }
+      end
+      it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Allowed-Origins \{\n\t"ubuntu:precise-security";\n\};$/) }
+    end
+  end
+
+  describe "blacklist" do
+    describe "with param defaults" do
+      let(:params) {{ }}
+      it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Package-Blacklist \{\n\};$/) }
+    end
+
+    describe "with blacklist => []" do
+      let :params do
+        { :blacklist => ['libc6', 'libc6-dev'] }
+      end
+      it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Package-Blacklist \{\n\t"libc6";\n\t"libc6-dev";\n\};$/) }
+    end
+  end
+
+  describe "with update => 2" do
+    let :params do
+      { :update => "2" }
+    end
+    it { should contain_file(file_periodic).with_content(/^APT::Periodic::Update-Package-Lists "2";$/) }
+  end
+
+  describe "with download => 2" do
+    let :params do
+      { :download => "2" }
+    end
+    it { should contain_file(file_periodic).with_content(/^APT::Periodic::Download-Upgradeable-Packages "2";$/) }
+  end
+
+  describe "with upgrade => 2" do
+    let :params do
+      { :upgrade => "2" }
+    end
+    it { should contain_file(file_periodic).with_content(/^APT::Periodic::Unattended-Upgrade "2";$/) }
+  end
+
+  describe "with autoclean => 2" do
+    let :params do
+      { :autoclean => "2" }
+    end
+    it { should contain_file(file_periodic).with_content(/^APT::Periodic::AutocleanInterval "2";$/) }
+  end
+
+  describe "with auto_fix => false" do
+    let :params do
+      { :auto_fix => false }
+    end
+    it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::AutoFixInterruptedDpkg "false";$/) }
+  end
+
+  describe "with minimal_steps => true" do
+    let :params do
+      { :minimal_steps => true }
+    end
+    it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::MinimalSteps "true";$/) }
+  end
+
+  describe "with install_on_shutdown => true" do
+    let :params do
+      { :install_on_shutdown => true }
+    end
+    it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::InstallOnShutdown "true";$/) }
+  end
+
+  describe "mail_to" do
+    describe "param defaults" do
+      let(:params) {{ }}
+      it { should_not contain_file(file_unattended).with_content(/^Unattended-Upgrade::Mail /) }
+      it { should_not contain_file(file_unattended).with_content(/^Unattended-Upgrade::MailOnlyOnError /) }
+    end
+
+    describe "with mail_to => user@website, mail_only_on_error => true" do
+      let :params do
+        { :mail_to => "user@website",
+          :mail_only_on_error => true }
+      end
+      it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Mail "user@website";$/) }
+      it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::MailOnlyOnError "true";$/) }
+    end
+  end
+
+  describe "with remove_unused => false" do
+    let :params do
+      { :remove_unused => false }
+    end
+    it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Remove-Unused-Dependencies "false";$/) }
+  end
+
+  describe "with auto_reboot => true" do
+    let :params do
+      { :auto_reboot => true }
+    end
+    it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Automatic-Reboot "true";$/) }
+  end
+
+  describe "dl_limit" do
+    describe "param defaults" do
+      let(:params) {{ }}
+      it { should_not contain_file(file_unattended).with_content(/^Acquire::http::Dl-Limit /) }
+    end
+
+    describe "with dl_limit => 70" do
+      let :params do
+        { :dl_limit => "70" }
+      end
+      it { should contain_file(file_unattended).with_content(/^Acquire::http::Dl-Limit "70";$/) }
+    end
+  end
+
+  describe "with enable => 0" do
+    let :params do
+      { :enable => "0" }
+    end
+    it { should contain_file(file_periodic).with_content(/^APT::Periodic::Enable "0";$/) }
+  end
+
+  describe "with backup_interval => 1" do
+    let :params do
+      { :backup_interval => "1" }
+    end
+    it { should contain_file(file_periodic).with_content(/^APT::Periodic::BackUpArchiveInterval "1";$/) }
+  end
+
+  describe "with backup_level => 0" do
+    let :params do
+      { :backup_level => "0" }
+    end
+    it { should contain_file(file_periodic).with_content(/^APT::Periodic::BackUpLevel "0";$/) }
+  end
+
+  describe "with max_age => 1" do
+    let :params do
+      { :max_age => "1" }
+    end
+    it { should contain_file(file_periodic).with_content(/^APT::Periodic::MaxAge "1";$/) }
+  end
+
+  describe "with min_age => 1" do
+    let :params do
+      { :min_age => "1" }
+    end
+    it { should contain_file(file_periodic).with_content(/^APT::Periodic::MinAge "1";$/) }
+  end
+
+  describe "with max_size => 1" do
+    let :params do
+      { :max_size => "1" }
+    end
+    it { should contain_file(file_periodic).with_content(/^APT::Periodic::MaxSize "1";$/) }
+  end
+
+  describe "with download_delta => 2" do
+    let :params do
+      { :download_delta => "2" }
+    end
+    it { should contain_file(file_periodic).with_content(/^APT::Periodic::Download-Upgradeable-Packages-Debdelta "2";$/) }
+  end
+
+  describe "with verbose => 2" do
+    let :params do
+      { :verbose => "2" }
+    end
+    it { should contain_file(file_periodic).with_content(/^APT::Periodic::Verbose "2";$/) }
+  end
+
+end
diff --git a/templates/10periodic.erb b/templates/10periodic.erb
new file mode 100644 (file)
index 0000000..5737c9a
--- /dev/null
@@ -0,0 +1,12 @@
+APT::Periodic::Enable "<%= @enable %>";
+APT::Periodic::BackUpArchiveInterval "<%= @backup_interval %>";
+APT::Periodic::BackUpLevel "<%= @backup_level %>";
+APT::Periodic::MaxAge "<%= @max_age %>";
+APT::Periodic::MinAge "<%= @min_age %>";
+APT::Periodic::MaxSize "<%= @max_size %>";
+APT::Periodic::Update-Package-Lists "<%= @update %>";
+APT::Periodic::Download-Upgradeable-Packages "<%= @download %>";
+APT::Periodic::Download-Upgradeable-Packages-Debdelta "<%= @download_delta %>";
+APT::Periodic::Unattended-Upgrade "<%= @upgrade %>";
+APT::Periodic::AutocleanInterval "<%= @autoclean %>";
+APT::Periodic::Verbose "<%= @verbose %>";
diff --git a/templates/50unattended-upgrades.erb b/templates/50unattended-upgrades.erb
new file mode 100644 (file)
index 0000000..4df0f74
--- /dev/null
@@ -0,0 +1,53 @@
+// Automatically upgrade packages from these (origin:archive) pairs
+Unattended-Upgrade::Allowed-Origins {
+<% @origins.each do |origin| -%>
+       "<%= origin %>";
+<% end -%>
+};
+
+// List of packages to not update
+Unattended-Upgrade::Package-Blacklist {
+<% @blacklist.each do |package| -%>
+       "<%= package %>";
+<% end -%>
+};
+
+// This option allows you to control if on a unclean dpkg exit
+// unattended-upgrades will automatically run 
+//   dpkg --force-confold --configure -a
+// The default is true, to ensure updates keep getting installed
+Unattended-Upgrade::AutoFixInterruptedDpkg "<%= @auto_fix %>";
+
+// Split the upgrade into the smallest possible chunks so that
+// they can be interrupted with SIGUSR1. This makes the upgrade
+// a bit slower but it has the benefit that shutdown while a upgrade
+// is running is possible (with a small delay)
+Unattended-Upgrade::MinimalSteps "<%= @minimal_steps %>";
+
+// Install all unattended-upgrades when the machine is shuting down
+// instead of doing it in the background while the machine is running
+// This will (obviously) make shutdown slower
+Unattended-Upgrade::InstallOnShutdown "<%= @install_on_shutdown %>";
+
+// Send email to this address for problems or packages upgrades
+// If empty or unset then no email is sent, make sure that you
+// have a working mail setup on your system. A package that provides
+// 'mailx' must be installed.
+<% if @mail_to != "NONE" %>Unattended-Upgrade::Mail "<%= @mail_to %>";<% end %>
+
+// Set this value to "true" to get emails only on errors. Default
+// is to always send a mail if Unattended-Upgrade::Mail is set
+<% if @mail_to != "NONE" %>Unattended-Upgrade::MailOnlyOnError "<%= @mail_only_on_error %>";<% end %>
+
+// Do automatic removal of new unused dependencies after the upgrade
+// (equivalent to apt-get autoremove)
+Unattended-Upgrade::Remove-Unused-Dependencies "<%= @remove_unused %>";
+
+// Automatically reboot *WITHOUT CONFIRMATION* if a 
+// the file /var/run/reboot-required is found after the upgrade 
+Unattended-Upgrade::Automatic-Reboot "<%= @auto_reboot %>";
+
+
+// Use apt bandwidth limit feature, this example limits the download
+// speed to 70kb/sec
+<% if @dl_limit != "NONE" %>Acquire::http::Dl-Limit "<%= @dl_limit %>";<% end %>
diff --git a/tests/unattended-upgrades.pp b/tests/unattended-upgrades.pp
new file mode 100644 (file)
index 0000000..7f65ab4
--- /dev/null
@@ -0,0 +1 @@
+include apt::unattended-upgrades