diff options
author | Daniele Sluijters <daenney@users.noreply.github.com> | 2015-04-14 17:25:40 +0200 |
---|---|---|
committer | Daniele Sluijters <daenney@users.noreply.github.com> | 2015-04-14 17:25:40 +0200 |
commit | 886245f2cb7614a8c749d34e6f08ee17b92c970f (patch) | |
tree | 942f955f9ad8717c2b46aff8721e84f9b678af5d |
Initial commit (this is not finished).
-rw-r--r-- | .fixtures.yml | 11 | ||||
-rw-r--r-- | .gitignore | 9 | ||||
-rw-r--r-- | .rspec | 2 | ||||
-rw-r--r-- | Gemfile | 22 | ||||
-rw-r--r-- | LICENSE | 35 | ||||
-rw-r--r-- | README.md | 78 | ||||
-rw-r--r-- | Rakefile | 56 | ||||
-rw-r--r-- | manifests/init.pp | 69 | ||||
-rw-r--r-- | manifests/params.pp | 50 | ||||
-rw-r--r-- | spec/classes/unattended_upgrades_spec.rb | 32 | ||||
-rw-r--r-- | spec/spec_helper.rb | 1 | ||||
-rw-r--r-- | templates/periodic.erb | 47 | ||||
-rw-r--r-- | templates/unattended-upgrades.erb | 60 |
13 files changed, 472 insertions, 0 deletions
diff --git a/.fixtures.yml b/.fixtures.yml new file mode 100644 index 0000000..7566fe3 --- /dev/null +++ b/.fixtures.yml @@ -0,0 +1,11 @@ +fixtures: + forge_modules: + stdlib: + repo: "puppetlabs-stdlib" + ref: "4.5.1" + repositories: + apt: + repo: "https://github.com/puppetlabs/puppetlabs-apt.git" + ref: "2.0.x" + symlinks: + unattended_upgrades: "#{source_dir}" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b5db85e --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +pkg/ +Gemfile.lock +vendor/ +spec/fixtures/ +.vagrant/ +.bundle/ +coverage/ +.idea/ +*.iml @@ -0,0 +1,2 @@ +--format documentation +--color @@ -0,0 +1,22 @@ +source "https://rubygems.org" + +group :test do + gem "rake" + gem "puppet", ENV['PUPPET_VERSION'] || '~> 3.7.0' + gem "rspec", '< 3.2.0' + gem "rspec-puppet", :git => 'https://github.com/rodjek/rspec-puppet.git' + gem "puppetlabs_spec_helper" + gem "metadata-json-lint" + gem "rspec-puppet-facts" +end + +group :development do + gem "travis" + gem "travis-lint" + gem "puppet-blacksmith" +end + +group :system_tests do + gem "beaker" + gem "beaker-rspec" +end @@ -0,0 +1,35 @@ +Copyright (c) 2011 Evolving Web Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +Copyright 2014 Puppet Labs, 2015 Puppet Community + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..6f56957 --- /dev/null +++ b/README.md @@ -0,0 +1,78 @@ +# unattended\_upgrades + +## Overview + +The unattended\_upgrades module allows for the installation and configuration of automatic security (and other) updates through apt. + +This functionality used to be part of the puppetlabs-apt module but was split off into its own module. + +## Module Description + +The unattended\_upgrades module automates the configuration of apt package updates. + +## Setup + +### What unattended\_upgrades affects: + +* Package/configuration for unattended\_upgrades + +### Beginning with unattended\_upgrades + +All you need to do is include the module `include unattended_upgrades`. + +## Usage + +Using unattended\_upgrades simply consists of including the module and if needed altering some of the default settings. + +## Reference + +### Classes + +* `unattended_upgrades`: Main class, installs the necessary packages and writes the configuration. + +### Parameters + +#### unattended\_upgrades + +* `auto`: A hash of settings with three possible keys: + * `fix_interrupted_dpkg`(`true`): Try to fix package installation state + * `reboot`(`false`): Reboot system after package update installation + * `remove`(`true`): Remove unneeded dependencies after update installation + + Any of these keys can be specified and will be merged into the defaults, so if you only want to change the `reboot` behaviour the following is enough: + + ```puppet + class { 'unattended_upgrades': + auto => { 'reboot' => true }, + } + ``` +* `blacklist`(`[]`): A list of packages to **not** automatically upgrade. This list is empty by default. +* `dl_limit`(`undef`): Use a bandwidth limit for downloading, specified in kb/sec. +* `enable` (`1`): Enable the automatic installation of updates. +* `install_on_shutdown` (`false`): Install updates on shutdown instead of in the background. +* `legacy_origin` (`false`): Use the legacy `Unattended-Upgrade::Allowed-Origins` setting or the modern `Unattended-Upgrade::Origins-Pattern`. +* `mail`: A hash to configure email behaviour. The possible keys are: + * `only_on_error` (`true`): Only send mail when something went wrong + * `to` (`undef`): Email address to send email too + + If the default for `to` is kept you will not receive any mail at all. You'll likely want to set this parameter: + + ```puppet + class { 'unattended_upgrades': + mail => { 'to' => 'admin@domain.tld', }, + } + ``` +* `minimal_steps` (`true`): Split the upgrade process into sections to allow shutdown during upgrade. +* `origins`: The repositories from which to automatically upgrade included packages. +* `package_ensure` (`installed`): The ensure state for the 'unattended-upgrades' package. + + +## Limitations + +This module should work across all versions of Debian/Ubuntu. + +## License + +The original code for this module comes from Evolving Web and was licensed under the MIT license. Code added since the fork of that module into puppetlabs-apt is covered under the Apache License version 2 as is any code added since it was split off into this separate unattended\_upgrades module. + +The LICENSE contains both licenses. diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..1778d2a --- /dev/null +++ b/Rakefile @@ -0,0 +1,56 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet/version' +require 'puppet/vendor/semantic/lib/semantic' unless Puppet.version.to_f < 3.6 +require 'puppet-lint/tasks/puppet-lint' +require 'puppet-syntax/tasks/puppet-syntax' + +# These gems aren't always present, for instance +# on Travis with --without development +begin + require 'puppet_blacksmith/rake_tasks' +rescue LoadError +end + +Rake::Task[:lint].clear + +PuppetLint.configuration.relative = true +PuppetLint.configuration.send("disable_80chars") +PuppetLint.configuration.log_format = "%{path}:%{linenumber}:%{check}:%{KIND}:%{message}" +PuppetLint.configuration.fail_on_warnings = true + +# Forsake support for Puppet 2.6.2 for the benefit of cleaner code. +# http://puppet-lint.com/checks/class_parameter_defaults/ +PuppetLint.configuration.send('disable_class_parameter_defaults') +# http://puppet-lint.com/checks/class_inherits_from_params_class/ +PuppetLint.configuration.send('disable_class_inherits_from_params_class') + +exclude_paths = [ + "bundle/**/*", + "pkg/**/*", + "vendor/**/*", + "spec/**/*", +] +PuppetLint.configuration.ignore_paths = exclude_paths +PuppetSyntax.exclude_paths = exclude_paths + +desc "Run acceptance tests" +RSpec::Core::RakeTask.new(:acceptance) do |t| + t.pattern = 'spec/acceptance' +end + +desc "Populate CONTRIBUTORS file" +task :contributors do + system("git log --format='%aN' | sort -u > CONTRIBUTORS") +end + +task :metadata do + sh "metadata-json-lint metadata.json" +end + +desc "Run syntax, lint, and spec tests." +task :test => [ + :syntax, + :lint, + :spec, + :metadata, +] diff --git a/manifests/init.pp b/manifests/init.pp new file mode 100644 index 0000000..414abe2 --- /dev/null +++ b/manifests/init.pp @@ -0,0 +1,69 @@ +class unattended_upgrades ( + $age = {}, + $auto = {}, + $backup = {}, + $blacklist = [], + $dl_limit = undef, + $enable = 1, + $install_on_shutdown = false, + $legacy_origin = $::unattended_upgrades::params::legacy_origin, + $mail = {}, + $minimal_steps = true, + $origins = $::unattended_upgrades::params::origins, + $package_ensure = installed, + $size = {}, + $update = 1, + $upgrade = 1, + $upgradeable_packages = {}, + $verbose = 0, +) inherits ::unattended_upgrades::params { + + include ::apt + Class['apt'] -> Class['unattended_upgrades'] + + validate_bool( + $install_on_shutdown, + $legacy_origin, + $minimal_steps, + ) + validate_array($blacklist) + validate_array($origins) + validate_hash($auto) + $_auto = merge($auto, $::unattended_upgrades::default_auto) + validate_hash($mail) + if $mail['only_on_error'] { + validate_bool($mail['only_on_error']) + } + $_mail = merge($mail, $::unattended_upgrades::default_mail) + validate_hash($backup) + $_backup = merge($backup, $::unattended_upgrades::default_backup) + validate_hash($age) + $_age = merge($age, $::unattended_upgrades::default_age) + validate_hash($size) + $_size = merge($size, $::unattended_upgrades::default_size) + validate_hash($upgradeable_packages) + $_upgradeable_packages = merge($upgradeable_packages, $::unattended_upgrades::upgradeable_packages) + + package { 'unattended-upgrades': + ensure => $package_ensure, + } + + apt::conf { 'unattended-upgrades': + priority => 50, + content => template("${module_name}/unattended-upgrades.erb"), + require => Package['unattended-upgrades'], + } + + apt::conf { 'periodic': + priority => 10, + content => template("${module_name}/periodic.erb"), + require => Package['unattended-upgrades'], + } + + apt::conf { 'auto-upgrades': + ensure => absent, + priority => 20, + require => Package['unattended-upgrades'], + } + +} diff --git a/manifests/params.pp b/manifests/params.pp new file mode 100644 index 0000000..49aec20 --- /dev/null +++ b/manifests/params.pp @@ -0,0 +1,50 @@ +class unattended_upgrades::params { + + if $::osfamily != 'Debian' { + fail('This module only works on Debian or derivatives like Ubuntu') + } + + $default_auto = { 'fix_interrupted_dpkg' => true, 'remove' => true, 'reboot' => false, 'clean' => 0, } + $default_mail = { 'only_on_errors' => true, 'to' => undef, } + $default_backup = { 'archive_interval' => 0, 'level' => 3, } + $default_age = { 'min' => 2, 'max' => 0, } + $default_size = { 'max' => 0, } + $default_upgradeable_packages = { 'download_only' => 0, 'debdelta' => 1, } + + # Strict variables facts lookup compatibility + $xfacts = { + 'lsbdistid' => defined('$lsbdistid') ? { + true => $::lsbdistid, + default => undef, + }, + 'lsbdistcodename' => defined('$lsbdistcodename') ? { + true => $::lsbdistcodename, + default => undef, + }, + } + + case $xfacts['lsbdistid'] { + 'debian': { + case $xfacts['lsbdistcodename'] { + 'squeeze': { + $legacy_origin = true + $origins = ['${distro_id} oldstable', #lint:ignore:single_quote_string_with_variables + '${distro_id} ${distro_codename}-security', #lint:ignore:single_quote_string_with_variables + '${distro_id} ${distro_codename}-lts',] #lint:ignore:single_quote_string_with_variables + } + default: { + $legacy_origin = false + $origins = ['origin=Debian,archive=stable,label=Debian-Security'] + } + } + } + 'ubuntu': { + $legacy_origin = true + $origins = ['${distro_id} {$distro_codename}-security', #lint:ignore:single_quote_string_with_variables + '${distro_id} {$distro_codename}-updates',] #lint:ignore:single_quote_string_with_variables + } + default: { + fail('Please explicitly specify unattended_upgrades::legacy_origin and unattended_upgrades::origins') + } + } +} diff --git a/spec/classes/unattended_upgrades_spec.rb b/spec/classes/unattended_upgrades_spec.rb new file mode 100644 index 0000000..b31f3d7 --- /dev/null +++ b/spec/classes/unattended_upgrades_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe 'unattended_upgrades' do + let(:file_unattended) { '/etc/apt/apt.conf.d/50unattended-upgrades' } + let(:file_periodic) { '/etc/apt/apt.conf.d/10periodic' } + let(:facts) { { + :osfamily => 'Debian', + :lsbdistid => 'Debian', + :lsbistcodename => 'wheezy', + :lsbrelease => '7.0.3', + } } + + it { should contain_package("unattended-upgrades") } + + it { + should create_file(file_unattended).with({ + "owner" => "root", + "group" => "root", + "mode" => "0644", + "require" => "Package[unattended-upgrades]", + }) + } + + it { + should create_file(file_periodic).with({ + "owner" => "root", + "group" => "root", + "mode" => "0644", + "require" => "Package[unattended-upgrades]", + }) + } +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..2c6f566 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1 @@ +require 'puppetlabs_spec_helper/module_spec_helper' diff --git a/templates/periodic.erb b/templates/periodic.erb new file mode 100644 index 0000000..8a581e0 --- /dev/null +++ b/templates/periodic.erb @@ -0,0 +1,47 @@ +APT::Periodic::Enable "<%= @enable %>"; +# - Enable the update/upgrade script (0=disable) +# +APT::Periodic::BackupArchiveInterval "<%= @_backup['archive_interval'] %>"; +# - Backup after n-days if archive contents changed.(0=disable) +# +APT::Periodic::BackupLevel "<%= @_backup['level'] %>"; +# - Backup level.(0=disable), 1 is invalid. +# +APT::Periodic::MaxAge "<%= @_age['max'] %>"; +# - Set maximum allowed age of a cache package file. If a cache +# package file is older it is deleted (0=disable) +# +APT::Periodic::MinAge "<%= @_age['min'] %>"; +# - Set minimum age of a package file. If a file is younger it +# will not be deleted (0=disable). Usefull to prevent races +# and to keep backups of the packages for emergency. +# +APT::Periodic::MaxSize "<%= @_size['max'] %>"; +# - Set maximum size of the cache in MB (0=disable). If the cache +# is bigger, cached package files are deleted until the size +# requirement is met (the biggest packages will be deleted +# first). +# +APT::Periodic::Update-Package-Lists "<%= @update %>"; +# - Do "apt-get update" automatically every n-days (0=disable) +# +APT::Periodic::Download-Upgradeable-Packages "<%= @_upgradeable_packages['downlaod_only'] %>"; +# - Do "apt-get upgrade --download-only" every n-days (0=disable) +# +# APT::Periodic::Download-Upgradeable-Packages-Debdelta "<%= @_upgradeable_packages['debdelta'] %>"; +# - Use debdelta-upgrade to download updates if available (0=disable) +APT::Periodic::Unattended-Upgrade "<%= @upgrade %>"; +# - Run the "unattended-upgrade" security upgrade script +# every n-days (0=disabled) +# Requires the package "unattended-upgrades" and will write +# a log in /var/log/unattended-upgrades +# +APT::Periodic::AutocleanInterval "<%= @_auto['clean'] %>"; +# - Do "apt-get autoclean" every n-days (0=disable) +# +APT::Periodic::Verbose "<%= @verbose %>"; +# - Send report mail to root +# 0: no report (or null string) +# 1: progress report (actually any string) +# 2: + command outputs (remove -qq, remove 2>/dev/null, add -d) +# 3: + trace on diff --git a/templates/unattended-upgrades.erb b/templates/unattended-upgrades.erb new file mode 100644 index 0000000..5007193 --- /dev/null +++ b/templates/unattended-upgrades.erb @@ -0,0 +1,60 @@ +// Automatically upgrade packages from these (origin:archive) pairs +<%- if @legacy_origin -%> +Unattended-Upgrade::Allowed-Origins { +<%- else -%> +Unattended-Upgrade::Origins-Pattern { +<%- end -%> +<% @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_interrupted_dpkg'].to_s %>"; + +// 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.to_s %>"; + +// 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.to_s %>"; + +<% unless @mail_to.nil? %> +// 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. +Unattended-Upgrade::Mail "<%= @mail_to %>"; + +// Set this value to "true" to get emails only on errors. Default +// is to always send a mail if Unattended-Upgrade::Mail is set +Unattended-Upgrade::MailOnlyOnError "<%= @mail_only_on_error.to_s %>"; +<% end %> + +// Do automatic removal of new unused dependencies after the upgrade +// (equivalent to apt-get autoremove) +Unattended-Upgrade::Remove-Unused-Dependencies "<%= @_auto['remove'].to_s %>"; + +// Automatically reboot *WITHOUT CONFIRMATION* if a +// the file /var/run/reboot-required is found after the upgrade +Unattended-Upgrade::Automatic-Reboot "<%= @_auto['reboot'].to_s %>"; + +<% unless @dl_limit.nil? %> +// Use apt bandwidth limit feature, this example limits the download +// speed to 70kb/sec +Acquire::http::Dl-Limit "<%= @dl_limit %>"; +<% end %> |