FIll array in loop

660 views
Skip to first unread message

Helmut Schneider

unread,
Jan 9, 2022, 9:31:32 AM1/9/22
to puppet...@googlegroups.com
Hi,

I need to fill an array in a loop. While I understand variable scoping I
found some information that it is possible.

https://stackoverflow.com/questions/41041549/puppet-adding-array-elements-in-a-loop/41047623
https://blog.thewatertower.org/2019/04/15/building-or-appending-to-an-array-using-a-lambda-in-puppet/

Unfortunately I'm not able to adapt it to my needs:

$array = []
[1, 2, 3].each |$variable| {
add $variable to $array
}

Any tips?

Thank you!

Dirk Heinrichs

unread,
Jan 10, 2022, 2:04:12 AM1/10/22
to puppet...@googlegroups.com
Am Sonntag, dem 09.01.2022 um 15:31 +0100 schrieb Helmut Schneider:

Unfortunately I'm not able to adapt it to my needs:

$array = []
[1, 2, 3].each |$variable| {
  add $variable to $array
}

Any tips?

The first link you posted already has the answer. Puppet variables are immutable so you can't create an empty array and then add vaules to it. It must be done in one step and, as that answer says, you'll have to use the map function, like

$array = [1, 2, 3].map |$var| { $var }

HTH...

Dirk
-- 
Dirk Heinrichs
Senior Systems Engineer, Delivery Pipeline
OpenText ™ Discovery | Recommind
Recommind GmbH, Von-Liebig-Straße 1, 53359 Rheinbach
Vertretungsberechtigte Geschäftsführer Gordon Davies, Madhu Ranganathan, Christian Waida, Registergericht Amtsgericht Bonn, Registernummer HRB 10646
This e-mail may contain confidential and/or privileged information. If you are not the intended recipient (or have received this e-mail in error) please notify the sender immediately and destroy this e-mail. Any unauthorized copying, disclosure or distribution of the material in this e-mail is strictly forbidden
Diese E-Mail enthält vertrauliche und/oder rechtlich geschützte Informationen. Wenn Sie nicht der richtige Adressat sind oder diese E-Mail irrtümlich erhalten haben, informieren Sie bitte sofort den Absender und vernichten Sie diese Mail. Das unerlaubte Kopieren sowie die unbefugte Weitergabe dieser Mail sind nicht gestattet.

Helmut Schneider

unread,
Jan 10, 2022, 8:29:20 AM1/10/22
to puppet...@googlegroups.com
Am 10.01.2022 um 08:04 schrieb 'Dirk Heinrichs' via Puppet Users:
> Am Sonntag, dem 09.01.2022 um 15:31 +0100 schrieb Helmut Schneider:
>
>> Unfortunately I'm not able to adapt it to my needs:
>>
>> $array = []
>> [1, 2, 3].each |$variable| {
>>   add $variable to $array
>> }
>>
>> Any tips?
>
> The first link you posted already has the answer. Puppet variables are
> immutable so you can't create an empty array and then add vaules to it.
> It must be done in one step and, as that answer says, you'll have to use
> the map function, like
>
> $array = [1, 2, 3].map |$var| { $var }
>
> HTH...

I'm afraid I still do not unterstand this correctly:

profiles:
vpn:
openvpn:
syslogd:
40-openvpn.conf:
openvpn:
'*.*': '/var/log/openvpn.log'

$array = [1].map |$var| {
keys($profiles).each |$category| {
if $profiles[$category] =~ Hash {
keys($profiles[$category]).each |$app| {
"$app"
}
}
}
}

notify {"Array: $array":}

This returned "vpn" ($category) while I'd expect "openvpn" ($app).

Dirk Heinrichs

unread,
Jan 10, 2022, 9:56:00 AM1/10/22
to puppet...@googlegroups.com
Am Montag, dem 10.01.2022 um 14:29 +0100 schrieb Helmut Schneider:

I'm afraid I still do not unterstand this correctly:

profiles:
   vpn:
     openvpn:
       syslogd:
         40-openvpn.conf:
           openvpn:
             '*.*':                          '/var/log/openvpn.log'

$array = [1].map |$var| {
   keys($profiles).each |$category| {
     if $profiles[$category] =~ Hash {
       keys($profiles[$category]).each |$app| {
         "$app"
       }
     }
   }
}

Not 100% sure this will be correct, since your "profiles" sample above has only one entry, but anyway...

I guess what you'd need to do is

$array = $profiles.map |...| {
  ...
}

