How can I add multiple entries in /etc/hosts file


#1

With the use of databags, how can I add multiple IP, hostname entries in /etc/hosts file dynamically?

Currently I have created databag and using chefUtil edit to do that (not yet tested though)
But saw many error posts on net with chefUtil edit

Is this a correct way or is there any best practice way which chef recommands?


my current way is

Cretaed a databag (IEM) with data bag item as staging
added ip1, hostname1, fddn1… ipn,hostname n and fqdn n… in databag item

in recipe calling it as
configuration_details = data_bag_item(IEM,staging)

line1=‘configuration_details[ip1] configuration_details[fqdn1] configuration_details[hostname1]‘
file = Chef::Util::FileEdit.new(’/etc/hosts’)
file.insert_line_if_no_match(/#{line1}/, line)
file.write_file

line2=‘configuration_details[ip2] configuration_details[fqdn2] configuration_details[hostname2]‘
file = Chef::Util::FileEdit.new(’/etc/hosts’)
file.insert_line_if_no_match(/#{line2}/, line)
file.write_file


#2

While there’s no “best practice” on how to add entries to a local hosts file, I’d strongly recommend against using FileEdit directly - I’ve found it really hard to debug when the logic goes beyond a single line.

You may wish to examine a couple of cookbooks that have resources:
https://supermarket.chef.io/cookbooks/hosts_file
https://supermarket.chef.io/cookbooks/hostsfile

Using your example data bag with the hosts_file cookbook, you might do something like this:

configuration_details = data_bag_item(IEM,staging)

hosts_file_entry configuration_details[ip1] do
  hostname configuration_details[fqdn1]
  aliases [configuration_details[hostname1]]
  comment "Some relevant comment"
end

Depending on how you structure your data bag item, you could wrap that in some sort of enumerator.


#3

Ok.
Can I do with use of templates and databags them. I dont want to use one more cookbook.


another approch i could think is as follows

my databag :
{
“name”: “data_bag_item_IEM_IEM_serverDetails”,
“json_class”: “Chef::DataBagItem”,
“chef_type”: “data_bag_item”,
“data_bag”: “IEM”,
“raw_data”: {
“id”: “IEM_serverDetails”,
"_default": {
“address”: [
“10.154.39.246:5059”
]
},
“Staging”: {
“ip”: [
“10.155.247.213”,
“10.155.247.218”
]
“fqdn”: [
whc-stag-IEM-relay-1.whc.sl.edst.ibm.com”,
whc-stag-IEM-relay-2.whc.sl.edst.ibm.com
]
“hostname”: [
“whc-stag-IEM-relay-1”,
“whc-stag-IEM-relay-2”
]
},

in recipe -----------

configuration_details = data_bag_item(“IEM”, “IEM_serverDetails”)
IEM_IP = IEM[node.chef_environment][‘ip’]
IEM_fqdn = IEM[node.chef_environment][‘fqdn’]
IEM_hostname = IEM[node.chef_environment][‘hostname’]

template “/etc/hosts” do
source "hostsfile.erb"
owner "root"
group "root"
mode 0644
variables(
:IEM_IP => IEM_IP
:IEM_fqdn => IEM_fqdn,
:IEM_hostname => IEM_hostname
)
end


if this approach is also ok, i m not sure how to iterate the loop for multiple IPs/fqDNs etc in template.
Cna you please guide


#4

To start off with: I highly suggest using a layered cookbook approach. Have a “base” worker cookbook, and a “wrapper” that defines the node attributes appropriately. It will make your life easier if you are working on a project that has a “medium” or larger scope and complexity.

I also, personally, tend to shy away from databags unless the information is sensitive and needs to be encrypted. They are not versioned by default - if you wish to change the format of the databag, everything which uses that databag must be kept in lockstep. Doing it in node attributes in a cookbook means that “schema” changes don’t break nodes running a different version (such as multiple environments).

Now, that being said, however you get your variables, I’m going to suggest another change in the hashes you are using for “ease of loop”:

IEM_serverDetails: { 
    "Staging": {
        "whc-stag-IEM-relay-1.whc.sl.edst.ibm.com": "10.155.257.213",
        "whc-stag-IEM-relay-2.whc.sl.edst.ibm.com": "10.155.257.218"
    }
}

And in your code, instead of the multiple assignments use:

iem_hosts = data_bag_item("IEM", "IEM_serverDetails")

Giving you a hash where iem_hosts[node.chef_environment][hostname] will give you the correct ip for the host. Then your template can do something like this:
(assuming your template resource passes :iem_hosts => iem_hosts[node.chef_environment ):

## This file generated by chef
127.0.0.1 localhost localhost.localdomain
<%=node['ipaddress']%> <%=node['hostname']%> <%=node['fqdn']%>

## IEM hosts
 <% @iem_hosts.each do |cur_host, cur_ip| %>
<%=cur_ip%> <%=cur_host.split('.')[0]%> <%=cur_host%>
<%end%>

This should give the kind of output you are looking for. I also highly suggest reading over the templates documentation: https://docs.chef.io/resources.html#template
It is rather thorough.

Hope this helps,
Jp Robinson


#5

Thanks,

I am going to try this.

Do I need to mention or define anywhere about chef_envirnoment?

  1. If I create a databag with diff env and call node[chef.environment] , how it reads the env ?
  2. I was looking at chef_envrinoment resource In chef docs and saw 4 env, staging, prod, testing and dev. Can I add one more env? if yes how?

#6

Do I need to mention or define anywhere about chef_envirnoment?

  1. If I create a databag with diff env and call node[chef.environment] , how it reads the env ?
  2. I was looking at chef_envrinoment resource In chef docs and saw 4 env, staging, prod, testing and dev. Can I add one more env? if yes how?

I’ll try to answer these as best I can:
0. chef_environment is the environment in chef server your node is assigned into, it is a an “automatic” level attribute.

  1. I’m not clear on what you mean with this question, unless my previous answer covers it.
  2. You can define any number of environments you like. See:
    https://docs.chef.io/environments.html

I hope this answers your questions.

–Jp


#7

This had solved almost my problem but when I ran it , I observed /etc/hosts file is getting replaced with existing one which is not desired.

I missed this imp thing earlier.
Currently I appended it with using simple bash resource echo >> /etc/hosts

But client is forcing to use data bags to achieve this.
Now I am puzzled again how can I use databag for diff env to append /etc/hosts

Your help is highly appreciable here


#8

You should really try to have Chef manage the whole file. When you only partially manage a file, you open yourself to a lot of situations where the file can have different content based on the history of how the edits were applied.

That said, if you have no other option than to edit a file line-by-line, you can use a cookbook like this one to help you do that: https://supermarket.chef.io/cookbooks/line


#9

There is a hostsfile cookbook in the marketplace that does this nicely.
https://supermarket.chef.io/cookbooks/hostsfile/versions/0.1.1

Chris


#10

I did it with node.chef_envirnoment method and its working fine

Thanks for al your support