Image: Pexels - Evgeny Tchebotarev

Writing config files

ansible Apr 2, 2023

That's an amazingly boring title for something that simply could be seen as magic. Sometimes with Ansible you'd really want to write out files without actually defining the contents. Vague ? :) Yeah i'd guess.

As an example for a configuration file lets assume that using Ansible combined with a Jinja template you would have something like this:

# Jinja template
set_default = {{ template_set_default }}
change_color = {{ some_variable }}

All the above variables would have to be set ( when not using defined and other logic ), but what if you have multiple files with different content.

Well, that was the challenge for today :)

Writing the role

Since i havent reached my caffeine high yet, lets create a role named arwain simply an acronymn for 'Ansible Role Without An Interesting Name'.

ansible-galaxy init --offline roles/adhoc/arwain


I'll be testing/working on seenine . Lets define some variables to work with. Preferably in inventory/host_vars/seenine

    INI_main: true
    entry1: 'yes'
    using_color: 'no'
    text: 'no'
    hold_camera: 'maybe'


In this particular example looking at the variables i'd like to see files written to (and i'll append /tmp/ to it) /tmp/testing/myfile1.txt and myfile2.txt , Will test if a variable starts with INI to encapsulate it with '[]'. And use the rest as file contents. Obviously when all this works we can write any type of file or add more magic.


# tasks file for roles/adhoc/arwain

- name: Create list of keys as dir/filenames
    l_filenames: "{{ arwain_variables.keys() | list }}"

- name: Include tasks for writing multiple templates
  include_tasks: write_template.yml
  with_items: "{{ l_filenames }}"
    loop_var: d_filename


- name: Create fact with variables per file
    my_items: "{{ arwain_variables[d_filename] }}"

- name: Create directory
    path: "/tmp/{{ d_filename.split('_')[0] }}"
    owner: "{{ ansible_user }}"
    group: "{{ ansible_user }}"
    mode: 0750
    state: directory

- name: Write template
    src: templates/write_template.j2
    dest: "/tmp/{{ d_filename|replace('_','/') }}"
    owner: "{{ ansible_user }}"
    group: "{{ ansible_user }}"
    mode: 0644


And for the template file roles/adhoc/arwain/templates/write_template.j2

{{ ansible_managed | comment }}
{% for entry in my_items %}
{% if entry.startswith('INI') %}
[{{ entry.split('_')[1] }}]
{% else %}
{{ entry }} = {{ my_items[entry] }}
{% endif %}
{% endfor %}


Change the roles/adhoc/arwain/tests/tests.yml file to match your test environment.

- hosts: 'seenine*'
  remote_user: ansible
  become: no
  gather_facts: no
    - roles/adhoc/arwain

Lets put it to the test

ansible-playbook roles/adhoc/arwain/tests/test.yml

That seems to work, lets check the contents of a file:

cat /tmp/testing/myfile1.txt

# - This file is managed by Ansible.
entry1 = yes
using_color = no

And file 2:

# - This file is managed by Ansible.
text = no
hold_camera = maybe

And thats it :)


Riccardo B.

Riccardo is an all round Linux Systems Engineer with over 20 years of experience and a knack for Automation. Favoring acronyms like NAO, IaC, SRE and more. Also hardly ever writes in third person :)