Facts which depend on (not-yet-installed) packages

100 views
Skip to first unread message

Jan Schütze

unread,
Mar 15, 2015, 3:04:53 PM3/15/15
to puppet...@googlegroups.com
Hello,

I have the following use case: For a custom class/type I need to know which php_version is installed on the machine. So I wrote a custom fact like this:

Facter.add('php_version') do
setcode do
Facter::Util::Resolution.exec('/usr/bin/php -i | /bin/egrep -e "^PHP Version" | /usr/bin/head -n 1 | /usr/bin/cut -d " " -f 4 | /usr/bin/cut -d "-" -f 1')
end
end
It works great. Except: When php is not yet installed (there is a Package['php'] definition, too). Then it will return an empty string.

Thus I have to run puppet two times to get the expected result.

I am sure that this is expected behavior of puppet. How do I handle such case?

Regards

Jan

--

Garrett Honeycutt

unread,
Mar 15, 2015, 5:11:49 PM3/15/15
to puppet...@googlegroups.com
Hi Jan,

Since your module installs PHP, you're kind of stuck with two runs,
unless you can provide some sane default when php_version is not
present. Suggest implementing your module such that PHP always gets
installed and whatever resources require that php_version be present are
wrapped in some conditional logic.

Here's a quick fix[1] to make your code faster and more portable and not
throw errors when PHP is not found. It does require that PHP be in your
$PATH.

Facter.add("php_version") do
setcode do
test_exists = "which php 2>&1 >/dev/null ; echo $?"
if Facter::Util::Resolution.exec(test_exists) == '0'
php_output = Facter::Util::Resolution.exec('php --version')
php_output.split[1]
end
end
end

[1] - https://gist.github.com/ghoneycutt/42ab87c20f84ec422535

Best regards,
-g

--
Garrett Honeycutt
@learnpuppet
Puppet Training with LearnPuppet.com
Mobile: +1.206.414.8658

jcbollinger

unread,
Mar 16, 2015, 12:07:02 PM3/16/15
to puppet...@googlegroups.com
Fact values are computed before any part of the catalog is built, and they reflect the state of the machine before Puppet applies any changes.  If PHP is not initially installed, then that's a plausible, valid state that your fact value should reflect and your manifests should accommodate.  In the worst case, your manifests could accommodate absence of PHP by requiring two Puppet runs to converge to a final configuration.  That's what you have now, evidently.

Consider carefully, however, what that fact value is telling you: what version of PHP, if any, is installed before the run.  If the target configuration depends in any way on PHP version, then what you probably want is the PHP version that will be present after the run.  If there is any chance that the run will ever update PHP to a new version, then even when PHP is already installed, your manifests rely on an unsafe assumption that the version present before the run will be the same as the version present after.

Possibly what you want is a different (or additional) fact: not the version of PHP currently installed, but the latest version available from the configured repositories.  This is the version that will be present after a successful run if you have ...

package { 'php': ensure => 'latest' }

... it is also the version that will be present after the run if PHP is not initially installed and you have ...

package { 'php': ensure => 'present' }

... provided that the package repository configuration is not changed so as to affect which PHP packages are available.  Given that, if you ensure that the PHP package is managed before anything that depends on PHP version (as you should already be doing) then all should be good.

If you want maximum reliability, however, you need to recognize that if indeed what you want to know is which version of PHP will be present on the machine after a successful catalog run, then your nodes simply cannot provide that information.  It depends on data they do not have.  You need to some mechanism other than (or in addition to) node facts to ascertain that.


John

Poil

unread,
Mar 17, 2015, 3:22:05 AM3/17/15
to puppet...@googlegroups.com
Hi,

You can write something that will lookup in the dpkg/yum cache (but I don't like this), so you will have the future installed version at the 1st run

Exemple here : https://github.com/fsalum/puppet-redis/blob/master/lib/facter/redis_version.rb

Best regards,
--
You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-users/7f0ccfaa-108b-44c3-a9d1-cbca6c0bde22%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Alex Harvey

unread,
Mar 17, 2015, 11:46:05 PM3/17/15
to puppet...@googlegroups.com
Can't you avoid this problem altogether by determining the PHP version in your custom provider code?  Then you wouldn't need a custom fact at all, and in your manifest, have the custom type require the PHP package.

Alex Harvey

unread,
Mar 18, 2015, 3:39:48 AM3/18/15
to puppet...@googlegroups.com
Have a look at how the build in RPM provider works, for instance:

jcbollinger

unread,
Mar 18, 2015, 10:14:01 AM3/18/15
to puppet...@googlegroups.com


On Tuesday, March 17, 2015 at 10:46:05 PM UTC-5, Alex Harvey wrote:
Can't you avoid this problem altogether by determining the PHP version in your custom provider code?  Then you wouldn't need a custom fact at all, and in your manifest, have the custom type require the PHP package.


Great insight!  I didn't think to question whether the fact was required at all.  If indeed it is used to determine how to apply the resource in question, as opposed to determining what to apply, then having the provider perform the version check is definitely the way to go.  If it's in a gray area between "how" and "what", then choosing the "how" side with a possibility to override via resource parameter is probably best.


John

Reply all
Reply to author
Forward
0 new messages