Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have set up a template to set up the content of the /etc/hosts file. Here is my template: localhost.localdomain localhost
<%= scope.lookupvar('ipaddress') %> <%= scope.lookupvar('fqdn') %> <%= scope.lookupvar('hostname') %>

This is correctly working, but I would like, on nodes with more than one network interface, to provide hostname for both IP addresses. I have then tried the following template:

<%= scope.lookupvar('interfaces').each do |interface| %> <%= scope.lookupvar('ipaddress_'+interface) %>

But puppet displays the error on client:

Could not retrieve catalog from remote server: wrong header line format

Of course, I could use what puppet provides to rule hosts file, but something like:

# host entry with multiple aliases
host { 'dashboard':
  ip => [$ipaddress_eth0, $ipaddress_eth1]
  host_aliases => [ 'nagios', 'munin' ],

is not allowed (ip can not be an array apparently, and moreover, I have no way to find out whether the node has 2 interfaces or just one).

Thanks for your help!

I have then created this fact, exported to the destination node. It is supposed to return an array of used IP addresses:

Facter.add('network_interfaces') do

result = []

setcode do
  f ='/etc/network/interfaces', 'r')
     if line =~ /^.*address ((([0-9]{1,3})\.){3}([0-9]{1,3})).*$/i
        result << $1


Here is the output of facter -p network_interfaces

Here is my code to create the hosts line:

# host entry with multiple aliases
host { 'dashboard':
  ip => $network_interfaces
  host_aliases => [ 'nagios', 'munin' ],

But puppet fails with the error:

Parameter ip failed: Invalid IP address ""

Obviously, the ip array returned by the fact is not regarded as an array by puppet but as a regular string.

Is it possible for a fact to return an array instead of string as concatenated elements of the array?

Many thanks!

share|improve this question

You have a syntax error in:

<%= scope.lookupvar('interfaces').each do |interface| %> <%= scope.lookupvar('ipaddress_'+interface) %>
  1. You use <%= when you start iterating: it should be <%
  2. You don't close your block

Rewrite like this instead:

<% scope.lookupvar('interfaces').each do |interface| %>
<%= scope.lookupvar('ipaddress_'+interface) %>
<% end %>

Second, interfaces is a String representing all available interfaces on your machine. You need to convert that String into an Enumerable, in which case the #split method comes in handy:

<% scope.lookupvar('interfaces').split(",").each do |interface| %>
<%= scope.lookupvar('ipaddress_'+interface) %>
<% end %>
share|improve this answer
Oki thanks for your answer; I have not read properly your code, this is changed now, but my trouble is not solved: It seems that scope.lookupvar('ipaddress_'+interface) is always translated as eth0,eth1,lo as if there were no loop! There are 3 iterations (as expected as there are 3 elements in the array) but the first returns 'undefined' and the others ''. If I put only interfaces instead of scope.lookupvar('ipaddress_'+interfaces) i get 'eth0,eth1,lo' then '' for the two following lines. I wonder what i get wrong – philippe Sep 13 '12 at 7:55
up vote 0 down vote accepted

Ok so according to man hosts, for each host a single line should be present.

There should not be more than one IP address for each hosts.

I have done the following: If I can find a production interface on my nodes, I use this one, otherwise, I use the default interface which is for management.

My fact looks like this:

Facter.add('ip_prod') do
require 'facter/util/ip'
confine :interface => "eth0,eth1,lo"
setcode do
    ip = Facter::Util::IP.get_interface_value('eth1', 'ipaddress')

This one is only loaded if there are eth0 and eth1 as physical interfaces.

As hosts template; I use this:

<% if @ip_prod %>
<%= ip_prod %> <%= scope.lookupvar('fqdn') %> <%= scope.lookupvar('hostname') %>
<% else %>
<%= ip_admin %> <%= scope.lookupvar('fqdn') %> <%= scope.lookupvar('hostname') %>
<% end%>

I run into each network interface possible and assign it if the related fact exists, else I use the "default" fact which assign the management IP in this file.

Thanks for your help, hoping it could help someone else :)

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.