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
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!