Search code examples
rubypuppetauto-generate

Puppet: generate statement fails when trying to retrieve default path of an executable


I have built a stanza to remove a ruby gem package from our servers. The problem is that the ruby gem executable is installed in different paths on the servers, so on one server it could be in /opt/ruby/bin/gem on other servers it's in /usr/local/rvm/rubies/ruby-2.0.0-p353/bin/gem

My stanza uses the generate function in puppet to pull out the default ruby gem installation as follows:

$ruby_gem_location = generate('which', 'gem')
exec { "remove-remote_syslog":
        command => "gem uninstall remote_syslog",
        path    => "$ruby_gem_location:/opt/ruby/bin:/usr/bin:/usr/sbin",
        onlyif  => "$ruby_gem_location list|grep remote_syslog"
        }

When I run puppet agent I get the following error:

Generators must be fully qualified at ****redacted*

I have also tried to provide a default path for the which command as follows:

$ruby_gem_location = generate('/usr/bin/which', 'gem') 

and now the error says : Could not evaluate: Could not find command '/usr/bin/gem

I checked the target server and the gem command is in

/usr/local/rvm/rubies/ruby-2.0.0-p353/bin/gem

What am I doing wrong?

How can I pull out the default ruby gem location on our servers?

Thank you in advance


Solution

  • Your code

    $ruby_gem_location = generate('/usr/bin/which', 'gem')
    

    will generate a full path to your gem command (if it succeeds). From the result you describe, I think it is generating '/usr/bin/gem', which is perhaps a symlink to the real gem command. You are putting that into your command path instead of just the directory part, and that will not be helpful. It is not, however, the source of the error message you report.

    The real problem here is that generate(), like all DSL fucntions, runs during catalog building. I infer from your results that you are using a master / agent setup, so generate() is giving you a full path to gem -- evidently /usr/bin/gem -- on the master. Since the whole point is that different servers have gem installed in different places, this is unhelpful. The actual error message arises from an attempt to execute your onlyif command with the wrong path to gem.

    Your best way forward is probably to create a custom fact with which each node can report the appropriate location of the gem binary. You can then use that fact's value in your Exec, maybe:

    exec { "remove-remote_syslog":
      command => "$::ruby_gem_path uninstall remote_syslog",
      onlyif  => "$::ruby_gem_path list | grep remote_syslog"
    }
    

    Note that you don't need a path attribute if you give a complete path to the executable in the first place.

    Details on creating the $::ruby_gem_path custom fact depend on a number of factors, and in their full generality they are rather too broad for SO, but PL provides good documentation.