hobbes
hobbes

Reputation: 467

Chef: How to gather local network.interface attribute with state key equal to up?

I'm interested in gathering the key value for any network_interfaces_*_state:up attribute's running on the host with the chef-client being run on. So any network interface with a state 'up' attribute.

I have a template containing a configuration file, in which I need to gather the active network devices, using the above chef attribute. I've tried writing a few things within the default recipe file, such as:

template '/etc/foo.conf' do
    ....
    variables ({
        netdev: search(node, 'network_interfaces_*_state:up').each {r |r| puts "#{r['network']['interfaces'].select { |i,j| j['state'] == 'up' }.keys } " }
    })
end

So there are two things that are obviously wrong.

  1. Running this as knife exec -E "......" returns the interface name for state:up on all nodes. I only want it from the current node that the chef-client is being run on.
  2. chef-client is returning an undefined method 'search' for Chef::Resource::Template, tracing back to the 'netdev' variable as posted above.

I'm unfamiliar with Ruby and using Chef at this level, and was really hoping that I could get help with understanding two things. How do I pull a attribute value from a local host, and how the heck can I write this into a recipe/cookbook?

Upvotes: 0

Views: 1130

Answers (1)

Tensibai
Tensibai

Reputation: 15784

So what you need is the first 'up' interface, assuming the loopback interface should be avoided, this should do:

template '/etc/foo.conf' do
    ....
    variables ({
        netdev: node['network']['interfaces'].select { |i,j| j['state'] == 'up' && i != 'lo' }.keys[0]
    })
end

The main idea is to filter the interfaces hash on the interface state and name, keep the keys and take the first one of the resulting array.


Previous answer kept for information.

Attributes are indexed and flattened so you may search for just state:up but may find other attributes named state.

Using the flattened version you could do:

knife node search 'network_interface_*_state:up' -a network.interfaces

This is derived from the examples of nested fields in the documentation linked above.

In case you wish to get each interface up for each node you can play with the search and a little of ruby with knife exec like this :

 knife exec -E "nodes.search('network_interfaces_*_state:up').each { |n| puts \"#{n} #{n['network']['interfaces'].select { |i,j| j['state'] == 'up' }.keys } \" }"
node[xxxxxxx] ["eth1", "eth2", "eth3", "usb0"]
node[yyyyyyy] ["docker0"]
node[zzzzzzz] ["eth1", "eth2", "eth3", "usb0"]

The idea is to search for nodes with up interfaces and for each filtering the interfaces whose property (j in select block as they are a hash within a hash) state is up and then keep only the keys of the resulting filtered hash which are the interfaces with state up. (side note my examples above were done with state:down to limit the results)

Upvotes: 2

Related Questions