How to access $facts['os'] in a manifest

2,795 views
Skip to first unread message

Marc Haber

unread,
Jun 1, 2016, 2:43:43 PM6/1/16
to puppet...@googlegroups.com
Hi,

I have the following code:

if( $facts['os']['family'] == 'RedHat' and $facts['os']['release']['major'] == '7' ) {
file { "...":
ensure => 'file',
path => "...",
content => "...",
}
}

My agent is puppet 3.8.4, my master is 3.7.3 with no special
configuration.

Here is the fact:

$ facter | grep ^os
os => {"name"=>"CentOS", "family"=>"RedHat", "release"=>{"major"=>"7", "minor"=>"2", "full"=>"7.2.1511"}, "lsb"=>{"distcodename"=>"Core", "distid"=>"CentOS", "distdescription"=>"CentOS Linux release 7.2.1511 (Core) ", "release"=>":core-4.1-amd64:core-4.1-noarch", "distrelease"=>"7.2.1511", "majdistrelease"=>"7", "minordistrelease"=>"2"}}
osfamily => RedHat

When building the catalog, I get the dreaded "facts is not a hash or
array". When searching for this, I get tangled in a maze of "if your
agent is older than foo, and your server has stringify_bla set, then
you might succeed with baz."

How do I write my manifest to get things

(a) pretty
(b) non-deprecated?

Any hints will be appreciated.

Greetings
Marc

--
-----------------------------------------------------------------------------
Marc Haber | "I don't trust Computers. They | Mailadresse im Header
Mannheim, Germany | lose things." Winona Ryder | Fon: *49 621 31958061
Nordisch by Nature | How to make an American Quilt | Fax: *49 621 31958062

Henrik Lindberg

unread,
Jun 1, 2016, 3:35:09 PM6/1/16
to puppet...@googlegroups.com
On 01/06/16 16:43, Marc Haber wrote:
> Hi,
>
> I have the following code:
>
> if( $facts['os']['family'] == 'RedHat' and $facts['os']['release']['major'] == '7' ) {
> file { "...":
> ensure => 'file',
> path => "...",
> content => "...",
> }
> }
>
> My agent is puppet 3.8.4, my master is 3.7.3 with no special
> configuration.
>
> Here is the fact:
>
> $ facter | grep ^os
> os => {"name"=>"CentOS", "family"=>"RedHat", "release"=>{"major"=>"7", "minor"=>"2", "full"=>"7.2.1511"}, "lsb"=>{"distcodename"=>"Core", "distid"=>"CentOS", "distdescription"=>"CentOS Linux release 7.2.1511 (Core) ", "release"=>":core-4.1-amd64:core-4.1-noarch", "distrelease"=>"7.2.1511", "majdistrelease"=>"7", "minordistrelease"=>"2"}}
> osfamily => RedHat
>
> When building the catalog, I get the dreaded "facts is not a hash or
> array". When searching for this, I get tangled in a maze of "if your
> agent is older than foo, and your server has stringify_bla set, then
> you might succeed with baz."
>
> How do I write my manifest to get things
>
> (a) pretty
> (b) non-deprecated?
>
> Any hints will be appreciated.
>

First check what you get in puppet with a simple manifest:

notice($facts)

If all the data elements are strings, turn off stringify_facts - it
flattens data and makes all facts be strings.

Hope that helps.

If you can, hop on to the puppet slack or IRC channels to get more help
from community members - always easier interactively.

- henrik
--

Visit my Blog "Puppet on the Edge"
http://puppet-on-the-edge.blogspot.se/

Marc Haber

unread,
Jun 2, 2016, 7:22:11 AM6/2/16
to puppet...@googlegroups.com
On Wed, Jun 01, 2016 at 05:34:59PM +0200, Henrik Lindberg wrote:
> First check what you get in puppet with a simple manifest:
>
> notice($facts)

