Using Ansible templates to maintain partial file blocks
Ansible provides some excellent utilities for maintaining single lines and partial blocks of text. Both modules have support for handling template and fact variables, and a variety of options to support your use case. Here are a couple of examples using each module.
Using the lineinfile module for a single line. This module will not support inserting newline \n
characters:
- lineinfile: >
dest=/etc/memcached.conf
regexp='^-m [\d]*'
line='-m {{ memory }}'
state=present
Using the blockinfile module for multiple lines:
- blockinfile:
dest: /etc/hosts
content: |
127.0.0.1 {{ ansible_hostname }}.local
::1 {{ ansible_hostname }}.local
state: present
The blockinfile
module offers several useful options such as:
insertafter
andinsertbefore
to manage exactly where you need the block to be inserted. Useful for structured files like XML.marker
to customize block markers, allowing you to manage multiple blocks in the same file.
In my case, I have a much larger block I'd like to be able to maintain using a separate Jinja2 template file. For this we will need to use the more advanced lookup
plugin, and capture the template content.
- set_fact:
hosts_content: "{{ lookup('template', 'templates/etc-hosts.j2') }}"
- blockinfile:
dest: /etc/hosts
content: '{{ hosts_content }}'
state: present
In this manner, you can keep your tasks configuration file concise by storing large blocks of content more appropriately in a separate file.
A Single Line Shell Solution
In some cases, Ansible might be overkill. If you only need to ensure that a single line exists, and the order within the file does not matter, you can use something like this simple one-liner. This will check if the line exists, and append it to the end of the file if it does not.
Append line to file if it doesn't exist:
LN="127.0.0.1 dev-local"
grep -q -F "${LN}" /etc/hosts || echo "${LN}" | sudo tee -a /etc/hosts