Working with go-templates in Ansible

!unsafe

George Shuklin
OpsOps
2 min readFeb 28, 2020

--

There was an endless pain on templatization of yaml files containing go-inspired string interpolation. The most known culprits are Prometheus and Kapacitor. The Prometheus is the most outstanding because it has yaml as format for configuration files.

Yaml means you need to write it as yaml, not as template. (Best practice it is).

Unfortunately, alerts in Prometheus are full of {{ mustaches }}.

{{ service_name }} failed on {{ $labels.controller }}

service_name here is Ansible variable and $labels.controller is Prometheus.

For a long time I hated to touch this subject. I even don’t want to recount all attempts to solve this.

Until today. I found the way to do it right.

The goal

The goal is to write a yaml file with some values containing literal {{ mustaches }} whose Ansible need to avoid (no interpolation).

The solution

Ansbile have two types of strings: normal (they receive recursive jinja templatization and type probing) and unsafe. Ansible leave them ‘as is’.

That’s all. Mark ‘do no touch’ strings as unsafe and that’s all.

Example

---
- hosts: localhost
gather_facts: false
tasks:
- copy:
content: '{{ foo | to_nice_yaml }}'
dest: /tmp/foo.yaml
vars:
foo:
info: !unsafe 'try to use {{ inventory_hostname }}'

It generates file /tmp/foo.yaml which contains

info: try to use {{ inventory_hostname }}

Combining safe and unsafe

It’s easy

---
- hosts: localhost
gather_facts: false
tasks:
- copy:
content: '{{ foo | to_nice_yaml }}'
dest: /tmp/foo.yaml
vars:
foo:
info: '{{ bar }} == {{ inventory_hostname }}'
vars:
bar: !unsafe '{{ inventory_hostname }}'

Result:

info: '{{ inventory_hostname }} == localhost'

There is a little notice about !unsafe in the documentation and I absolutely happy I found it. It’s a huge relief and a great enhancement of my tooling.

--

--

George Shuklin
OpsOps

I work at Servers.com, most of my stories are about Ansible, Ceph, Python, Openstack and Linux. My hobby is Rust.