$ sudo puppet apply -e 'notify{"${os}":}'
Notice: Compiled catalog for host in environment production in 0.02 seconds
Notice: {"name"=>"CentOS", "family"=>"RedHat", "release"=>{"major"=>"7", "minor"=>"2", "full"=>"7.2.1511"}, "lsb"=>{"distcodename"=>"Core", "distid"=>"CentOS", "distdescription"=>"CentOS Linux release 7.2.1511 (Core) ", "release"=>":core-4.1-amd64:core-4.1-noarch", "distrelease"=>"7.2.1511", "majdistrelease"=>"7", "minordistrelease"=>"2"}}
Notice: /Stage[main]/Main/Notify[{"name"=>"CentOS", "family"=>"RedHat", "release"=>{"major"=>"7", "minor"=>"2", "full"=>"7.2.1511"}, "lsb"=>{"distcodename"=>"Core", "distid"=>"CentOS", "distdescription"=>"CentOS Linux release 7.2.1511 (Core) ", "release"=>":core-4.1-amd64:core-4.1-noarch", "distrelease"=>"7.2.1511", "majdistrelease"=>"7", "minordistrelease"=>"2"}}]/message: defined 'message' as '{"name"=>"CentOS", "family"=>"RedHat", "release"=>{"major"=>"7", "minor"=>"2", "full"=>"7.2.1511"}, "lsb"=>{"distcodename"=>"Core", "distid"=>"CentOS", "distdescription"=>"CentOS Linux release 7.2.1511 (Core) ", "release"=>":core-4.1-amd64:core-4.1-noarch", "distrelease"=>"7.2.1511", "majdistrelease"=>"7", "minordistrelease"=>"2"}}'
Notice: Finished catalog run in 0.70 seconds
$ sudo puppet apply -e 'notify{"foo ${facts}":}'
Notice: Compiled catalog for host in environment production in 0.03 seconds
Notice: foo
Notice: /Stage[main]/Main/Notify[foo ]/message: defined 'message' as 'foo '
Notice: Finished catalog run in 0.81 seconds
$ sudo puppet --version
3.8.6

Unfortunately, I cannot see here whether ${os} is actually a string,
can I?

$ sudo puppet apply -e '$myhash={ key1 => 'val1', key2 => 'val2' } notify{"foo ${myhash}":}'
Notice: Compiled catalog for host in environment production in 0.08 seconds
Notice: foo {"key1"=>"val1", "key2"=>"val2"}
Notice: /Stage[main]/Main/Notify[foo {"key1"=>"val1", "key2"=>"val2"}]/message: defined 'message' as 'foo {"key1"=>"val1", "key2"=>"val2"}'
Notice: Finished catalog run in 0.71 seconds
$ sudo puppet apply -e '$mystring="{\"key1\"=>\"val1\", \"key2\"=>\"val2\"}" notify{"foo ${mystring}":}'
Notice: Compiled catalog for host in environment production in 0.03 seconds
Notice: foo {"key1"=>"val1", "key2"=>"val2"}
Notice: /Stage[main]/Main/Notify[foo {"key1"=>"val1", "key2"=>"val2"}]/message: defined 'message' as 'foo {"key1"=>"val1", "key2"=>"val2"}'
Notice: Finished catalog run in 0.72 seconds
1.pportal|e13itfe@jira01 ~ $

Is ${os} now a string or not?

And, why is ${facts} obviously empty?

> If all the data elements are strings, turn off stringify_facts - it flattens
> data and makes all facts be strings.

I cannot do this in the production without excessive coordinative
effort. The colleagues managing the master side say that haven't
explicitly configured that settings and are going to stay with the
default.

> If you can, hop on to the puppet slack or IRC channels to get more help from
> community members - always easier interactively.

I am reluctant to discuss configuration snippets on IRC and currently
cannot guarantee timely answers. And, I am trying to cut down on the
number of IRC channels I am on ;-) But I'll think about it.

Greetings
Marc

--
-----------------------------------------------------------------------------
Marc Haber | "I don't trust Computers. They | Mailadresse im Header
Leimen, Germany | lose things." Winona Ryder | Fon: *49 6224 1600402
Nordisch by Nature | How to make an American Quilt | Fax: *49 6224 1600421

Henrik Lindberg

