apt::hold: Add a mechanism to hold a package.
I am aware this can be done with `dpkg --set-selections`, `apt-mark` or `ensure => 'held'` on a package resource. The changes to the README include the full rationale for wanting another mechanism.
This commit is contained in:
parent
fd3e07e58f
commit
519babcfb6
3 changed files with 194 additions and 0 deletions
40
README.md
40
README.md
|
@ -119,6 +119,45 @@ If you wish to pin a number of packages you may specify the packages as a space
|
||||||
delimited string using the `packages` attribute or pass in an array of package
|
delimited string using the `packages` attribute or pass in an array of package
|
||||||
names.
|
names.
|
||||||
|
|
||||||
|
### apt::hold
|
||||||
|
|
||||||
|
When you wish to hold a package in Puppet is should be done by passing in
|
||||||
|
'held' as the ensure attribute to the package resource. However, a lot of
|
||||||
|
public modules do not take this into account and generally do not work well
|
||||||
|
with an ensure of 'held'.
|
||||||
|
|
||||||
|
There is an additional issue that when Puppet is told to hold a package, it
|
||||||
|
will hold it at the current version installed, there is no way to tell it in
|
||||||
|
one go to install a specific version and then hold that version without using
|
||||||
|
an exec resource that wraps `dpkg --set-selections` or `apt-mark`.
|
||||||
|
|
||||||
|
At first glance this could also be solved by just passing the version required
|
||||||
|
to the ensure attribute but that only means that Puppet will install that
|
||||||
|
version once it processes that package. It does not inform apt that we want
|
||||||
|
this package to be held. In other words; if another package somehow wants to
|
||||||
|
upgrade this one (because of a version requirement in a dependency), apt
|
||||||
|
should not allow it.
|
||||||
|
|
||||||
|
In order to solve this you can use apt::hold. It's implemented by creating
|
||||||
|
a preferences file with a priority of 1001, meaning that under normal
|
||||||
|
circumstances this preference will always win. Because the priority is > 1000
|
||||||
|
apt will interpret this as 'this should be the version installed and I am
|
||||||
|
allowed to downgrade the current package if needed'.
|
||||||
|
|
||||||
|
With this you can now set a package's ensure attribute to 'latest' but still
|
||||||
|
get the version specified by apt::hold. You can do it like this:
|
||||||
|
|
||||||
|
apt::hold { 'vim':
|
||||||
|
version => '2:7.3.547-7',
|
||||||
|
}
|
||||||
|
|
||||||
|
Since you might just want to hold Vim at version 7.3 and not care about the
|
||||||
|
rest you can also pass in a version with a glob:
|
||||||
|
|
||||||
|
apt::hold { 'vim':
|
||||||
|
version => '2:7.3.*',
|
||||||
|
}
|
||||||
|
|
||||||
### apt::ppa
|
### apt::ppa
|
||||||
|
|
||||||
Adds a ppa repository using `add-apt-repository`.
|
Adds a ppa repository using `add-apt-repository`.
|
||||||
|
@ -238,3 +277,4 @@ A lot of great people have contributed to this module. A somewhat current list f
|
||||||
* Spencer Krum <spencer@puppetlabs.com>
|
* Spencer Krum <spencer@puppetlabs.com>
|
||||||
* William Van Hevelingen <blkperl@cat.pdx.edu> <wvan13@gmail.com>
|
* William Van Hevelingen <blkperl@cat.pdx.edu> <wvan13@gmail.com>
|
||||||
* Zach Leslie <zach@puppetlabs.com>
|
* Zach Leslie <zach@puppetlabs.com>
|
||||||
|
* Daniele Sluijters <github@daenney.net>
|
||||||
|
|
54
manifests/hold.pp
Normal file
54
manifests/hold.pp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
# == Define apt::hold
|
||||||
|
#
|
||||||
|
# This defined type allows you to hold a package based on the version you
|
||||||
|
# require. It's implemented by dropping an apt preferences file pinning the
|
||||||
|
# package to the version you require.
|
||||||
|
#
|
||||||
|
# === Parameters
|
||||||
|
#
|
||||||
|
# [*version*]
|
||||||
|
# The version at which you wish to pin a package.
|
||||||
|
#
|
||||||
|
# This can either be the full version, such as 4:2.11.8.1-5, or
|
||||||
|
# a partial version, such as 4:2.11.*
|
||||||
|
#
|
||||||
|
# [*package*]
|
||||||
|
# _default_: +$title+, the title/name of the resource.
|
||||||
|
#
|
||||||
|
# Name of the package that apt is to hold.
|
||||||
|
#
|
||||||
|
# [*priority*]
|
||||||
|
# _default_: +1001+
|
||||||
|
#
|
||||||
|
# The default priority of 1001 causes this preference to always win. By
|
||||||
|
# setting the priority to a number greater than 1000 apt will always install
|
||||||
|
# this version even if it means downgrading the currently installed version.
|
||||||
|
define apt::hold(
|
||||||
|
$version,
|
||||||
|
$ensure = 'present',
|
||||||
|
$package = $title,
|
||||||
|
$priority = 1001,
|
||||||
|
){
|
||||||
|
|
||||||
|
validate_string($title)
|
||||||
|
validate_re($ensure, ['^present|absent',])
|
||||||
|
validate_string($package)
|
||||||
|
validate_string($version)
|
||||||
|
|
||||||
|
if ! is_integer($priority) {
|
||||||
|
fail('$priority must be an integer')
|
||||||
|
}
|
||||||
|
|
||||||
|
if $ensure == 'present' {
|
||||||
|
::apt::pin { "hold ${package} at ${version}":
|
||||||
|
packages => $package,
|
||||||
|
version => $version,
|
||||||
|
priority => $priority,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
::apt::pin { "hold ${package} at ${version}":
|
||||||
|
ensure => 'absent',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
100
spec/defines/hold_spec.rb
Normal file
100
spec/defines/hold_spec.rb
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
describe 'apt::hold' do
|
||||||
|
let :facts do {
|
||||||
|
:osfamily => 'Debian',
|
||||||
|
:lsbdistid => 'Debian',
|
||||||
|
:lsbrelease => 'wheezy',
|
||||||
|
} end
|
||||||
|
|
||||||
|
let :title do
|
||||||
|
'vim'
|
||||||
|
end
|
||||||
|
|
||||||
|
let :default_params do {
|
||||||
|
:version => '1.1.1',
|
||||||
|
} end
|
||||||
|
|
||||||
|
describe 'default params' do
|
||||||
|
let :params do default_params end
|
||||||
|
|
||||||
|
it 'creates an apt preferences file' do
|
||||||
|
should contain_apt__hold(title).with({
|
||||||
|
:ensure => 'present',
|
||||||
|
:package => title,
|
||||||
|
:version => params[:version],
|
||||||
|
:priority => 1001,
|
||||||
|
})
|
||||||
|
|
||||||
|
should contain_apt__pin("hold #{title} at #{params[:version]}").with({
|
||||||
|
:ensure => 'present',
|
||||||
|
:packages => title,
|
||||||
|
:version => params[:version],
|
||||||
|
:priority => 1001,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'ensure => absent' do
|
||||||
|
let :params do default_params.merge({:ensure => 'absent',}) end
|
||||||
|
|
||||||
|
it 'creates an apt preferences file' do
|
||||||
|
should contain_apt__hold(title).with({
|
||||||
|
:ensure => params[:ensure],
|
||||||
|
})
|
||||||
|
|
||||||
|
should contain_apt__pin("hold #{title} at #{params[:version]}").with({
|
||||||
|
:ensure => params[:ensure],
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'priority => 990' do
|
||||||
|
let :params do default_params.merge({:priority => 990,}) end
|
||||||
|
|
||||||
|
it 'creates an apt preferences file' do
|
||||||
|
should contain_apt__hold(title).with({
|
||||||
|
:ensure => 'present',
|
||||||
|
:package => title,
|
||||||
|
:version => params[:version],
|
||||||
|
:priority => params[:priority],
|
||||||
|
})
|
||||||
|
|
||||||
|
should contain_apt__pin("hold #{title} at #{params[:version]}").with({
|
||||||
|
:ensure => 'present',
|
||||||
|
:packages => title,
|
||||||
|
:version => params[:version],
|
||||||
|
:priority => params[:priority],
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'validation' do
|
||||||
|
context 'version => {}' do
|
||||||
|
let :params do { :version => {}, } end
|
||||||
|
it 'should fail' do
|
||||||
|
expect { subject }.to raise_error(/is not a string/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'ensure => bananana' do
|
||||||
|
let :params do default_params.merge({:ensure => 'bananana',}) end
|
||||||
|
it 'should fail' do
|
||||||
|
expect { subject }.to raise_error(/does not match/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'package => []' do
|
||||||
|
let :params do default_params.merge({:package => [],}) end
|
||||||
|
it 'should fail' do
|
||||||
|
expect { subject }.to raise_error(/is not a string/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'priority => bananana' do
|
||||||
|
let :params do default_params.merge({:priority => 'bananana',}) end
|
||||||
|
it 'should fail' do
|
||||||
|
expect { subject }.to raise_error(/must be an integer/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue