David Portabella
David Portabella

Reputation: 12710

puppet convert an array to a hash based on key

I have an array as follows:

  $servers = [
     {name => 'server1', address => '10.10.10.11', port => 8081}, 
     {name => 'server2', address => '10.10.10.12', port => 8082}, 
  ]

and I need to programmatically convert it into a hash based on the 'name' key:

  $serversMap = {
    server1 => {address => '10.10.10.11', port => 8081},
    server2 => {address => '10.10.10.12', port => 8082},
  }

this works in puppet 3:

  $serversMap = $servers.reduce({}) |$cumulate, $server| { 
    $key = "${server['name']}"
    $value = $server.filter |$entry| { $entry[0] != 'name' }
    $tmp = merge($cumulate, {"$key" => $value }) 
    $tmp
   }

however, is there an easier way?

and why I need to create the temporal variable $tmp? without that, I get at Error: Function 'merge' must be the value of a statement error.

ps: it's obvious but I will say it anyway: the $servers variable is given to me, I cannot change its structure. and I need that same data but in the form of $serversMap. and so, I am asking how to programmatically convert from $servers to $serversMap.

Upvotes: 4

Views: 9556

Answers (1)

Lodewijk Bogaards
Lodewijk Bogaards

Reputation: 19987

Except for the $tmp variable this code is optimal.

The $tmp variable needs to be there, because the merge function is an rvalue. From the docs:

There are actually two completely different types of functions available — rvalues (which return a value) and statements (which do not). If you are writing an rvalue function, you must pass :type => :rvalue when creating the function; see the examples below.

The puppet source that produces this error is pretty self explanatory when it comes to rvalue statements:

    # It is harmless to produce an ignored rvalue, the alternative is to mark functions
    # as appropriate for both rvalue and statements
    # Keeping the old behavior when a pblock is not present. This since it is not known
    # if the lambda contains a statement or not (at least not without a costly search).
    # The purpose of the check is to protect a user for producing a meaningless rvalue where the
    # operation has no side effects.
    #
    if !pblock && Puppet::Parser::Functions.rvalue?(@name)
      raise Puppet::ParseError,
        "Function '#{@name}' must be the value of a statement"
    end

The real reason is that Puppet is just not that sophisticated as a language. If you want real power switch to Ruby.

Upvotes: 4

Related Questions