puppetlabs/puppet — pull request #3132 by lotheac (2014-09-30 13:04:09+00:00)
Title: (PUP-1270) Use full IPS package version matching

This is a continuation of PR#2200, rebased onto master with additional logic.

First, let's review the problem: puppet only considers IPS package versions
partially (eg. '1.0-0.151006', which is missing 'build version' and 'timestamp'
documented in pkg(5)). This causes the following problems:

- ensure => latest does nothing when the updated package only has a changed timestamp
- ensure => '1.0,5.11-0.151006:20140220T084443Z' is always applied, because it's not string equal to what puppet thinks is the installed version ('1.0-0.151006'); this causes pkg(1M) to exit with status 4, which makes puppet throw an error
- ensure => '1.0-0.151006' sort of works; on the first run, it installs the latest available matching version (due to pkg(1M) working that way), and on subsequent runs does nothing. This can lead to subtle bugs where systems provisioned later do not necessarily have the same version of a package installed (ie. if a newer-timestamped one was released in the meantime).

For the solution, I implemented a provider-specific insync? for the pkg provider, which should remove the regressions noted in the original pull request. There is unfortunately no way to do this without allowing less-than-explicit version numbers in ensure (because that's the original behavior!); I think that is *only* acceptable because pkg(1M) also allows less-than-explicit versions AND we don't want to break backward compatibility. I added warnings for the cases where implicit ensure versions are given. The functionality is thus:

- specifying a full version number (one that includes publish timestamp) functions as expected wrt. no action (package in sync), package upgrade and package downgrade

sunset ~ % puppet resource package PUP-1270-test-package
package { 'PUP-1270-test-package':
ensure => '1.0,5.11-0.151006:20140220T084443Z',
}
sunset ~ % pfexec puppet apply --test -e 'package {"PUP-1270-test-package": ensure => "1.0,5.11-0.151006:20140220T084443Z" }'
Info: Loading facts
Notice: Compiled catalog for sunset.niksula.hut.fi in environment production in 0.68 seconds
Info: Applying configuration version '1412080332'
Notice: Finished catalog run in 0.67 seconds
sunset ~ % pfexec puppet apply --test -e 'package {"PUP-1270-test-package": ensure => "1.2,5.11-0.151006:20140930T115744Z" }'
Info: Loading facts
Notice: Compiled catalog for sunset.niksula.hut.fi in environment production in 0.66 seconds
Info: Applying configuration version '1412080365'
Notice: /Stage[main]/Main/Package[PUP-1270-test-package]/ensure: ensure changed '1.0,5.11-0.151006:20140220T084443Z' to '1.2,5.11-0.151006:20140930T115744Z'
Notice: Finished catalog run in 13.57 seconds
sunset ~ 2 % pfexec puppet apply --test -e 'package {"PUP-1270-test-package": ensure => "1.1,5.11:20140219T191731Z" }'
Info: Loading facts
Notice: Compiled catalog for sunset.niksula.hut.fi in environment production in 0.70 seconds
Info: Applying configuration version '1412080432'
Notice: /Stage[main]/Main/Package[PUP-1270-test-package]/ensure: ensure changed '1.2,5.11-0.151006:20140930T115744Z' to '1.1,5.11:20140219T191731Z'
Notice: Finished catalog run in 17.02 seconds

- specifying a less-than-explicit version works *mostly* the same as before. Currently in master, as mentioned in the problem review above, updates never happen after the initial install. With this patch, supplying such an implicit version number causes an update if there is a newer matching version available. I consider this a bugfix, and the rationale for this is the principle of least astonishment: since pkg(1M) works that way, puppet should too if it allows implicit versions. We throw warnings for implicit version matches, however.

sunset ~ 2 % pfexec puppet apply --test -e 'package {"PUP-1270-test-package": ensure => "1.0-0.151006" }'
Info: Loading facts
Notice: Compiled catalog for sunset.niksula.hut.fi in environment production in 0.70 seconds
Info: Applying configuration version '1412081011'
Warning: Package[PUP-1270-test-package](provider=pkg): Selecting version '1.0,5.11-0.151006:20140220T084443Z' for implicit '1.0-0.151006'
Notice: /Stage[main]/Main/Package[PUP-1270-test-package]/ensure: ensure changed '1.1,5.11:20140219T191731Z' to '1.0,5.11-0.151006:20140220T084443Z'
Notice: Finished catalog run in 20.79 seconds
sunset ~ 2 % pfexec puppet apply --test -e 'package {"PUP-1270-test-package": ensure => "1.0" }'
Info: Loading facts
Notice: Compiled catalog for sunset.niksula.hut.fi in environment production in 0.68 seconds
Info: Applying configuration version '1412081050'
Warning: Package[PUP-1270-test-package](provider=pkg): Implicit version 1.0 has 3 possible matches
Warning: Package[PUP-1270-test-package](provider=pkg): Implicit version 1.0 has 3 possible matches
Notice: Finished catalog run in 9.65 seconds

(interesting sidenote about the last command above: it appears 'type/package.rb:insync?' is called twice if it first returns true; I did not investigate this because it is not caused by my changeset)

- ensure => latest now properly updates packages where only the timestamp changes.

sunset ~ % puppet resource package PUP-1270-test-package
package { 'PUP-1270-test-package':
ensure => '1.2,5.11-0.151006:20140930T115744Z',
}
sunset ~ % pfexec puppet apply --test -e 'package {"PUP-1270-test-package": ensure => "latest" }'
Info: Loading facts
Notice: Compiled catalog for sunset.niksula.hut.fi in environment production in 0.68 seconds
Info: Applying configuration version '1412081346'
Notice: /Stage[main]/Main/Package[PUP-1270-test-package]/ensure: ensure changed '1.2,5.11-0.151006:20140930T115744Z' to '1.2,5.11-0.151006:20140930T124721Z'
Notice: Finished catalog run in 20.27 seconds

There are some additional comments about the details in the code.