Ansible Templates


In this video we are going to learn about how Ansible Templates can help us make our configuration files dynamic and re-usable.

The gist of template files is to take what would normally be a static / concrete file, then replace all the hardcoded bits that make it difficult to share, and then pass in the required values as variables to enable us to declare the file once, but re-use it many times.

As an example, an Apache Virtual Host file follows a very repeatable format.

If we create a new Apache Virtual Host on a development server, the chances are that file is going to look 99.9% similar to every other time we built a development server for a project.

The only thing that tends to change is the name of the domain we are developing under. And worst, that file usually contains the same text in three, four, five or more places, repeated over and over. Site root, site name, log file, error file...

We can do better.

Adding a Little Jinja

If you have used a modern web framework - Symfony2, Django, Rails, etc - you will more than likely have used a templating language. And if you haven't, well, the good news is that the templating language is by far the easiest part of any framework to learn (in my opinion), so there is nothing to worry about.

Ansible Templates use the excellent Jinja templating library. As such, all our Ansible Templates must have the .j2 file extension.

At its most basic, our Jinja template files allow us to turn something like this:

# templates/our-template-name.j2
server {
    root /var/www/{{ domain }}/web;
}

into:

# /etc/nginx/sites-enabled/our-passed-in-variable.dev
server {
    root /var/www/our-passed-in-variable.dev/web;
}

Of course, this assumes you are using the standard Role directory structure.

Hold On To The Handlebars

Ansible Templates make use of Handlebar-style / double curly braces that are finding their way into common usage amongst many modern templating libraries.

It's a simple way of denoting which parts of the template are variables, and which bits are standard text.

I'm not going to cover everything about the way Jinja templates work because that's been covered better than I could hope to in the official template designer documentation.

What I do want to cover is the one gotcha, which I often forget, but which may throw up an error.

It is good practice to put quotation marks around your variable declarations when working in YAML files. An example of this would be:

- name: Enable Site Config
  file: src="/etc/nginx/sites-available/{{ fqdn }}.conf" dest="/etc/nginx/sites-enabled/{{ fqdn }}.conf" state=link

Note, the "" marks around the src and dest.

However, you don't put speech marks around variables used inside templates by default.

An Easy Ride

There are a couple of further things we need to ensure are in place before this will work. Both are super easy.

Firstly, we need to make sure that any variables we are using in an Ansible Template are actually defined.

Kinda obvious. And thankfully, the error message that's thrown for us to see is pretty self explanitory also.

Secondly, we need to get the template syntax right in our Task. An example of this would be:

# tasks/main.yml
- name: Add nginx.conf
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf owner=root group=root

When we run our playbook, behind the scenes, Ansible and Jinja will combine forces to populate our template file with all the expected variables, then this newly created file will be copied up to our deployment target as a static file with whatever file path we specified in the template's dest parameter.

Congratulations, you now know everything you need to know to get started using Ansible Templates.

Doing More With Templates

Of course, what I've explained above is the basics.

And as I said at the start there, Jinja is a fully functional template engine which gives us access to all the power and features on offer.

We can apply filters to our variables to do fancy things like replacing dots with underscores, or ensuring a variable is in lower or upper case.

We can use loops and tests, checking for truthy / falsy, and a lot more besides.

However, I would advise against going too far with these features. Keeping your playbooks, roles, templates, and tasks as simple as possible is generally best for all. Not just for you when you come back to make the inevitable changes in six months time, but for any junior or inexperienced devs who have to follow these files when things go wrong.

Code For This Course

Get the code for this course.

Episodes