puppetfacter

Injecting facter into file content - no implicit conversion of Hash into String


I want to inject some values from facter <prop> into a file content.

It works with $fqdn since facter fqdn returns string.

node default {
  file {'/tmp/README.md':
    ensure  => file,
    content => $fqdn, # $(facter fqdn)
    owner   => 'root',
  }

}

However, it does not work with hash object (facter os):

   node default {
      file {'/tmp/README.md':
        ensure  => file,
        content => $os, # $(facter os) !! DOES NOT WORK
        owner   => 'root',
      }

   }

And getting this error message when running puppet agent -t:

Error: Failed to apply catalog: Parameter content failed on File[/tmp/README.md]: Munging failed for value {"architecture"=>"x86_64", "family"=>"RedHat", "hardware"=>"x86_64", "name"=>"CentOS", "release"=>{"full"=>"7.4.1708", "major"=>"7", "minor"=>"4"}, "selinux"=>{"config_mode"=>"enforcing", "config_policy"=>"targeted", "current_mode"=>"enforcing", "enabled"=>true, "enforced"=>true, "policy_version"=>"28"}} in class content: no implicit conversion of Hash into String (file: /etc/puppetlabs/code/environments/production/manifests/site.pp, line: 2)

How to convert the hash to string inside the pp file?


Solution

  • If you have Puppet >= 4.5.0, it is now possible to natively convert various data types to strings in the manifests (i.e. in the pp files). The conversion functions are documented here.

    This would do what you want:

    file { '/tmp/README.md':
      ensure  => file,
      content => String($os),
    }
    

    or better:

    file { '/tmp/README.md':
      ensure  => file,
      content => String($facts['os']),
    }
    

    On my Mac OS X, that leads to a file with:

    {'name' => 'Darwin', 'family' => 'Darwin', 'release' => {'major' => '14', 'minor' => '5', 'full' => '14.5.0'}}
    

    Have a look at all that documentation, because there are quite a lot of options that might be useful to you.

    Of course, if you wanted the keys inside the $os fact,

    file { '/tmp/README.md':
      ensure  => file,
      content => $facts['os']['family'],
    }
    

    Now, if you don't have the latest Puppet, and you don't have the string conversion functions, the old way of doing this would be via templates and embedded Ruby (ERB), e.g.

    $os_str = inline_template("<%= @os.to_s %>")
    file { '/tmp/README.md':
      ensure => file,
      content => $os_str,
    }
    

    This actually leads to a slightly differently-formatted Hash since Ruby, not Puppet does the formatting:

    {"name"=>"Darwin", "family"=>"Darwin", "release"=>{"major"=>"14", "minor"=>"5", "full"=>"14.5.0"}}