unread,
Jun 2, 2016, 12:42:29 PM6/2/16
to puppet...@googlegroups.com
On 02/06/16 09:22, Marc Haber wrote:
> On Wed, Jun 01, 2016 at 05:34:59PM +0200, Henrik Lindberg wrote:
>> First check what you get in puppet with a simple manifest:
>>
>> notice($facts)
>
> $ sudo puppet apply -e 'notify{"${os}":}'
> Notice: Compiled catalog for host in environment production in 0.02 seconds
> Notice: {"name"=>"CentOS", "family"=>"RedHat", "release"=>{"major"=>"7", "minor"=>"2", "full"=>"7.2.1511"}, "lsb"=>{"distcodename"=>"Core", "distid"=>"CentOS", "distdescription"=>"CentOS Linux release 7.2.1511 (Core) ", "release"=>":core-4.1-amd64:core-4.1-noarch", "distrelease"=>"7.2.1511", "majdistrelease"=>"7", "minordistrelease"=>"2"}}
> Notice: /Stage[main]/Main/Notify[{"name"=>"CentOS", "family"=>"RedHat", "release"=>{"major"=>"7", "minor"=>"2", "full"=>"7.2.1511"}, "lsb"=>{"distcodename"=>"Core", "distid"=>"CentOS", "distdescription"=>"CentOS Linux release 7.2.1511 (Core) ", "release"=>":core-4.1-amd64:core-4.1-noarch", "distrelease"=>"7.2.1511", "majdistrelease"=>"7", "minordistrelease"=>"2"}}]/message: defined 'message' as '{"name"=>"CentOS", "family"=>"RedHat", "release"=>{"major"=>"7", "minor"=>"2", "full"=>"7.2.1511"}, "lsb"=>{"distcodename"=>"Core", "distid"=>"CentOS", "distdescription"=>"CentOS Linux release 7.2.1511 (Core) ", "release"=>":core-4.1-amd64:core-4.1-noarch", "distrelease"=>"7.2.1511", "majdistrelease"=>"7", "minordistrelease"=>"2"}}'
> Notice: Finished catalog run in 0.70 seconds
> $ sudo puppet apply -e 'notify{"foo ${facts}":}'
> Notice: Compiled catalog for host in environment production in 0.03 seconds
> Notice: foo
> Notice: /Stage[main]/Main/Notify[foo ]/message: defined 'message' as 'foo '
> Notice: Finished catalog run in 0.81 seconds
> $ sudo puppet --version
> 3.8.6
>
> Unfortunately, I cannot see here whether ${os} is actually a string,
> can I?
>

When you notice ${os} it turns the value into the printed string. That
string looks like a hash, so you are indeed seeing a structure value
where you should be able to access $os[name] etc.


> $ sudo puppet apply -e '$myhash={ key1 => 'val1', key2 => 'val2' } notify{"foo ${myhash}":}'
> Notice: Compiled catalog for host in environment production in 0.08 seconds
> Notice: foo {"key1"=>"val1", "key2"=>"val2"}
> Notice: /Stage[main]/Main/Notify[foo {"key1"=>"val1", "key2"=>"val2"}]/message: defined 'message' as 'foo {"key1"=>"val1", "key2"=>"val2"}'
> Notice: Finished catalog run in 0.71 seconds
> $ sudo puppet apply -e '$mystring="{\"key1\"=>\"val1\", \"key2\"=>\"val2\"}" notify{"foo ${mystring}":}'
> Notice: Compiled catalog for host in environment production in 0.03 seconds
> Notice: foo {"key1"=>"val1", "key2"=>"val2"}
> Notice: /Stage[main]/Main/Notify[foo {"key1"=>"val1", "key2"=>"val2"}]/message: defined 'message' as 'foo {"key1"=>"val1", "key2"=>"val2"}'
> Notice: Finished catalog run in 0.72 seconds
> 1.pportal|e13itfe@jira01 ~ $
>
> Is ${os} now a string or not?

There is no mention of ${os} in that snippet

>
> And, why is ${facts} obviously empty?
>

By default, $facts is an opt in before 4.0 and did not exist before
3.5.0. See
https://docs.puppet.com/puppet/3.8/reference/lang_facts_and_builtin_vars.html#the-factsfactname-hash

In almost every case it is ok to turn on support for $facts. It only
breaks something if you already have global variables that clash (very
unlikely).

Hope that helps

- henrik

>> If all the data elements are strings, turn off stringify_facts - it flattens
>> data and makes all facts be strings.
>
> I cannot do this in the production without excessive coordinative
> effort. The colleagues managing the master side say that haven't
> explicitly configured that settings and are going to stay with the
> default.
>
>> If you can, hop on to the puppet slack or IRC channels to get more help from
>> community members - always easier interactively.
>
> I am reluctant to discuss configuration snippets on IRC and currently
> cannot guarantee timely answers. And, I am trying to cut down on the
> number of IRC channels I am on ;-) But I'll think about it.
>
> Greetings
> Marc
>


