Using data types on hashes

130 views
Skip to first unread message

Martin Alfke

unread,
Aug 24, 2015, 8:39:02 AM8/24/15
to puppet-dev
Hi,

I am playing around with the Puppet 4 Type system and nested hashes.
Is it possible to use the Type system on a hash and check sub hashes as Struct?

# nested hashes
$hash = {
‘ben’ => {
uid => 2204,
home => ‘/home/ben’,
},
‘jones’ => {
uid => 2205,
home => ‘home/jones’,
}
}

# class definition
class users (
Hash[String, Struct[{ uid => Integer, home => Pattern[/^\/.*/]}]] $hash,
){

}

# class declaration
class { ‘users’:
hash => $hash,
}

In this case I receive the following error:
Error: Expected parameter 'hash' of 'Class[Users]' to have type Hash[String, Struct[{'uid'=>Integer, 'home'=>Pattern[/^\/.*/]}]], got Struct[{'ben'=>Struct[{'uid'=>Integer, 'home'=>String}], 'jones'=>Struct[{'uid'=>Integer, 'home'=>String}]}] at /root/hash.pp:16 on node puppetmaster.example.net

When using the Struct one needs to know the keys. But the keys may be any arbitrary value.

Within class users I could use the keys function and a define and check for the data types within the define.
But I thought that the mentioned approach is valid (at least I haven’t found a hint that my approach is not valid).

Any help/feedback appreciated,

best,
Martin

Henrik Lindberg

unread,
Aug 26, 2015, 11:50:15 AM8/26/15
to puppe...@googlegroups.com
On 2015-24-08 14:38, Martin Alfke wrote:
> Hi,
>
> I am playing around with the Puppet 4 Type system and nested hashes.
> Is it possible to use the Type system on a hash and check sub hashes as Struct?
>
Yes, certainly.

> # nested hashes
> $hash = {
> ‘ben’ => {
> uid => 2204,
> home => ‘/home/ben’,
> },
> ‘jones’ => {
> uid => 2205,
> home => ‘home/jones’,
> }
> }
>
> # class definition
> class users (
> Hash[String, Struct[{ uid => Integer, home => Pattern[/^\/.*/]}]] $hash,
> ){
> …
> }
>
> # class declaration
> class { ‘users’:
> hash => $hash,
> }
>
> In this case I receive the following error:
> Error: Expected parameter 'hash' of 'Class[Users]' to have type Hash[String, Struct[{'uid'=>Integer, 'home'=>Pattern[/^\/.*/]}]], got Struct[{'ben'=>Struct[{'uid'=>Integer, 'home'=>String}], 'jones'=>Struct[{'uid'=>Integer, 'home'=>String}]}] at /root/hash.pp:16 on node puppetmaster.example.net
>
That is because you cannot match integer values (such as 2204) with a
Pattern (it only matches strings).

> When using the Struct one needs to know the keys. But the keys may be any arbitrary value.
>
If you want to support any arbitrary value of any type (including
Undef), use the Any type. If you do not want Undef, you can use
NotUndef[Any]. If you want to be explicit about values of integers and
strings (not being empty strings say), you can use a Variant type - e.g.
Variant[Integer, String] (any string or integer value),
Variant[Integer[0, default], String[1]] (any 0 or positive integer, or
any non empty string). etc.

You can also use the Scalar type if you want to accept non undef single
values (matches any Integer, Float, String, and Regular expression).

Plenty of options depending on how stringent you want the check to be.

> Within class users I could use the keys function and a define and check for the data types within the define.
> But I thought that the mentioned approach is valid (at least I haven’t found a hint that my approach is not valid).
>

Your approach is valid, you just got tripped up by Integer values not
matching with a Pattern.

Regards
- henrik
--

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

Martin Alfke

unread,
Aug 26, 2015, 11:56:35 AM8/26/15
to puppe...@googlegroups.com
Hi Henrik,
On 26 Aug 2015, at 17:49, Henrik Lindberg <henrik....@cloudsmith.com> wrote:

