3

Overview:

Just started using Puppet and used the following array with 'ensure' so a specific version of Apache is installed (rather than the latest) and its 'held'(which means it won't be upgraded on a standard apt-get dist-upgrade to the latest version.

Problem:

When using the code below only the first value in the ensure array is taken into consideration by Puppet. So when the code is below is executed it installs the correct version of Apache but the package is not set to hold (checked by running dpkg --get-selection).

If the values in the array are swapped then the package is held but the latest version is installed.

Code:

package { 'apache2':

        ensure => [ "2.0.64", held ],
 }

Appreciate any pointers on this one!
Thanks.

Henk
  • 1,331
  • 11
  • 24
hokeycokey
  • 243
  • 1
  • 4
  • 11
  • 1
    "Held is considered a superset of installed." Source: http://docs.puppetlabs.com/references/2.6.4/type.html – Henk Mar 15 '12 at 22:15

3 Answers3

6

As best I can tell by reading the source code the "holdable" feature is fundamentally flawed. The ensure (see ensurable.do, line 50) cannot accept an array of options. Thus, a package can not both be installed at a particular version and marked held using dpkg. I assume the default behavior of the parser is such that if it receives an array where one is not supported, the first value is used. That would explain your outcome.

In my opinion the version and/or holdable features should be re-implemented as a new variable, such as:

package { 'apache2'
  ensure => installed,
  version => '2.0.64',
  hold => true,
}

I suggest you submit a bug report. In the meantime, you could do:

package { 'apache2':
  ensure => '2.0.64',
}

exec { 'hold-apache2-version':
  command => 'dpkg ...',
  require => Package['apache2'],
}
Kyle Smith
  • 9,683
  • 1
  • 31
  • 32
  • Thanks for getting back to me. I'll take a look at the source code as you suggest. Something I'm defo going to do in the future! – hokeycokey Mar 15 '12 at 22:30
  • P.S I guess the only way to achieve the desired pinning of packages would be to run an exec command with dpkg --set-selections – hokeycokey Mar 15 '12 at 22:32
3

I came up with a workaround. Brace yourself, this is gross.

if $::puppetversion == '2.7.11' {
  $ensure_puppet = 'held'
} else {
  $ensure_puppet = '2.7.11-1puppetlabs1'
}
package { ['puppet', 'puppet-common']:
  ensure => $ensure_puppet
}

It uses the built-in fact $::puppetversion to do version interrogation. So the state of the package will be 'held' unless the installed version is different from what we want. This should enable me to upgrade the puppet infrastructure at will without worrying about unattended-upgrades doing it for me.

This doesn't answer the exact question regarding version locking Apache, but one could trivially write a custom fact to query Apache for its version.

I had initially tried the manual dpkg hold approach. I used the package type to ensure versions and then ran an execute script to make sure it was held separately. It's similar to the approach that I take with yum version locking.

define apt::hold() {
  exec { "hold-${name}":
    command => "/bin/echo '${name} hold' | /usr/bin/dpkg --set-selections",
    unless  => "/usr/bin/dpkg --get-selections ${name} | /bin/grep hold",
    require => Package[$name]
  }
}

package { ['puppet', 'puppet-common']:
  ensure => '2.7.11-1puppetlabs1'
}
apt::hold { ['puppet', 'puppet-common']: }

Now, this works, but it produces a lot of annoying notifications in the logs and reports. The package type can't reconcile that a package can be both held and a certain version. So it will notify me that the package state has changed from 'held' to '2.7.11-1puppetlabs1'.

[sanitized.server.name.net] out: info: Retrieving plugin
[sanitized.server.name.net] out: info: Loading facts in /var/lib/puppet/lib/facter/operatingsystemmajor.rb
[sanitized.server.name.net] out: info: Loading facts in /var/lib/puppet/lib/facter/datacenter.rb
[sanitized.server.name.net] out: info: Caching catalog for sanitized.server.name.net
[sanitized.server.name.net] out: info: Applying configuration version '1333727048'
[sanitized.server.name.net] out: notice: /Stage[main]/Puppet/Package[facter]/ensure: ensure changed 'held' to '1.6.6-1puppetlabs1'
[sanitized.server.name.net] out: notice: /Stage[main]/Puppet::Client/Package[puppet-common]/ensure: ensure changed 'held' to '2.7.11-1puppetlabs1'
[sanitized.server.name.net] out: notice: /Stage[main]/Puppet::Client/Package[puppet]/ensure: ensure changed 'held' to '2.7.11-1puppetlabs1'
[sanitized.server.name.net] out: notice: Finished catalog run in 6.25 seconds

I don't like my reports crying wolf all the time. It also causes issues if I want to do something like:

package { ['puppet', 'puppet-common']:
  ensure => '2.7.11-1puppetlabs1',
  notify => Service['puppet']
}

To restart the service after an upgrade. I end with the service being bounced every single time puppet runs.

I agree with everyone else though that 'held' should probably be a separate attribute of the package type.

1

I use this puppet module to manage apt on my systems. It provides a "preferences_snippet" define which can be used to pin packages to specific versions or releases (see README).

jcharaoui
  • 322
  • 2
  • 12