--

Marc Haber

unread,
Jun 2, 2016, 12:58:50 PM6/2/16
to puppet...@googlegroups.com
Hi,

thanks for your answers. They're helpful.

On Thu, Jun 02, 2016 at 02:42:17PM +0200, Henrik Lindberg wrote:
> On 02/06/16 09:22, Marc Haber wrote:
> >On Wed, Jun 01, 2016 at 05:34:59PM +0200, Henrik Lindberg wrote:
> >>First check what you get in puppet with a simple manifest:
> >>
> >>notice($facts)
> >
> >$ sudo puppet apply -e 'notify{"${os}":}'
> >Notice: Compiled catalog for host in environment production in 0.02 seconds
> >Notice: {"name"=>"CentOS", "family"=>"RedHat", "release"=>{"major"=>"7", "minor"=>"2", "full"=>"7.2.1511"}, "lsb"=>{"distcodename"=>"Core", "distid"=>"CentOS", "distdescription"=>"CentOS Linux release 7.2.1511 (Core) ", "release"=>":core-4.1-amd64:core-4.1-noarch", "distrelease"=>"7.2.1511", "majdistrelease"=>"7", "minordistrelease"=>"2"}}
> >Notice: /Stage[main]/Main/Notify[{"name"=>"CentOS", "family"=>"RedHat", "release"=>{"major"=>"7", "minor"=>"2", "full"=>"7.2.1511"}, "lsb"=>{"distcodename"=>"Core", "distid"=>"CentOS", "distdescription"=>"CentOS Linux release 7.2.1511 (Core) ", "release"=>":core-4.1-amd64:core-4.1-noarch", "distrelease"=>"7.2.1511", "majdistrelease"=>"7", "minordistrelease"=>"2"}}]/message: defined 'message' as '{"name"=>"CentOS", "family"=>"RedHat", "release"=>{"major"=>"7", "minor"=>"2", "full"=>"7.2.1511"}, "lsb"=>{"distcodename"=>"Core", "distid"=>"CentOS", "distdescription"=>"CentOS Linux release 7.2.1511 (Core) ", "release"=>":core-4.1-amd64:core-4.1-noarch", "distrelease"=>"7.2.1511", "majdistrelease"=>"7", "minordistrelease"=>"2"}}'
> >Notice: Finished catalog run in 0.70 seconds
> >$ sudo puppet apply -e 'notify{"foo ${facts}":}'
> >Notice: Compiled catalog for host in environment production in 0.03 seconds
> >Notice: foo
> >Notice: /Stage[main]/Main/Notify[foo ]/message: defined 'message' as 'foo '
> >Notice: Finished catalog run in 0.81 seconds
> >$ sudo puppet --version
> >3.8.6
> >
> >Unfortunately, I cannot see here whether ${os} is actually a string,
> >can I?
> >
>
> When you notice ${os} it turns the value into the printed string. That
> string looks like a hash, so you are indeed seeing a structure value where
> you should be able to access $os[name] etc.

How would it look like if ${os} were actually a hash?

> >$ sudo puppet apply -e '$myhash={ key1 => 'val1', key2 => 'val2' } notify{"foo ${myhash}":}'
> >Notice: Compiled catalog for host in environment production in 0.08 seconds
> >Notice: foo {"key1"=>"val1", "key2"=>"val2"}
> >Notice: /Stage[main]/Main/Notify[foo {"key1"=>"val1", "key2"=>"val2"}]/message: defined 'message' as 'foo {"key1"=>"val1", "key2"=>"val2"}'
> >Notice: Finished catalog run in 0.71 seconds
> >$ sudo puppet apply -e '$mystring="{\"key1\"=>\"val1\", \"key2\"=>\"val2\"}" notify{"foo ${mystring}":}'
> >Notice: Compiled catalog for host in environment production in 0.03 seconds
> >Notice: foo {"key1"=>"val1", "key2"=>"val2"}
> >Notice: /Stage[main]/Main/Notify[foo {"key1"=>"val1", "key2"=>"val2"}]/message: defined 'message' as 'foo {"key1"=>"val1", "key2"=>"val2"}'
> >Notice: Finished catalog run in 0.72 seconds
> >1.pportal|e13itfe@jira01 ~ $
> >
> >Is ${os} now a string or not?
>
> There is no mention of ${os} in that snippet

