puppet content of /etc/hosts template with facter

5,113

Solution 1

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')
    ip
end
end

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 :)

Solution 2

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:
5,113

Related videos on Youtube

philippe
Author by

philippe

Something about Myself

Updated on September 18, 2022

Comments

  • philippe
    philippe over 1 year

    I have set up a template to set up the content of the /etc/hosts file. Here is my template:

    127.0.0.1 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 = File.open('/etc/network/interfaces', 'r')
      f.each_line{|line|
         if line =~ /^.*address ((([0-9]{1,3})\.){3}([0-9]{1,3})).*$/i
            result << $1
         end 
      }   
    result
    end 
    
    end
    

    Here is the output of facter -p network_interfaces

    192.168.10.10
    172.23.10.10
    

    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 "192.168.10.10172.23.10.10"
    

    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!

  • Dave M
    Dave M about 2 years
    This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From Review