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.