puppet content of /etc/hosts template with facter
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) %>
- You use
<%=
when you start iterating: it should be<%
- 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 %>
Related videos on Youtube
Comments
-
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 about 2 yearsThis 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