Using Variables Within Quoted Strings in Ansible – Best Practices

ansiblejinja

Please take this working play example:

- name: Display the URL
  hosts: all
  gather_facts: false
  vars:
    - host_domain: "testing.example.com"
    - default_url: "http://def.localhost.{{ host_domain }}"
    - my_url: "{{ some_undeclared_var | default(default_url) }}"
  tasks:
    - debug:
        msg: "{{ my_url }}"

This works fine. The output is as expected:

msg: http://def.localhost.testing.example.com

I would like to set the default value in-line, without first declaring the default_url var. Something like this:

  vars:
    - host_domain: "testing.example.com"
    - my_url: "{{ some_undeclared_var | default('http://def.localhost.{{ host_domain }}') }}"

I've tried different techniques:

  • my_url: "{{ some_undeclared_var | default(\'http://def.localhost.{{ host_domain }}\') }}"
  • my_url: "{{ some_undeclared_var | default(\"http://def.localhost.{{ host_domain }}\") }}"
  • my_url: "{{ some_undeclared_var | default('http://def.localhost.'{{ host_domain }}) }}"
  • my_url: "{{ some_undeclared_var | default('http://def.localhost.'host_domain) }}"

I can't seem to figure out the syntax for this. Can anyone help?

Best Answer

You never nest {{...}} template markers. Inside a Jinja template context, just use regular Jinja syntax for referring to variables. See the docs for details.

So, instead of:

  vars:
    - host_domain: "testing.example.com"
    - my_url: "{{ some_undeclared_var | default('http://def.localhost.{{ host_domain }}') }}"

You would write:

  vars:
    - host_domain: "testing.example.com"
    - my_url: "{{ some_undeclared_var | default('http://def.localhost.{}'.format(host_domain)) }}"

Here's a runnable example:

- hosts: localhost
  gather_facts: false
  vars:
    - host_domain: "testing.example.com"
    - my_url: "{{ some_undeclared_var | default('http://def.localhost.{}'.format(host_domain)) }}"
  tasks:
    - debug:
        msg: "{{ my_url }}"

This outputs:

TASK [debug] *******************************************************************
ok: [localhost] => {
    "msg": "http://def.localhost.testing.example.com"
}

You could also write default('http://def.localhost.%s' % (host_domain)) (using %-style formatting), or default('http://def.localhost.' ~ host_domain) (using the string concatenation operator).