Ansible Automation on Ubuntu 22.04 – Templates

I did a couple of previous posts on Ansible, one for getting it installed and setting up inventory, and another one on how to write a simple playbook. In the spirit of keeping things simple, I thought I’d write up a very basic example on how to use a template in Ansible to write a text file.

There are many situations where we want to write text files, whether they’re for configuration (Cisco config files, etc), code, HTML, security rules, JSON documents, XML documents, the list goes on. All of these files are text files, and we can write them using Ansible templates. Today let’s just write a “.txt” file with a playbook.

Topology

Network Topology

We have a simple subnet of 10.0.0.0/24 created in GNS3, with Ansible installed on the controller at 10.0.0.1. There are two managed nodes, one at 10.0.0.2 and 10.0.0.3. This time I’m using SSH key authentication, and I already copied the public key from the controller to the managed nodes.

Ansible installation

In my first post on ansible I installed from Ansible’s PPA repository, but you can also install from python’s pip package manager. You don’t have to know any python to do it. You can install ansible like this:

python -m pip install --user ansible

The command might vary depending on whether python points to python 2 or 3 on your OS, so might need to type python3 instead of python. Also, you will likely need to add the path ~/.local/bin to your bash $PATH variable in order to be able to access the ansible binary that pip installed, using only their names. I added this little tidbit to the bottom of my ~/.bashrc file, logged out and in again to get it to work:

export PATH=~/.local/bin:$PATH

This modifies the $PATH variable to include the directory where ansible is installed for my current user. Bash should now be able to find the ansible commands just by typing their names. There are many ways to modify the $PATH variable, this is just one that worked for this lab.

Inventory setup

I’m working out of my user’s home folder, but you can set up your inventory and playbooks in whatever directory you like. We’ll create a hosts file in YAML format that contains the managed node IP addresses. My file looks like this:

servers:
  hosts:
    ubuntu1:
      ansible_host: 10.0.0.2
      ansible_user: james
    ubuntu2:
      ansible_host: 10.0.0.3
      ansible_user: james
  vars:
    ansible_python_interpreter: /usr/bin/python3
    something_interesting: Happy Halloween 2022!

This file defines two hosts, ubuntu1 and ubuntu2 with their ansible_host variables set to their respective IP addresses from the topology. There are many variables that exist in ansible that are defined already, some that are optionally gathered when you connect to a managed node or run a task, and some that you can define in the inventory, playbook or CLI. I’ve defined a custom variable under the vars section of the servers group called something_interesting. The variable’s value is “Happy Halloween 2022!”. We’ll use it later in our template.

Create a template

In whatever directory your hosts file exists, create a templates directory. Inside templates, we’ll create a file called test.txt.j2. The j2 extension refers to Jinja, the templating engine that ansible uses. All we really need to know for this exercise about Jinja is that it means we can put variables into the templates using the syntax {{ some_variable }}, which will insert into the text whatever value that variable holds. I’ve created test.txt.j2 and its contents look like this:

This is an ansible template! Any text can go in this file.
You can insert variables too! Like this:

The ansible user is: {{ ansible_user }}
The IP of this server is: {{ ansible_host }}

But they don't have to be ansible-provided variables! It can be anything:

Awesome message: {{ something_interesting }}

Have fun with Ansible templates!

I’m using {{ ansible_user }}, which should be “james”, {{ ansible_host }} which should be the IP address of whatever server ansible is connecting to, as well as {{ something_interesting }} which should evaluate to “Happy Halloween 2022!”.

Create a playbook

We’ll now create a very simple playbook to write a text file based on the template we just created on the managed nodes. I’ve created a playbook called my_playbook.yml that looks like this:

- hosts: all
  gather_facts: false
  tasks:
    - name: Write a text file from our base template!
      template:
        src: ./templates/test.txt.j2
        dest: ~/my_cool_template.txt

It only has one task, which takes a source template file name and destination text file name. The src is the path and name of the template file, and the dest is the path and name of the text file to be written on the managed node. This play should write the text files to the home directories on the managed nodes.

Run the playbook

Let’s run our playbook. The following command should do it:

ansible-playbook -i hosts my_playbook.yml
-----

PLAY [all] *********************************************************************

TASK [Write a text file from our base template!] *******************************
changed: [ubuntu2]
changed: [ubuntu1]

PLAY RECAP *********************************************************************
ubuntu1                    : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
ubuntu2                    : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

Looks like it worked, but let’s verify that the text file was written and that it has the content we expected.

Verify

Logging into ubuntu1, I’ll confirm the file:

ls
----
my_cool_template.txt

And check its contents:

cat my_cool_template.txt 
----

This is an ansible template! Any text can go in this file.
You can insert variables too! Like this:

The ansible user is: james
The IP of this server is: 10.0.0.2

But they don't have to be ansible-provided variables! It can be anything:

Awesome message: Happy Halloween 2022!

Have fun with Ansible templates!

Looking good! The variables have been changed into their values by Jinja.

Just to be sure, let’s check ubuntu2 to make sure it looks the way we expect. After logging in, we’ll confirm the file exists:

ls
----
my_cool_template.txt

And confirm its contents:

cat my_cool_template.txt
----

This is an ansible template! Any text can go in this file.
You can insert variables too! Like this:

The ansible user is: james
The IP of this server is: 10.0.0.3

But they don't have to be ansible-provided variables! It can be anything:

Awesome message: Happy Halloween 2022!

Have fun with Ansible templates!

We can see that the ansible_host variable was different this time, which is the power of templating. You can use the same template and get different results. Even with this super simple example, hopefully you can see how you could use this to automate writing complex text files.

Happy automating!