Search code examples
parsingansiblejson-query

Getting template error while templating string when trying to work with json and json_query filter


I try to execute this ansible command :

 ansible localhost -m debug -a "var={{ db_config| to_json |json_query(*)}}" \
       -e 'db_config=[{"name":"mydb1","services":["app1","app2"]},{"name":"mydb12","services":["app1"]}]'

To get all json elements using json_query(*) but I'm getting the following error :

 fatal: [localhost]: FAILED! =>
  msg: 'template error while templating string: expected token ''end of print statement'', got ''name''. String: {{"[{\\"name\\":\\"mydb1\\",\\"services\\":[\\"app1\\",\\"app2\\"]},{\\"name\\":\\"mydb12\\",\\"services\\":[\\"app1\\"]}]"}}'

Solution

  • There are several issues in this single one liner:

    1. The parameter to use for debug in your case is msg (to output the result of a template or static value) and not var (used to debug a single var without any transformation). See the debug module documentation
    2. You are passing as a parameter a json string representation. The filter you want to use is from_json (to transform your string to a dict/list) and not to_json (which does the exact opposite).
    3. Your jmespath expression in json_query is invalid for two reason:
      • It's not a string (just a bare wildcard caracter)
      • Even quoted it would not respect the specification (follow the above link).

    The following fixed one liner gives the result (I believe...) you expect:

    $ ansible localhost -m debug -a 'msg={{ db_config | from_json | json_query("[]") }}' \
    -e 'db_config=[{"name":"mydb1","services":["app1","app2"]},{"name":"mydb12","services":["app1"]}]'
    localhost | SUCCESS => {
        "msg": [
            {
                "name": "mydb1",
                "services": [
                    "app1",
                    "app2"
                ]
            },
            {
                "name": "mydb12",
                "services": [
                    "app1"
                ]
            }
        ]
    }
    

    Note that you can even drop the json decoding step by passing your arguement as a full inlined json:

    $ ansible localhost -m debug -a 'msg={{ db_config | json_query("[]") }}' \
    -e '{"db_config":[{"name":"mydb1","services":["app1","app2"]},{"name":"mydb12","services":["app1"]}]}'
    localhost | SUCCESS => {
        "msg": [
            {
                "name": "mydb1",
                "services": [
                    "app1",
                    "app2"
                ]
            },
            {
                "name": "mydb12",
                "services": [
                    "app1"
                ]
            }
        ]
    }
    

    I suspect you are trying all this to later test json_query expressions to select your data.

    • You should be aware there a lot of other core filters in ansible (among which selectattr, rejectattr, select, reject, map, dict2items, items2dict, first, last, unique, zip, subelements,...) that combined together can do most of the job json_query can do without its overhead (installing a python module and an ansible collection). json_query is only really needed for very complex queries.
    • In case I am wrong and your final goal is really to display all elements of your input data, you can overly simplify. From the two examples above:
    $ ansible localhost -m debug -a 'msg={{ db_config | from_json }}' \
    -e 'db_config=[{"name":"mydb1","services":["app1","app2"]},{"name":"mydb12","services":["app1"]}]'
    
    # OR (the next one can work with `var` for debug)
    
    $ ansible localhost -m debug -a 'var=db_config' \
    -e '{"db_config":[{"name":"mydb1","services":["app1","app2"]},{"name":"mydb12","services":["app1"]}]}'