Melvin Mah
Melvin Mah

Reputation: 125

Puppet: Can $hostname be checked against a master file before running manifest head?

I've seen someone doing a check on whether an agent's MAC address is on a specific regular expression before it runs the specified stuff below. The example is something like this:

if $is_virtual == "true" and $kernel == "Linux" and $macaddress =~ /^02:00:0A/ {
    include nmonitor
    include rootsh
    include checkmk-agent
    include backuppcacc
    include onecontext
    include sysstatpkg
    include ensurekvmsudo
    include cronntpdate
}

That's just it in that particular manifest file. Similarly another manifest example but via regular expression below:

node /^mi-cloud-(dev|stg|prd)-host/ {
    if $is_virtual == 'false' {
        include etchosts
        include checkmk-agent
        include nmonitor
        include rootsh
        include sysstatpkg
        include cronntpdate
        include fstab-ds-dev
    }
}

I've been asked of whether can that similar concept be applied upon checking the agent's hostname with a master file of hostnames allowed to be run or otherwise.

I am not sure whether it can be done, but the rough idea goes around something like:

file { 'hostmasterfile.ini'
        ensure  => present,
        source  => puppet:///test/hostmaster.ini,
        content => $hostname
}

$coname = content


#Usually the start / head of the manifest
if $hostname == $coname {
   include <a>
   include <b>
}

Note: $fqdn is out of the question.

To my knowledge, I have not seen any such sample manifest that matches the request. Whats more, it goes against a standard practice of keeping things easier to manage and not putting all eggs in a basket.

An ex-colleague of mine claims that idea above is about self-provisioning. However that concept is non-existent in Puppet (he posed that question at a workshop a few months back). I am not sure how true is that though.

If that thing above can be done, any suggestion of how can it be done? Or is it best to go back to the standard one manifest per node for easy maintenance?

Thanks very much. M

Upvotes: 1

Views: 6194

Answers (1)

Felix Frank
Felix Frank

Reputation: 8223

Well, you can replace your node blocks with if constructs.

if $hostname == 'host1' {
    # manifest for host1 here
}

You can combine this with some sort of inifile (e.g., using the generate) function. If the <a> and <b> for the include statements are then fetched from your ini file as well, you have constructed a crude ENC.

Note that this has security implications - any agent can claim to have any host name. It's even very simple to do:

FACTER_hostname=kerberos01 puppet agent --test

Any node can receive the catalog for kerberos01 this way. (node blocks rely on $certname instead, which cannot be forged.)

I could not decipher your precise intent from your question, but I suspect that you really want an ENC or a Hiera based approach.

Edit after feedback from your first comment:

To make the master read contents from local files, you should

  1. get rid of the file { 'hostmasterfile.ini': } - it only allows you to set contents, not retrieve them
  2. initialize the variable content using the file function (this will make all nodes fail if the file is not readable)

The code could look like this (assuming that there can be multiple host names in the ini file).

$ini_data = file('/etc/puppet/files/test/hostmaster.ini')

Next step would be a regex lookup like this:

if $ini_data =~ /name=$hostname/ {

Unfortunately, this does not work! Puppet will not expand variable values in regular expressions, apparently.

You can use this (kind of silly) workaround:

$ini_lookup = regsubst($ini_data, "name=$hostname", '__FOUND__')

if $ini_lookup =~ /__FOUND__/ {
     ...
}

Final remark about security: If your team is adamant about not using $certname for this lookup (although it should be easy to map host names to cert names), you should consider adding the host name to your trusted facts.

Upvotes: 1

Related Questions