Ruby: Looping and calling associative arrays (TypeError no implicit conversion of String into Integer)

265 Views Asked by At

So I have this piece of code:

node['nginx'][0]['server_name']='black.domain.com'
node['nginx'][0]['app_server']='http://10.50.0.163:8090'
node['nginx'][0]['redirect_path']='/mesh'

node['nginx'][1]['server_name']='red.domain.com'
node['nginx'][1]['app_server']='http://10.50.0.163:8090'
node['nginx'][1]['redirect_path']='/mesh'

node.default['nginx'].each do |key, value|
    value.each do |prop|
            Chef::Log.info prop['app_server']       
    end
end

Like the title says it's erorring out on:

 21>>       Chef::Log.info prop['app_server']

My question is how do I loop though this associative array?

Best, -Iulian

3

There are 3 best solutions below

4
On BEST ANSWER

you can loop through node['nginx'] like this. (i don't know what node.default['nginx'] is supposed to be)

node['nginx'].each do |num, hash|
  #on the first iteration: 
  #  num = 0
  #  hash = {'server_name' => 'black.domain.com', 'app_server' => 'http://10.50.0.163:8090', 'redirect_path' => '/mesh'}
  #on the second iteration
  #  num = 1
  #  hash = {'server_name' => 'red.domain.com', 'app_server' => 'http://10.50.0.163:8090', 'redirect_path' => '/mesh'}
  #now you can do what you want with the data eg
  Chef::Log.info hash['app_server'] 
end
1
On

Your loop should look like this:

node.default['nginx'].each do |node_properties|
  Chef::Log.info node_properties['app_server']
end
0
On

While the code is perfectly fine, let me suggest you another way of structuring your attributes: Use a hash instead of an array:

node['nginx']['black_1']['server_name'] = 'black1.domain.com'
node['nginx']['black_1']['app_server'] = 'http://10.50.0.163:8090'
node['nginx']['black_1']['redirect_path'] = '/mesh'

node['nginx']['black_2']['server_name'] = 'black2.domain.com'
node['nginx']['black_2']['app_server'] = 'http://10.50.0.163:8090'
node['nginx']['black_2']['redirect_path'] = '/mesh'

You can loop through it using:

node['nginx'].each do |site_name, node_properties|
  Chef::Log.info node_properties['app_server']
end

Reason:

It's very hard to delete/manipulate arrays elements in chef attributes, e.g. using node attributes or within a wrapper cookbook. Let's say you need to change the ip address or port of some site, e.g. in a wrapper cookbook to deploy the setup for some "stage"/"testing" environment. You'll need to know the position of the record within the array or you'll have to loop to the whole array and lookup e.g. server_name to match the right entry.

Details:

  1. "Prefer Hashes of Attributes to Arrays of Attributes"
  2. "Arrays and Chef"