How can I make Ansible interpret a variable inside a variable?

As advised in the Frequently Asked Questions of Ansible, moustache do not stack.

Another rule is ‘moustaches don’t stack’. We often see this:

{{ somevar_{{other_var}} }}

The above DOES NOT WORK as you expect, if you need to use a dynamic variable use the following as appropriate:

{{ hostvars[inventory_hostname]['somevar_' ~ other_var] }}

For ‘non host vars’ you can use the vars lookup plugin:

{{ lookup('vars', 'somevar_' ~ other_var) }}

Source: https://docs.ansible.com/ansible/latest/reference_appendices/faq.html#when-should-i-use-also-how-to-interpolate-variables-or-dynamic-variable-names


So, there are two cases where this will apply:

  1. When trying to access a key of a dictionary from a variable, you would simply use the variable as is, remembering that, when you are inside the expression delimiters {{ ... }}, a string will be interpreted as a variable, if not enclosed inside simple or double quotes.

    - ansible.builtin.debug:
        msg: "{{ foo[key] }}"
      vars:
        key: bar
        foo:
          bar: baz
    
  2. When trying to construct the name of the variable or the key of a dictionary from a variable, you will have to use the concatenation operator, ~:

    - ansible.builtin.debug:
        msg: "{{ foo['foo_' ~ key] }}"
      vars:
        key: bar
        foo:
          foo_bar: baz
    

    You might also need to use the vars lookup to access a dynamic variable:

    - ansible.builtin.debug:
        msg: "{{ lookup('vars', 'foo_' ~ key) }}"
      vars:
        key: bar
        foo_bar: baz
    

Side notes:

  • Do use the vars lookup — lookup('vars', 'somevar_' ~ other_var) — and not the vars dictionary — vars['somevar_' ~ other_var], as it was never intended to be an Ansible feature and will be removed in future version

    Short history, vars is a leftover from previous code that used it to pass variables to template, it was never intended for external use and most of the time didn’t template anything.

    Unrelated changes allowed it to template ‘sometimes’ but this was never on purpose, the only reason it was not removed is because some people relied on it, that had discovered by looking at the code and/or other people that had already been using it. Even though it has been our intention for a long time to deprecate and remove the vars construct, lack of a good way to trigger a runtime message has kept us from doing so.

    We created 2 alternatives via lookups varnames and vars, which might not be as flexible as a dict but also would not chew up memory for unneeded access, since most users just want to match a small subset of existing variables.

    Source: https://github.com/ansible/ansible/issues/74904#issuecomment-854137949

  • It is more advisable to use the right concatenation operator, ~ than the math operator + as advised in the Ansible documentation for the reason raised in Jinja documentation:

    Usually the objects are numbers, but if both are strings or lists, you can concatenate them this way. This, however, is not the preferred way to concatenate strings! For string concatenation, have a look-see at the ~ operator.

    Source: https://jinja.palletsprojects.com/en/2.11.x/templates/#math

Leave a Comment