3

I have a small custom fact in a my php module

Facter.add('php_extension_version') do
  setcode do
    Facter::Core::Execution.exec("php -i | awk '/^PHP Extension =>/ { print $4}'") || nil
  end
end

This obviously requires the php binary to be installed. However, I noticed that all facts are run once before applying the catalog, so this fact is invalid before php installed.

Is there any way of gathering the information after the module is installed? Is there perhaps another way of exposing this information except facter?

Update

I'm using the two facts to determine which of multiple .so files is the right one to install:

if $php_zts_enabled {
    $so_name = "newrelic-$php_extension_version.so"
} else {
    $so_name = "newrelic-$php_extension_version-zts.so"
}

file {"/usr/lib64/php5/extensions/newrelic.so":
    source => "file:///opt/newrelic-php5-$version-linux/agent/x64/$so_name",
    owner  => root,
    group  => root,
    mode   => 0644,
    notify => Service['apache'],
    require => Exec["extract-php-agent-$version"]
}

The files that are located in the agent/x64 directory can be

newrelic-20060613.so      newrelic-20090626-zts.so  newrelic-20121212.so      newrelic-20131226-zts.so
newrelic-20060613-zts.so  newrelic-20100525.so      newrelic-20121212-zts.so
newrelic-20090626.so      newrelic-20100525-zts.so  newrelic-20131226.so
Robert Munteanu
  • 67,031
  • 36
  • 206
  • 278

2 Answers2

3

You essentially have only two opportunities to execute code on the node:

  1. As part of a Facter fact. As you are aware, this happens before puppet applies a catalog, so any facts dependent on the results of the puppet run will not be useful until the next run.
  2. As part of a custom provider. You can create a custom type and provider for installing the extensions that checks the node state before deciding what to do. Providers execute on the node, and as long as you know the overall provider lifecycle you can make this happen after the PHP install. However, this is incredibly complex compared to normal puppet modules.

Outside of those options, the normal way of doing this would be to enforce the version and configuration of php within your own manifests, and then pass that information to here. You should already know the version of PHP and its extensions based on what packages you have installed.

Chris Pitman
  • 12,990
  • 3
  • 41
  • 56
1

I would modify the fact so that it's present only when the binary is present (hence it won't be present at the very first run).

Facter.add('php_extension_version') do
  setcode do
    if system("which php > /dev/null 2>&1")
      Facter::Core::Execution.exec("php -i | awk '/^PHP Extension =>/ { print $4}'") || nil
    end

  end
end

and then in your manifest you'd wrap the original code in the if

if $php_extension_version {
    if $php_zts_enabled {
        $so_name = "newrelic-$php_extension_version.so"
    } else {
        $so_name = "newrelic-$php_extension_version-zts.so"
    }

    file {"/usr/lib64/php5/extensions/newrelic.so":
        source => "file:///opt/newrelic-php5-$version-linux/agent/x64/$so_name",
        owner  => root,
        group  => root,
        mode   => 0644,
        notify => Service['apache'],
        require => Exec["extract-php-agent-$version"]
    }
}
  • Thanks for the reply. What do I do if I actually need the fact available? Your answer only allows it to fail gracefully – Robert Munteanu Sep 14 '15 at 21:58
  • What do you mean by fact available? with the second approach the fact will be available: it will contain the actual value if the php binary exists or the string "not present" in case it doesn't. Do you mean you would like the fact not to be present in case the binary is not installed yet? – Elisiano Petrini Sep 14 '15 at 22:07
  • 'Not present' is not useful for me so I would like the fact to run _after_ the binary is installed. And I'm open for suggestions to making the information available some other way, but facter seems to be the recommended approach – Robert Munteanu Sep 14 '15 at 22:09
  • I honestly don't think it's possible because of the plugin sync behavior of puppet: first all the facts are synchronized (to be available in the puppet code) and then the manifests are processed. What you could do is adapt your puppet code to check the value of the fact. If it's different from a string of your choice (i.e.: 'not present' or even an empty string) then do the code snippet in puppet. – Elisiano Petrini Sep 14 '15 at 22:13
  • That would work for me, but how can I execute code snippets in puppet? Custom functions are executed on the server – Robert Munteanu Sep 14 '15 at 22:17
  • to have a full picture I'd need to see your php module code but it boils to code your manifest with something like `if $::php_extension_version != "not present" { ... }`. Again, the string can be whatever you want. – Elisiano Petrini Sep 14 '15 at 22:20
  • I've updated the question with details, maybe that helps – Robert Munteanu Sep 14 '15 at 22:26
  • That's what I suspected. So basically you should wrap your code inside a conditional statement that check for the fact existence. I've updated the answer to reflect this. – Elisiano Petrini Sep 14 '15 at 22:43
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/89625/discussion-between-robert-munteanu-and-elisiano-petrini). – Robert Munteanu Sep 14 '15 at 23:09