Search code examples
ansiblejinja2ansible-templatejson-query

How to pass jinja2 variable to json_query


I have the following jinja2 template

[
{% for items in hosts %}
{
    "name":"{{ items.name }}",
    "display_name":"{{ items.display_name }}",
    "services": {{ host_group | from_json | json_query('[*].services[0]') | to_json }},
}
{% endfor %}
]

i need to replace services[0] by a variable {{ loop.index0 }}, i tried this syntax

"services": {{ host_group | from_json | json_query('[*].services[loop.index0]') | to_json }}

but i'm getting an error :

AnsibleFilterError: JMESPathError in json_query filter plugin:
    Expecting: star, got: unquoted_identifier: Parse error at column 13, token "loop" (UNQUOTED_IDENTIFIER), for expression:
    "[*].services[loop.index0]"

I tried another syntax:

"services": {{ host_group | from_json | json_query('[*].services[' + {{ loop.index0 }} +']') | to_json }},

and it gives also an error :

AnsibleError: template error while templating string: expected token ':', got '}'. String: [

Solution

  • There are two things to keep in mind when working with Jinja:

    1. You never nest the {{...}} template markers.
    2. If you put something in quotes, it's a literal string.

    So when you write:

    json_query('[*].services[loop.index0]')
    

    You are passing json_query the literal string [*].services[loop.index0], which isn't a valid JMESPath query. If you want to substitute the value of a variable in a string, you need to either build the string via concatenation, or use string formatting logic.

    Concatenation

    Using concatenation might look like:

    json_query('[*].services[' ~ loop.index0 ` ']')
    

    Here, ~ is the string concatenation operator -- it's like +, but it makes sure to convert everything into a string. Compare this:

    ansible localhost -m debug -a 'msg={{ "there are " + 4 + " lights" }}'
    

    To this:

    ansible localhost -m debug -a 'msg={{ "there are " ~ 4 ~ " lights" }}'
    

    String formatting

    Using string formatting might look like:

    json_query('[*].services[%s]' % (loop.index0))
    

    Or:

    json_query('[*].services[{}]'.format(loop.index0))
    

    These are two forms of string formatting available in Python; for more details, start here.