> On 2015-24-08 14:38, Martin Alfke wrote:
>> Hi,
>>
>> I am playing around with the Puppet 4 Type system and nested hashes.
>> Is it possible to use the Type system on a hash and check sub hashes as Struct?
>>
> Yes, certainly.
>
>> # nested hashes
>> $hash = {
>> ‘ben’ => {
>> uid => 2204,
>> home => ‘/home/ben’,
>> },
>> ‘jones’ => {
>> uid => 2205,
>> home => ‘home/jones’,
>> }
>> }
>>
>> # class definition
>> class users (
>> Hash[String, Struct[{ uid => Integer, home => Pattern[/^\/.*/]}]] $hash,
>> ){
>> …
>> }
> …

> That is because you cannot match integer values (such as 2204) with a Pattern (it only matches strings).

??

Hash[String, Struct[{ uid => Integer, home => Pattern[/^\/.*/]}]] $hash

Am I missing something?
Within the Struct I provide the key name (uid) and Type (Integer) and the second key (home) with Type (Pattern).

>
>> Within class users I could use the keys function and a define and check for the data types within the define.
>> But I thought that the mentioned approach is valid (at least I haven’t found a hint that my approach is not valid).
>>
>
> Your approach is valid, you just got tripped up by Integer values not matching with a Pattern.

Good to know…

Many thanks,
Martin

Henrik Lindberg

unread,
Aug 26, 2015, 8:09:01 PM8/26/15
to puppe...@googlegroups.com
On 2015-26-08 17:56, Martin Alfke wrote:
> Hi Henrik,
> On 26 Aug 2015, at 17:49, Henrik Lindberg <henrik....@cloudsmith.com> wrote:
>
>> On 2015-24-08 14:38, Martin Alfke wrote:
>>> Hi,
>>>
>>> I am playing around with the Puppet 4 Type system and nested hashes.
>>> Is it possible to use the Type system on a hash and check sub hashes as Struct?
>>>
>> Yes, certainly.
>>
>>> # nested hashes
>>> $hash = {
>>> ‘ben’ => {
>>> uid => 2204,
>>> home => ‘/home/ben’,
>>> },
>>> ‘jones’ => {
>>> uid => 2205,
>>> home => ‘home/jones’,
>>> }
>>> }
>>>
>>> # class definition
>>> class users (
>>> Hash[String, Struct[{ uid => Integer, home => Pattern[/^\/.*/]}]] $hash,
>>> ){
>>> …
>>> }
>> …
>
>> That is because you cannot match integer values (such as 2204) with a Pattern (it only matches strings).
>
> ??
>
Doh, I misread.

> Hash[String, Struct[{ uid => Integer, home => Pattern[/^\/.*/]}]] $hash
>
> Am I missing something?
> Within the Struct I provide the key name (uid) and Type (Integer) and the second key (home) with Type (Pattern).
>
Yes, you are indeed. Your regular expression is however not correct for
the home directories that you have given. The regexp /^\/.*/ requires
that the string starts with a slash. If you change your input to say

home => '/home/jones'

it should work.

Or change the regular expression. The ^ means anchor at start of string,
and \/ means a slash is required, then 0 or more characters. If you
accept any String, simply use String. If you want to ensure that it is a
valid path you need a way more complex regular expression.

Were you attempting to specify "not allowed to start with a slash"?
If so, try Pattern[/^[^\/]+.*/]

>>
>>> Within class users I could use the keys function and a define and check for the data types within the define.
>>> But I thought that the mentioned approach is valid (at least I haven’t found a hint that my approach is not valid).
>>>
>>
>> Your approach is valid, you just got tripped up by Integer values not matching with a Pattern.
>
> Good to know…
>
Sorry that I went of on a tangent after misreading the error message.
Hope the suggestions above will work out better for you.

Regards
Henrik

Martin Alfke

unread,
Aug 27, 2015, 3:02:01 AM8/27/15
to puppe...@googlegroups.com

On 27 Aug 2015, at 02:08, Henrik Lindberg <henrik....@cloudsmith.com> wrote:

