24

I would like to iterate over an array that is stored as a Facter fact, and for each element of the array create a new system user and a directory, and finally make API calls to AWS.

Example of the fact: my_env => [shared1,shared2,shared3]

How can I iterate over an array in Puppet?

Alex Harvey
  • 14,494
  • 5
  • 61
  • 97
PapelPincel
  • 4,255
  • 6
  • 39
  • 49
  • 1
    This might be of help: http://stackoverflow.com/questions/12076976/puppet-iteration-string-array – Rilindo Oct 20 '12 at 22:39

6 Answers6

74

This might work, depending on what you are doing

# Assuming fact my_env => [ shared1, shared2, shared3 ]

define my_resource {
  file { "/var/tmp/$name":
    ensure => directory,
    mode   => '0600',
  }
  user { $name:
    ensure => present,
  }
}
my_resource { $my_env: }

It will work if your requirements are simple, if not, Puppet makes this very hard to do. The Puppet developers have irrational prejudices against iteration based on a misunderstanding about how declarative languages work.

If this kind of resource doesn't work for you, perhaps you could give a better idea of which resource properties you are trying to set from your array?

EDIT:

With Puppet 4, this lamentable flaw was finally fixed. Current state of affairs documented here. As the documentation says, you'll find examples of the above solution in a lot of old code.

Alex Harvey
  • 14,494
  • 5
  • 61
  • 97
itsbruce
  • 4,825
  • 26
  • 35
  • What version of puppet does this example use? – digital Aug 21 '13 at 13:43
  • It should work with any 2.x or 3.x version of puppet. I have put in a comment for clarity, in case you thought the "my_env => []" bit was part of the code, which it is not (just a reference to the original question). – itsbruce Aug 21 '13 at 14:23
  • ahh ok, I misinterpreted the question. I just want to pass an array of parameters to the define so that I can provision various vhosts from an array. – digital Aug 21 '13 at 22:06
  • @itsbruce can you explain why you're using `$name` vs. `$title`? The [docs](http://docs.puppetlabs.com/puppet/latest/reference/lang_defined_types.html#title-and-name) state: "[using $name] is only useful for mimicking the behavior of a resource with a namevar, which is usually unnecessary. If you are wondering whether to use $name or $title, use $title." – Brian Gerstle May 25 '14 at 21:25
  • 2
    @brianG Because of the way the value is used. It is used to create a specifically named file. Titles, in Puppet, are symbolic names which can make dependencies and collectors easier (or more intuitive) to work with. This is a concrete usage and name is more appropriate. Changing the title of a puppet resource will not alter the actual changes made to a system and you should remember this when creating defined types. – itsbruce Aug 14 '14 at 11:40
  • 1
    This is the pre puppet 4.0.0 way of iterating - see Chris Rut's answer below for modern puppet. – Henrik Lindberg May 22 '18 at 12:31
  • @HenrikLindberg True. Time to edit this to add that good news. – itsbruce May 22 '18 at 13:43
22

As of puppet 3.2 this is possible using the "future" parser like so:

$my_env = [ 'shared1', 'shared2', 'shared3', ]
each($my_env) |$value| {
  file { "/var/tmp/$value":
    ensure => directory,
    mode => 0600,
  }
  user { $value:
    ensure -> present,
  }
}

See also: http://docs.puppetlabs.com/puppet/3/reference/lang_experimental_3_2.html#background-the-puppet-future-parser

ChrisRut
  • 221
  • 2
  • 2
  • thanks, I saw that but as it says in the documentation the implementation my change or even could be abandoned in the future. I'll wait for the next stable release before it goes live on production servers. itsbruce answer is still the best for now. – PapelPincel Jun 20 '13 at 08:52
  • This is standard since puppet 4.0.0 along with other iterative functions map, reduce, filter, reverse_each and several others. – Henrik Lindberg May 22 '18 at 12:30
3

Puppet 3.7 released earlier this month have the new DSL, which one feature is the iteration, check the following URL https://docs.puppetlabs.com/puppet/latest/reference/experiments_lambdas.html#enabling-lambdas-and-iteration

these new features can be enabled with the :

Setting parser = future in your puppet.conf file or adding the command line switch --parser=future

hope that helps

Walid
  • 857
  • 11
  • 15
  • if you are using Puppet Enterprise that feature could be not available, however things might change. this is what Puppet instructor told us that week regarding the parser = future difference between OSS and Enterprise – Walid Oct 29 '14 at 16:32
2

As of latest Puppet (6.4.2), and since Puppet 4, iteration over arrays is supported in a few ways:

$my_arr = ['foo', 'bar', 'baz']

Each function:

$my_arr.each |$v| {
  notice($v)
}

Each function alternative syntax:

each($my_arr) |$v| {
  notice($v)
}

To get the index:

Pass a second argument to each:

$my_arr.each |$i, $v| {
  notice("Index: $i, value: $v")
}

Comparison with Ruby:

Note that this grammar is inspired by Ruby but slightly different, and it's useful to show the two side by side to avoid confusion. Ruby would allow:

my_arr.each do |v|
  notice(v)
end

Or:

my_arr.each { |v|
  notice(v)
}

Other iteration functions:

Note that Puppet provides a number of other iteration functions:

  • each - Repeats a block of code a number of times, using a collection of values to provide different parameters each time.

  • slice - Repeats a block of code a number of times, using groups of values from a collection as parameters.

  • filter - Uses a block of code to transform a data structure by removing non-matching elements.

  • map - Uses a block of code to transform every value in a data structure.

  • reduce - Uses a block of code to create a new value, or data structure, by combining values from a provided data structure.

  • with - Evaluates a block of code once, isolating it in its own local scope. It doesn’t iterate, but has a family resemblance to the iteration functions.

Puppet 3 and earlier:

If you have inherited old code still using Puppet 3, the accepted answer is still correct:

define my_type {
  notice($name)
}

my_type { $my_arr: }

Note however that this is usually considered bad style in modern Puppet.

Alex Harvey
  • 14,494
  • 5
  • 61
  • 97
1

itsbruce's answer is probably the best for now, but there is an iteration proposal going through puppetlabs' armatures process for possible implementation in future.

Paul Tobias
  • 1,962
  • 18
  • 18
Philip Potter
  • 8,975
  • 2
  • 37
  • 47
0

There is a "create_resources()" function in puppet. that will be very helpful while iterating over the list of itmes

vinodh
  • 21
  • 3