Using a Chef recipe to append multiple lines to a config file
Asked Answered
M

5

13

I'm trying to create a Chef recipe to append multiple lines (20-30) to a specific config file.

I'm aware the recommended pattern is to change entire config files rather than just appending to a file, but I dislike this approach for multiple reasons.

So far the only solution I found was to use a cookbook_file and then use a bash resource to do:

cat lines_to_append >> /path/configfile

Obviously this wouldn't work properly, as it'd append the file over and over, each time you run chef-client. I'd have to create a small bash script to check for a specific string first, and, if not found, append to the file.

But this seems to defeat the purpose of using Chef. There must be a better way.

One promising solution was the line cookbook from OpsCode Community. It aimed to solve this exact problem. Unfortunately the functionality is incomplete, buggy, and the code is just a quick hack. Far from being a solid solution.

Another option I evaluated was augeas. Seems pretty powerful, but it'd add yet-another layer of abstraction to the system. Overkill, in my case.

Given that this is one of the most obvious tasks for any sysadmin, is there any easy and beautiful solution with Chef that I'm not seeing?


EDIT: here's how I'm solving it so far:

 cookbook_file "/tmp/parms_to_append.conf" do
   source "parms_to_append.conf"
 end

 bash "append_to_config" do
   user "root"
   code <<-EOF
      cat /tmp/parms_to_append.conf >> /etc/config
      rm /tmp/parms_to_append.conf
   EOF
   not_if "grep -q MY_IDENTIFIER /etc/config"
 end

It works, but not sure this is the recommended Chef pattern.

Marvelmarvella answered 2/6, 2013 at 3:22 Comment(0)
D
11

As you said yourself, the recommended Chef pattern is to manage the whole file.

If you're using Chef 11 you could probably make use of partials for what you're trying to achieve.

There's more info here and on this example cookbook.

As long as you have access to the original config template, just append <%= render "original_config.erb" %> to the top of your parms_to_append.conf template.

Duron answered 2/6, 2013 at 23:54 Comment(0)
P
9

As said before, using templates and partials is common way of doing this, but chef allows appending files, and even changing(editing) file lines. Appendind is performed using following functions:

  • insert_line_after_match(regex, newline);
  • insert_line_if_no_match(regex, newline)

You may find and example here on stackoverflow, and the full documentation on rubydoc.info

Please use it with caution, and only when partials and templates are not appropriate.

Pirtle answered 2/12, 2013 at 10:39 Comment(0)
D
5

I did something like this:

monit_overwrites/templates/default/monitrc.erb:

#---FLOWDOCK-START
set mail-format { from: [email protected] }
#---FLOWDOCK-END

In my recipe I did this:

monit_overwrites/recipes/default.rb:

execute "Clean up monitrc from earlier runs" do
  user "root"
  command "sed '/#---FLOWDOCK-START/,/#---FLOWDOCK-END/d' > /etc/monitrc"
end

template "/tmp/monitrc_append.conf" do
  source "monitrc_append.erb"
end

execute "Setup monit to push notifications into flowdock" do
  user "root"
  command "cat /tmp/monitrc_append.conf >> /etc/monitrc"
end

execute "Remove monitrc_append" do
  command "rm /tmp/monitrc_append.conf"
end
Donavon answered 29/5, 2014 at 12:7 Comment(0)
N
1

The easiest way to tackle this would be to create a string and pass it to content. Of course bash blocks work... but I think file resources are elegant.

lines = ""
File.open('input file') do |f|
   f.lines.each do |line|
      lines = lines  + line + "\n"
   end
end
file "file path"  do
   content line
end
Newbill answered 5/9, 2017 at 21:39 Comment(0)
O
1

Here is the example ruby block for inserting 2 new lines after match:

ruby_block "insert_lines" do
  block do
    file = Chef::Util::FileEdit.new("/etc/nginx/nginx.conf")
    file.insert_line_after_match("worker_rlimit_nofile", "load_module 1")
    file.insert_line_after_match("pid", "load_module 2")
    file.write_file
  end
end

insert_line_after_match searches for the regex/string and it will insert the value in after the match.

Oliphant answered 12/10, 2019 at 4:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.