How to Get Values from a Nested Ansible Dictionary

The following block of code is used to get a list of files from a directory. It then registers a variable with the contents of any files that were found.

---
- name: Get a list of files
  ansible.builtin.find:
    path: "/home/svc-ansible/Documents"
    patterns: "file*.txt"
  register: home_files

This next block is used to display the contents of the registered variable.

- name: "Print the variable"
  debug: var=home_files

The result of the debug command is below. Notice that the “files” key contains a nested dictionary. This is what I am am after, especially the “path” key in this case.

"home_files": {
        "changed": false,
        "examined": 3,
        "failed": false,
        "files": [
            {
                "atime": 1662746480.558686,
                "ctime": 1662746480.558686,
                "dev": 2052,
                "gid": 100,
                "gr_name": "users",
                "inode": 163856,
                "isblk": false,
                "ischr": false,
                "isdir": false,
                "isfifo": false,
                "isgid": false,
                "islnk": false,
                "isreg": true,
                "issock": false,
                "isuid": false,
                "mode": "0640",
                "mtime": 1662746480.558686,
                "nlink": 1,
                "path": "/home/svc-ansible/Documents/file2.txt",
                "pw_name": "svc-ansible",
                "rgrp": true,
                "roth": false,
                "rusr": true,
                "size": 0,
                "uid": 1002,
                "wgrp": false,
                "woth": false,
                "wusr": true,
                "xgrp": false,
                "xoth": false,
                "xusr": false
            },
            {
                "atime": 1662746525.3352597,
                "ctime": 1662746520.0151916,
                "dev": 2052,
                "gid": 100,
                "gr_name": "users",
                "inode": 163855,
                "isblk": false,
                "ischr": false,
                "isdir": false,
                "isfifo": false,
                "isgid": false,
                "islnk": false,
                "isreg": true,
                "issock": false,
                "isuid": false,
                "mode": "0640",
                "mtime": 1662746520.0151916,
                "nlink": 1,
                "path": "/home/svc-ansible/Documents/file1.txt",
                "pw_name": "svc-ansible",
                "rgrp": true,
                "roth": false,
                "rusr": true,
                "size": 26,
                "uid": 1002,
                "wgrp": false,
                "woth": false,
                "wusr": true,
                "xgrp": false,
                "xoth": false,
                "xusr": false
            },
            {
                "atime": 1662746489.2627974,
                "ctime": 1662746489.2627974,
                "dev": 2052,
                "gid": 100,
                "gr_name": "users",
                "inode": 163860,
                "isblk": false,
                "ischr": false,
                "isdir": false,
                "isfifo": false,
                "isgid": false,
                "islnk": false,
                "isreg": true,
                "issock": false,
                "isuid": false,
                "mode": "0640",
                "mtime": 1662746489.2627974,
                "nlink": 1,
                "path": "/home/svc-ansible/Documents/file3.txt",
                "pw_name": "svc-ansible",
                "rgrp": true,
                "roth": false,
                "rusr": true,
                "size": 0,
                "uid": 1002,
                "wgrp": false,
                "woth": false,
                "wusr": true,
                "xgrp": false,
                "xoth": false,
                "xusr": false
            }
        ],
        "matched": 3,
        "msg": "All paths examined",
        "skipped_paths": {}
    }

Initially, I expected to be able to just access the “path” key by using dot notation but that didn’t quite work out.

- debug: "{{ home_files.files.path }}"

The above resulted in a large fatal error.

TASK [aaronrombaut_photon3_vrops : debug] *******************************************************
fatal: [172.16.174.128]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'list object' has no attribute 'path'\n\nThe error appears to be in '/home/svc-ansible/Documents/ansible/VMware-vRealize-Operations-8.X/VMware-vRealize-Operations-8.X/roles/aaronrombaut_photon3_vrops/tasks/test_accessing_list.yml': line 11, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- debug: \"{{ home_files.files.path }}\"\n  ^ here\nWe could be wrong, but this one looks like it might be an issue with\nmissing quotes. Always quote template expression brackets when they\nstart a value. For instance:\n\n    with_items:\n      - {{ foo }}\n\nShould be written as:\n\n    with_items:\n      - \"{{ foo }}\"\n"}

Yuck, that was nasty and I surely didn’t want to read all that. So I tried various attempts with array indexing. Either way, I received the same error over and over again.

Eventually, with enough research and trial and error, this is how I actually was able to access the nested dictionary. This was very confusing to understand for me at first. The biggest thing for me was where the word “item” came from and what it was referencing. I am assuming that behind the scenes in Python, “item” is the generic term for what is in a foreach loop. (ex. (foreach item in items) { })

- debug: 
    msg: "{{ item.path }}"
  loop: "{{ home_files.files }}"
TASK [aaronrombaut_photon3_vrops : debug] *******************************************************
ok: [172.16.174.128] => (item={'path': '/home/svc-ansible/Documents/file2.txt', 'mode': '0640', 'isdir': False, 'ischr': False, 'isblk': False, 'isreg': True, 'isfifo': False, 'islnk': False, 'issock': False, 'uid': 1002, 'gid': 100, 'size': 0, 'inode': 163856, 'dev': 2052, 'nlink': 1, 'atime': 1662746480.558686, 'mtime': 1662746480.558686, 'ctime': 1662746480.558686, 'gr_name': 'users', 'pw_name': 'svc-ansible', 'wusr': True, 'rusr': True, 'xusr': False, 'wgrp': False, 'rgrp': True, 'xgrp': False, 'woth': False, 'roth': False, 'xoth': False, 'isuid': False, 'isgid': False}) => {
    "msg": "/home/svc-ansible/Documents/file2.txt"
}

So now I can loop through other code and programmatically feed it paths using the looping construct. The code is more dynamic now and as files are added to directories, they will be accounted for in future runs.

Leave a Reply

Your email address will not be published. Required fields are marked *