You can't use each here because it's an iterator that returns one item at a time, which would then have to be added to your array, which isn't possible (since Puppet variables are immutable). map, OTOH, returns an array (or hash) generated from another array (or hash).

For example:

$array = [1, 2, 3].map |$num| { "This is element number ${num}."}

Would result in $array like:

[
  "This is element number 1.",
  "This is element number 2.",
  "This is element number 3."
]

Again, see the example in your first link.

Helmut Schneider

unread,
Jan 10, 2022, 11:42:30 AM1/10/22
to puppet...@googlegroups.com
Am 10.01.2022 um 15:55 schrieb 'Dirk Heinrichs' via Puppet Users:
> Am Montag, dem 10.01.2022 um 14:29 +0100 schrieb Helmut Schneider:
>
>> I'm afraid I still do not unterstand this correctly:
>>
>> profiles:
>> vpn:
>> openvpn:
>> syslogd:
>> 40-openvpn.conf:
>> openvpn:
>> '*.*': '/var/log/openvpn.log'
>>
>> $array = [1].map |$var| {
>> keys($profiles).each |$category| {
>> if $profiles[$category] =~ Hash {
>> keys($profiles[$category]).each |$app| {
>> "$app"
>> }
>> }
>> }
>> }
>
> Not 100% sure this will be correct, since your "profiles" sample above
> has only one entry, but anyway...
>
> I guess what you'd need to do is
>
> $array = $profiles.map |...| {
> ...
> }

Well, yes, it outputs "openvpn" now but at the end of the day I hoped to
get the "openvpn" key from "40-openvpn.conf" and not from "vpn".

profiles:
vpn:
openvpn:
syslogd:
40-openvpn.conf:
openvpn:
'*.*': '/var/log/openvpn.log'
backup:
bacula:
syslogd:
40-bacula.conf:
bacula-dir:
'*.*': '/var/log/bacula-dir.log'
bacula-fd:
'*.*': '/var/log/bacula-fd.log'
bacula-sd:
'*.*': '/var/log/bacula-sd.log'
management:
snmpd:
syslogd:
40-snmpd.conf:
snmpd:
'*.*': '/var/log/snmpd.log'

I'm looking for a way to get the information of $profiles.*.*.syslogd or
better $profiles.*.*.syslogd.*. So "openvpn", "bacula-dir", "bacula-fd",
... into an array / hash / whatever.

Karsten Heymann

unread,
Jan 10, 2022, 12:07:45 PM1/10/22
to puppet...@googlegroups.com
Hi Helmut,
you could take this as a starting point (untested):

$profile_logging = $profiles.map | $p_name, $p_data | { $p_data.map | $s_name, $s_data | { $s_data['syslog'] } }.flatten

p_ is the outer profile layer, s_ is the inner service layer.

Some notes on solving this kind of problems:
1) It can be much easier to develop these functions in a small minimal pp file which only contains a sample dict as puppet code, the extraction code and a notify to print the output. With such a file, you can test small changes in the code without going through the puppet master.
2) Sometimes it can be easier to re-design the data structure than to write complex extraction code. It is possible to describe complex setups in a single yaml dict, but it may not be the best idea.
3) If you may have requirements like this repeatedly, I would recommend dedicating some time into understanding the relevant puppet functions (map, filter, then, group_by, ...). For someone who has not yet worked with functional languages, this is quiete a change in mind that will take some time to grasp and process.

Best regards
Karsten

Helmut Schneider

unread,
Jan 12, 2022, 10:21:23 AM1/12/22
to puppet...@googlegroups.com
Am 10.01.2022 um 18:07 schrieb Karsten Heymann:
> Hi Helmut,
> you could take this as a starting point (untested):
>
> $profile_logging = $profiles.map | $p_name, $p_data | { $p_data.map |
> $s_name, $s_data | { $s_data['syslog'] } }.flatten
>
> p_ is the outer profile layer, s_ is the inner service layer.

$array = keys($profiles).map |$ca_index, $category| {
keys($profiles[$category]).map |$a_index, $app| {
keys($profiles[$category][$app]).map |$co_index, $config| {
if $config == "syslogd" {
keys($profiles[$category][$app][$config]).map |$f_index, $file| {
keys($profiles[$category][$app][$config][$file]).map
|$p_prog, $prog| {
$prog
}
}
}
}
}
}.flatten

$profile_logging = $array.filter |$index, $entry| {
$entry =~ NotUndef
}

notify {"profile_logging: $profile_logging":}



Maybe not best code style but works. Thank you!

Reply all
Reply to author
Forward
0 new messages