Escaping double curly braces in Ansible

DockerJinja2Ansible

Docker Problem Overview


How to escape double curly braces in Ansible 1.9.2?

For instance, how can I escape double curly braces in the following shell command?

- name: Test 
  shell: "docker inspect --format '{{ .NetworkSettings.IPAddress }}' instance1"

Docker Solutions


Solution 1 - Docker

Whenever you have problems with conflicting characters in Ansible, a rule of thumb is to output them as a string in a Jinja expression.

So instead of {{ you would use {{ '{{' }}:

- debug: msg="docker inspect --format '{{ '{{' }} .NetworkSettings.IPAddress {{ '}}' }}' instance1"

Topic "Escaping" in the Jinja2 docs.

Solution 2 - Docker

This:

- name: Test 
  shell: "docker inspect --format {% raw %}'{{ .NetworkSettings.IPAddress }}' {% endraw %} instance1"

Should work

Another way to do is using backslashes like \{\{ .NetworkSettings.IPAddress \}\}

Hope it helps

Solution 3 - Docker

Tried on with ansible 2.1.1.0

{%raw%}...{%endraw%} block seems the clear way

- name: list container images and name date on the server
  shell: docker ps --format {%raw%}"{{.Image}} {{.Names}}"{%endraw%}

Only need to escape leading '{{'

tasks:
- name: list container images and names
  shell: docker ps --format "{{'{{'}}.Image}} {{'{{'}}.Names}}"

No harm to escap the tailing '}}', except more difficult to read.

tasks:
- name: list container images and names
  shell: docker ps --format "{{'{{'}}.Image{{'}}'}} {{'{{'}}.Names{{'}}'}}"

Backslash '' seems do not work

Solution 4 - Docker

New in Ansible 2.0 is the ability to declare a value as unsafe with the !unsafe tag.

In your example you could do:

- name: Test 
  shell: !unsafe "docker inspect --format '{{ .NetworkSettings.IPAddress }}' instance1"

See the docs for details.

Solution 5 - Docker

I have a similar issue: i need to post a JSON doc made from a jinja2 template containing some go templates variables (yes, i know :-P), such as

"NAME_TEMPLATE": %{{service_name}}.%{{stack_name}}.%{{environment_name}}

Trying to fence this part of the template between

{% raw %} ... {% endraw %}

didn't work because there is some sort of magic in ansible which will run the template and variable substition twice (i'm not sure about that, but it definitively looks like this)

You end up with "undefined variable service_name" when trying to use the template...

So i ended up using a combination of !unsafe and {% raw %} ... {% endraw %} to define a fact that's later used in the template.

- set_fact:
   __rancher_init_root_domain: "{{ rancher_root_domain }}"
   #!unsafe: try to trick ansible into not doing substitutions in that string, then use %raw% so the value won't substituted another time
   __rancher_init_name_template: !unsafe "{%raw%}%{{service_name}}.%{{stack_name}}.%{{environment_name}}{%endraw%}"

- name: build a template for a project
  set_fact:
    __rancher_init_template_doc: "{{ lookup('template', 'templates/project_template.json.j2') }}"

the template contains this:

    "ROOT_DOMAIN":"{{__rancher_init_root_domain}}",
    "ROUTE53_ZONE_ID":"",
    "NAME_TEMPLATE":"{{__rancher_init_name_template }}",
    "HEALTH_CHECK":"10000",

and the output is ok:

"NAME_TEMPLATE": "%{{service_name}}.%{{stack_name}}.%{{environment_name}}",

Solution 6 - Docker

Here's a shorter alternative to udondan's answer; surround the whole string with double brackets:

shell: "docker inspect --format {{ '{{ .NetworkSettings.IPAddress }}' }} instance1"

Solution 7 - Docker

I managed to work around my issue using a small script:

#!/usr/bin/env bash

docker inspect --format '{{ .NetworkSettings.IPAddress }}' "$1"

And the following Ansible play

- copy:
    src: files/get_docker_ip.sh
    dest: /usr/local/bin/get_docker_ip.sh
    owner: root
    group: root
    mode: 0770

- shell: "/usr/local/bin/get_docker_ip.sh {{ SWIFT_ACCOUNT_HOSTNAME }}"
  register: swift_account_info

Nevertheless, it's very surprising that Ansible doesn't allow escaping double curly braces!

Solution 8 - Docker

The solution by using raw has been already mentioned but the command in the answer before unfortunately didn't work for me.

Without ansible:

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker_instance_name

With ansible:

- name: Get ip of db container
  shell: "{% raw %}docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker_instance_name{% endraw %}"
  register: db_ip_addr
- debug:
  var: db_ip_addr.stdout

Solution 9 - Docker

I was unable to get @Ben's answer to work (shell: !unsafe ...)

What follows here is a complete (and working!) answer to the OP's question, updated for Ansible >2.0

---
# file: play.yml

- hosts: localhost
  connection: local
  gather_facts: no
  vars:
    # regarding !unsafe, please see:
    # https://docs.ansible.com/ansible/latest/user_guide/playbooks_advanced_syntax.html
    #
    - NetworkSettings_IPAddress: !unsafe "{{.NetworkSettings.IPAddress}}"
  tasks:
    - shell: "docker inspect --format '{{NetworkSettings_IPAddress}}' instance1"
      register: out
    - debug: var="{{item}}"                                                                                                   
      with_items:                                                                                                             
        - out.cmd                                                                                                             
        - out.stdout                                                                                                          

outputs: ([WARNINGS] removed)

# ansible-playbook play.yml
PLAY [localhost] ***************************************************************

TASK [shell] *******************************************************************
changed: [localhost]

TASK [debug] *******************************************************************
ok: [localhost] => (item=out.cmd) => {
    "item": "out.cmd", 
    "out.cmd": "docker inspect --format '{{.NetworkSettings.IPAddress}}' instance1"
}
ok: [localhost] => (item=out.stdout) => {
    "item": "out.stdout", 
    "out.stdout": "172.17.0.2"
}

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0   

# ansible --version | head -1
ansible 2.6.1

Solution 10 - Docker

Here is a mostly clean and Ansible native workaround not depending on docker --inspect with curly braces. We assume we have just referenced one container with the Ansible docker module before:

- name: query IP of client container
  shell: "docker exec {{ docker_containers[0].Id }} hostname -I"
  register: _container_query

- name: get IP of query result
  set_fact:
    _container_ip: "{{ _container_query.stdout | regex_replace('\\s','') }}"

You now have the IP of the Docker container in the Variable _container_ip. I also published this workaround on my article The Marriage of Ansible with Docker.

[Update 2015-11-03] Removed whitespaces of the stdout of the container query.

[Update 2015-11-04] BTW, there were two pull requests in the official Ansible repository, that would made this workaround needless by recovering the facts returned by the Docker module. So you could acces the IP of a docker container via docker_containers[0].NetworkSettings.IPAddress. So please vote for those pull requests:

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavide GuerriView Question on Stackoverflow
Solution 1 - DockerudondanView Answer on Stackoverflow
Solution 2 - DockerFilipeView Answer on Stackoverflow
Solution 3 - DockerTiger pengView Answer on Stackoverflow
Solution 4 - DockerJessView Answer on Stackoverflow
Solution 5 - DockerzuzurView Answer on Stackoverflow
Solution 6 - DockerbmaupinView Answer on Stackoverflow
Solution 7 - DockerDavide GuerriView Answer on Stackoverflow
Solution 8 - DockerTobias ErnstView Answer on Stackoverflow
Solution 9 - DockerMarc TamskyView Answer on Stackoverflow
Solution 10 - DockerThomas SteinbachView Answer on Stackoverflow