0

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: [
Karim Sad
  • 9
  • 1
  • 6

2 Answers2

1

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.

larsks
  • 277,717
  • 41
  • 399
  • 399
0

Using Ansible 2.9.23.

For the string placeholders {} and %s I had to use backticks, otherwise it wouldn't work:

json_query('results[?name==`{}`].version'.format(query))
json_query('results[?name==`%s`].version' % (query))

Given the example json:

{
    (...)
    "results": [
        {
            "envra": "0:ntp-4.2.6p5-29.el7_8.2.x86_64",
            "name": "ntp",
            "repo": "installed",
            "epoch": "0",
            "version": "4.2.6p5",
            "release": "29.el7_8.2",
            "yumstate": "installed",
            "arch": "x86_64"
        },
        (...)
    ],
    (...)
}

created by:

- name: list installed packages
  yum:
    list: installed
  register: installed_list

with a defined variable query: ntp, pass this variable to json_query in two ways:

- name: pass var to json_query - string formatting (1)
  debug:
    msg: "{{ installed_list|json_query('results[?name==`{}`].version'.format(query))|first }}"

- name: pass var to json_query - string formatting (2)
  debug:
    msg: "{{ installed_list|json_query('results[?name==`%s`].version' % (query))|first }}"

Results:

TASK [pass var to json_query - string formatting (1)] *****************************************************************************************************
ok: [host] => {
    "msg": "4.2.6p5"
}

TASK [pass var to json_query - string formatting (2)] *****************************************************************************************************
ok: [host] => {
    "msg": "4.2.6p5"
}
BMC
  • 184
  • 2
  • 9