Misleading question. The snipped was to find out how a notified hash
looks like and a notified string that looks like a stringyfied hash.
There seems to be no difference.

> >And, why is ${facts} obviously empty?
> >
>
> By default, $facts is an opt in before 4.0 and did not exist before 3.5.0.

I missed the part that it's default off in pre 4.0.

> In almost every case it is ok to turn on support for $facts. It only breaks
> something if you already have global variables that clash (very unlikely).

Opened a local ticket.

Thanks agan.

Henrik Lindberg

unread,
Jun 2, 2016, 1:41:44 PM6/2/16
to puppet...@googlegroups.com
Like in the output you got (above).
i.e. { "name" => "CentOS", "family" => " ...", ... }

>>> $ sudo puppet apply -e '$myhash={ key1 => 'val1', key2 => 'val2' } notify{"foo ${myhash}":}'
>>> Notice: Compiled catalog for host in environment production in 0.08 seconds
>>> Notice: foo {"key1"=>"val1", "key2"=>"val2"}
>>> Notice: /Stage[main]/Main/Notify[foo {"key1"=>"val1", "key2"=>"val2"}]/message: defined 'message' as 'foo {"key1"=>"val1", "key2"=>"val2"}'
>>> Notice: Finished catalog run in 0.71 seconds
>>> $ sudo puppet apply -e '$mystring="{\"key1\"=>\"val1\", \"key2\"=>\"val2\"}" notify{"foo ${mystring}":}'
>>> Notice: Compiled catalog for host in environment production in 0.03 seconds
>>> Notice: foo {"key1"=>"val1", "key2"=>"val2"}
>>> Notice: /Stage[main]/Main/Notify[foo {"key1"=>"val1", "key2"=>"val2"}]/message: defined 'message' as 'foo {"key1"=>"val1", "key2"=>"val2"}'
>>> Notice: Finished catalog run in 0.72 seconds
>>> 1.pportal|e13itfe@jira01 ~ $
>>>
>>> Is ${os} now a string or not?
>>
>> There is no mention of ${os} in that snippet
>
> Misleading question. The snipped was to find out how a notified hash
> looks like and a notified string that looks like a stringyfied hash.
> There seems to be no difference.
>
>>> And, why is ${facts} obviously empty?
>>>
>>
>> By default, $facts is an opt in before 4.0 and did not exist before 3.5.0.
>
> I missed the part that it's default off in pre 4.0.
>
>> In almost every case it is ok to turn on support for $facts. It only breaks
>> something if you already have global variables that clash (very unlikely).
>
> Opened a local ticket.
>

Hope that works out for you.

> Thanks agan.
>
np, cheers,

- henrik

Marc Haber

unread,
Jun 2, 2016, 1:55:34 PM6/2/16
to puppet...@googlegroups.com
We're turning around in circles. So I cannot see in a notify whether I
am notifying a hash or a stringyfied hash.

Henrik Lindberg

unread,
Jun 2, 2016, 4:11:02 PM6/2/16
to puppet...@googlegroups.com
Correct, you cannot see the difference.

With future parser you can do:

notice($os =~ Hash)

Which will notice 'true' if $os is a hash

There may be a stdlib function that does something similar - look for
something like is_hash()

Marc Haber

unread,
Jun 3, 2016, 10:27:10 AM6/3/16
to puppet...@googlegroups.com
On Thu, Jun 02, 2016 at 06:10:42PM +0200, Henrik Lindberg wrote:
> With future parser you can do:
>
> notice($os =~ Hash)
>
> Which will notice 'true' if $os is a hash

$ sudo puppet apply -e '$hmpf=is_hash($os) notify{"foo ${hmpf}":}'
Notice: Compiled catalog for hostname in environment production in 0.02 seconds
Notice: foo false
Notice: /Stage[main]/Main/Notify[foo false]/message: defined 'message' as 'foo false'
Notice: Finished catalog run in 0.25 seconds

So we have stringify_facts turned the wrong way here. Thanks for
helping.
Reply all
Reply to author
Forward
0 new messages