Yaron Idan
Yaron Idan

Reputation: 6765

Edit files using lineinfile and blockinfile or just copy the entire file using template?

I am starting to use Ansible in order to write a playbook that will deploy a staging environment for our application. I'm trying to understand if the best practice for applying changes to files are to change them locally on the control machine and then propagate them into the remote server, or whether the files should be manipulated inside the playbook.

Manipulating the files through the playbook seems better in terms of readability and documentation, as well as keeping the entire configuration process to one tool for the entire configuration process. On the other hand, changing the files on the local server is easier and faster.

What is the best way to approach these problems?

Thanks, Yaron.

Upvotes: 6

Views: 5965

Answers (4)

Michael Trojanek
Michael Trojanek

Reputation: 1953

As the other answers already told you, the copy and template modules are the preferred way to manipulate configuration files with Ansible.

They allow you to prepare the entire file upfront and then move it to your server (the difference between them is the template module allows you to use variables while the copy module copies the file as it is).

Since you have complete control over the file, there are no surprises.

However, there are (more often than not) circumstances which prohibit the use of these modules:

  • Different roles manipulating the same file
  • Dealing with legacy systems
  • Needing different versions of a file for different servers (to some extent)

In this case, I like to use the lineinfile module in a bulletproof way:

  • First remove all ocurrences of a directive except the one you want to add
  • Then add the line at a specific place

As an example, take the sshd_config file. You may want to make sure that your server listens only to the IP address 1.2.3.4:

- name: Remove lines with unwanted occurrences of ListenAddress
  lineinfile: dest=/etc/ssh/sshd_config
              regexp="^ListenAddress (?!1\.2\.3\.4)"
              state=absent

- name: Listen on 1.2.3.4
  lineinfile: dest=/etc/ssh/sshd_config
              line="ListenAddress 1.2.3.4"
              insertafter="^#?AddressFamily"

The first task removes every occurrence of ListenAddress which does not specify the IP we want (using a regular expression construct called negative lookahead).

The second task then inserts the proper directive (ListenAddress 1.2.3.4) directly after the line that begins with AddressFamily (comment or not).

This way, your tasks stay idempotent and you can be sure that there are no ListenAddress directives in the file you do not know about.

If you need more detail, I wrote an article about this topic. And in case the application you are trying to deploy is written in Rails, you may be interested in Efficient Rails DevOps, a book I wrote about this topic.

Upvotes: 2

Dave Snigier
Dave Snigier

Reputation: 2613

Templates should be your go-to. They're simpler to work with and you know the host will have the accurate configuration once the playbook is run.

I find myself reaching for lineinfile or blockinfile as a fallback when I have a legacy system with many changes to the file on many hosts which I need to retain.

Whenever possible, render a template to a configuration directory on linux. E.g. don't use lineinfile on /etc/sudoers to add admin accounts, render a template with the accounts to /etc/sudoers.d/administrators

Upvotes: 1

helloV
helloV

Reputation: 52423

Use lineinfile and blockinfile (ansible > 2.0). It is cleaner, portable and can be run from any control machine. But there are exception when the block is huge.

Upvotes: 2

flxPeters
flxPeters

Reputation: 1542

Welcome to Ansible!

I think you should have a look at Templates. Never change Files locally and deploy them. Your deployment should not change any file locally!

If you have a config file, write a template for this file and render some variables inside to change the config for the deployed application. The template module will render the file directly to your server.

Upvotes: 6

Related Questions