> On 2015-26-08 17:56, Martin Alfke wrote:
>> Hi Henrik,
>> On 26 Aug 2015, at 17:49, Henrik Lindberg <henrik....@cloudsmith.com> wrote:
>>
>
>> Hash[String, Struct[{ uid => Integer, home => Pattern[/^\/.*/]}]] $hash
>>
>> Am I missing something?
>> Within the Struct I provide the key name (uid) and Type (Integer) and the second key (home) with Type (Pattern).
>>
> Yes, you are indeed. Your regular expression is however not correct for the home directories that you have given. The regexp /^\/.*/ requires that the string starts with a slash. If you change your input to say
>
> home => '/home/jones'
>
> it should work.

Ah. It does work providing correct data.
The error message if I do provide a string with missing / at start pointed me into wrong direction.

Many thanks for your help.
I know learned that using Struct inside has will not give a detailed output on a specific sub hash to be wrong.
It complains about the whole hash being wrong without details.

I am now heading for usage of keys function and check the elements of the sub hash inside a define.

Best,
Martin


>
> Or change the regular expression. The ^ means anchor at start of string, and \/ means a slash is required, then 0 or more characters. If you accept any String, simply use String. If you want to ensure that it is a valid path you need a way more complex regular expression.
>
> Were you attempting to specify "not allowed to start with a slash"?
> If so, try Pattern[/^[^\/]+.*/]
>
>>>
>>>> Within class users I could use the keys function and a define and check for the data types within the define.
>>>> But I thought that the mentioned approach is valid (at least I haven’t found a hint that my approach is not valid).
>>>>
>>>
>>> Your approach is valid, you just got tripped up by Integer values not matching with a Pattern.
>>
>> Good to know…
>>
> Sorry that I went of on a tangent after misreading the error message.
> Hope the suggestions above will work out better for you.
>
> Regards
> Henrik
>
> --
>
> Visit my Blog "Puppet on the Edge"
> http://puppet-on-the-edge.blogspot.se/
>
> --
> You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/mrlkee%244st%241%40ger.gmane.org.
> For more options, visit https://groups.google.com/d/optout.

Henrik Lindberg

unread,
Aug 29, 2015, 6:19:51 AM8/29/15
to puppe...@googlegroups.com
On 2015-27-08 9:01, Martin Alfke wrote:
>
> On 27 Aug 2015, at 02:08, Henrik Lindberg <henrik....@cloudsmith.com> wrote:
>
>> On 2015-26-08 17:56, Martin Alfke wrote:
>>> Hi Henrik,
>>> On 26 Aug 2015, at 17:49, Henrik Lindberg <henrik....@cloudsmith.com> wrote:
>>>
>>
>>> Hash[String, Struct[{ uid => Integer, home => Pattern[/^\/.*/]}]] $hash
>>>
>>> Am I missing something?
>>> Within the Struct I provide the key name (uid) and Type (Integer) and the second key (home) with Type (Pattern).
>>>
>> Yes, you are indeed. Your regular expression is however not correct for the home directories that you have given. The regexp /^\/.*/ requires that the string starts with a slash. If you change your input to say
>>
>> home => '/home/jones'
>>
>> it should work.
>
> Ah. It does work providing correct data.
> The error message if I do provide a string with missing / at start pointed me into wrong direction.
>
> Many thanks for your help.
> I know learned that using Struct inside has will not give a detailed output on a specific sub hash to be wrong.
> It complains about the whole hash being wrong without details.
>

We have improvements for how type mismatches are reported. Hope to get
that into 4.3.0. It has a couple of heuristics regarding what is most
useful to know, and in your case it will point to the "path" where the
first mismatch was found.

- henrik

Martin Alfke

unread,
Aug 29, 2015, 1:51:16 PM8/29/15
to puppe...@googlegroups.com

On 29 Aug 2015, at 12:19, Henrik Lindberg <henrik....@cloudsmith.com> wrote:
>>
>> Many thanks for your help.
>> I know learned that using Struct inside has will not give a detailed output on a specific sub hash to be wrong.
>> It complains about the whole hash being wrong without details.
>>
>
> We have improvements for how type mismatches are reported. Hope to get that into 4.3.0. It has a couple of heuristics regarding what is most useful to know, and in your case it will point to the "path" where the first mismatch was found.

That’s great news.
For the moment I am checking types inside the define which is working fine.
Looking forward to seeing type mismatches improvement in 4.3.

Best,
Martin

Reply all
Reply to author
Forward
0 new messages