Home > front end >  How to recursively search a list of dictionaries of lists containing an element of interest using An
How to recursively search a list of dictionaries of lists containing an element of interest using An

Time:11-26

I have an Ansible playbook(version 2.9), which initially displays the available block devices using lsblk command. The playbook is

- hosts: localhost
  tasks:
  - name: define variable
    shell: lsblk -oMOUNTPOINT,NAME  --json
    register: lsblk_output
  - debug:
      msg: "{{ lsblk_output.stdout }}"

The output of the lsblk command with JSON format, lsblk -oMOUNTPOINT,NAME --json is

ok: [localhost] => {
    "msg": {
        "blockdevices": [
            {
                "mountpoint": "/snap/core18/2246",
                "name": "loop0"
            },
            {
                "mountpoint": "/snap/core18/2253",
                "name": "loop1"
            },
            {
                "mountpoint": "/snap/core20/1169",
                "name": "loop2"
            },
            {
                "mountpoint": "/snap/lxd/21803",
                "name": "loop3"
            },
            {
                "mountpoint": "/snap/core20/1242",
                "name": "loop4"
            },
            {
                "mountpoint": "/snap/lxd/21835",
                "name": "loop5"
            },
            {
                "mountpoint": "/snap/snapd/14066",
                "name": "loop6"
            },
            {
                "mountpoint": "/snap/snapd/13640",
                "name": "loop7"
            },
            {
                "children": [
                    {
                        "mountpoint": "/boot/efi",
                        "name": "sda1"
                    },
                    {
                        "mountpoint": "/boot",
                        "name": "sda2"
                    },
                    {
                        "children": [
                            {
                                "children": [
                                    {
                                        "mountpoint": "/",
                                        "name": "ubuntu--vg-ubuntu--lv"
                                    },
                                    {
                                        "mountpoint": null,
                                        "name": "ubuntu--vg-clean"
                                    }
                                ],
                                "mountpoint": null,
                                "name": "ubuntu--vg-ubuntu--lv-real"
                            },
                            {
                                "children": [
                                    {
                                        "mountpoint": null,
                                        "name": "ubuntu--vg-clean"
                                    }
                                ],
                                "mountpoint": null,
                                "name": "ubuntu--vg-clean-cow"
                            }
                        ],
                        "mountpoint": null,
                        "name": "sda3"
                    }
                ],
                "mountpoint": null,
                "name": "sda"
            },
            {
                "children": [
                    {
                        "mountpoint": null,
                        "name": "datavg-datavol1"
                    }
                ],
                "mountpoint": null,
                "name": "sdb"
            }
        ]
    }
}

If I modify the above shell command to lsblk -oMOUNTPOINT,NAME --json | jq '.blockdevices[] | select(.mountpoint == null) | .name'

The output is

TASK [debug] *************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "\"sda\"\n\"sdb\""
}

But, I need only one drive name based on the fact that the drive contains the "mountpoint": "/". The expected output is sda. How else can I modify the above shell command, so that a recursive search is carried out and I get the desired output?

CodePudding user response:

The registered variable lsblk_output.stdout is a string that contains the JSON data. You have to read the dictionary from the string by from_yaml (or by from_json, whatever you prefer). Then take the attribute blockdevices and select the mountpoint. For example, given the data

  lsblk_output:
    stdout:
      blockdevices:
      - children:
        - mountpoint: /
          name: nvme0n1p6
        - mountpoint: /export
          name: nvme0n1p7
        mountpoint: null
        name: nvme0n1
      - children:
        - mountpoint: /root2
          name: nvme0n2p6
        - mountpoint: /export2
          name: nvme0n2p7
        mountpoint: null
        name: nvme0n2

the query below gives the name of the '/' mountpoint

  - debug:
      msg: "{{ (lsblk_output.stdout|from_yaml).blockdevices|
               json_query(query)|
               flatten }}"
    vars:
      query: "[].*[?mountpoint == '/'].name"
  msg:
  - nvme0n1p6

CodePudding user response:

If you gather_facts, you can take advantage of the ansible_mounts fact instead of running lsblk.

A task such as below can filter out the disk/partition mounted at /.

    - name: show root disk
      debug:
        msg: "{{ ansible_mounts | json_query(query) | first }}"
      vars:
        query: "[?mount == '/'].device"

Results like:

ok: [localhost] => {
    "msg": "/dev/sda1"
}
  • Related