Search code examples
ansiblejmespath

Ansible, how to access variables which were imported from a file?


I have a yml file (cert_expiring.yml) that I'm generating in my playbook and it consists of a dictionary of IDs and server names of servers whose SSL certs are expiring.

Ex: cert_expiring.yml

myDict:
    705:node1.corp.com
    670:node2.corp.com
    1163:node3.corp.com
    715:node4.corp.com

I have a play that is reading in this file and storing it inside a variable called "expired_certs":

- name: Store file contents into variable
      include_vars:
        file: cert_expiring.yml
        name: expired_certs

The contents of "expired_certs" looks like this:

{
    "msg": {
        "changed": true,
        "msg": "All items completed",
        "results": [{
            "ansible_loop_var": "item",
            "backup": "",
            "changed": true,
            "diff": [{
                    "after": "",
                    "after_header": "./cert_expiring.txt (content)",
                    "before": "",
                    "before_header": "./cert_expiring.txt (content)"
                },
                {
                    "after_header": "./cert_expiring.txt (file attributes)",
                    "before_header": "./cert_expiring.txt (file attributes)"
                }
            ],
            "failed": false,
            "invocation": {
                "module_args": {
                    "attributes": null,
                    "backrefs": false,
                    "backup": false,
                    "content": null,
                    "create": true,
                    "delimiter": null,
                    "dest": "./cert_expiring.txt",
                    "directory_mode": null,
                    "firstmatch": false,
                    "follow": false,
                    "force": null,
                    "group": null,
                    "insertafter": null,
                    "insertbefore": null,
                    "line": "    705:node1.corp.com",
                    "mode": null,
                    "owner": null,
                    "path": "./cert_expiring.txt",
                    "regexp": null,
                    "remote_src": null,
                    "selevel": null,
                    "serole": null,
                    "setype": null,
                    "seuser": null,
                    "src": null,
                    "state": "present",
                    "unsafe_writes": null,
                    "validate": null
                }
            },
            "item": {
                "cn": "node1.corp.com",
                "expires": "2020-11-05T15:20:18+00:00",
                "id": 705,
                "serial": "1111"
            },
            "msg": "line added"
        }]
    }
}

I'm trying to follow the same procedure here to reference "cn", "expires", "id", and "serial" from the nested json but not sure why its not working.

This is my play to access those elements:

- name: Print expired_certs variable contents
      debug:
        msg: "{{ expired_certs | json_query('results.item[*].{expires: expires, cn: cn, serial: serial, id: id}') }}"

Output:

ok: [localhost] => {
    "msg": ""
}

Also, tried this:

msg: "{{ expired_certs | json_query('results.[*].{expires: item.expires, cn: item.cn, serial: item.serial, id: itme.id}') }}"

Output:

ok: [localhost] => {
    "msg": {
        "cn": null,
        "expires": null,
        "id": null,
        "serial": null
    }
}

Need help understanding how to access nested elements.


Solution

  • Looking at your JSON, the key results is a list, not a dictionary:

    {
      "results": [{
        "changed": true,
        "...cut": "for brevity"
      }]
    }
    

    In JSON, square brackets indicate array (or list to speak Ansible language)

    And the key item is a dictionary, not a list:

    {
      "item": {
        "cn": "node1.corp.com",
        "expires": "2020-11-05T15:20:18+00:00",
        "id": 705,
        "serial": "1111"
      }
    }
    

    In JSON, curly brackets indicate objects (or dictionary to speak Ansible language)

    So, your wildcard expression is just laying on the wrong key.

    It should be:

    results[*].item
    

    As opposed yo your actual:

    results.item[*]
    

    And also, because the item key does already contains only the information you need, you don't need to go the extra mile and redo an object. You can stay with results[*].item.

    Ending up with:

    - name: Print expired_certs variable contents
      debug:
        msg: "{{ expired_certs | json_query('results[*].item') }}"