# Filter ansible\_devices to get the first disk without partitions

**URL:** <https://forum.ansible.com/t/filter-ansible-devices-to-get-the-first-disk-without-partitions/44399>\
**Category:** Get Help\
**Tags:** jinja2\
**Created:** [September 1, 2025, 2:53pm UTC](https://forum.ansible.com/t/filter-ansible-devices-to-get-the-first-disk-without-partitions/44399 "2025-09-01T14:53:31Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![stemid](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/stemid/32/9338_2.png) [@stemid](https://forum.ansible.com/u/stemid)\
**Post date:** [September 1, 2025, 2:53pm UTC](https://forum.ansible.com/t/filter-ansible-devices-to-get-the-first-disk-without-partitions/44399/1 "2025-09-01T14:53:32Z")

</div>

My goal is to get the first disk in ansible\_devices without any partitions, to format it.

Here is the output of `ansible -m setup -a filter=ansible_devices all`, so in this case it’s sdb but it’s not always sdb.

```json
    "ansible_facts": {
        "ansible_devices": {
            "sda": {
                "holders": [],
                "host": "SCSI storage controller: Red Hat, Inc. Virtio SCSI",
                "links": {
                    "ids": [
                        "scsi-0QEMU_QEMU_HARDDISK_drive-scsi0"
                    ],
                    "labels": [],
                    "masters": [],
                    "uuids": []
                },
                "model": "QEMU HARDDISK",
                "partitions": {
                    "sda1": {
                        "holders": [],
                        "links": {
                            "ids": [
                                "scsi-0QEMU_QEMU_HARDDISK_drive-scsi0-part1"
                            ],
                            "labels": [],
                            "masters": [],
                            "uuids": [
                                "58dd5456-f0e0-45ce-a7fe-028c84332cb0"
                            ]
                        },
                        "sectors": 104595423,
                        "sectorsize": 512,
                        "size": "49.87 GB",
                        "start": "262144",
                        "uuid": "58dd5456-f0e0-45ce-a7fe-028c84332cb0"
                    },
                    "sda14": {
                        "holders": [],
                        "links": {
                            "ids": [
                                "scsi-0QEMU_QEMU_HARDDISK_drive-scsi0-part14"
                            ],
                            "labels": [],
                            "masters": [],
                            "uuids": []
                        },
                        "sectors": 6144,
                        "sectorsize": 512,
                        "size": "3.00 MB",
                        "start": "2048",
                        "uuid": null
                    },
                    "sda15": {
                        "holders": [],
                        "links": {
                            "ids": [
                                "scsi-0QEMU_QEMU_HARDDISK_drive-scsi0-part15"
                            ],
                            "labels": [],
                            "masters": [],
                            "uuids": [
                                "7D87-0B8D"
                            ]
                        },
                        "sectors": 253952,
                        "sectorsize": 512,
                        "size": "124.00 MB",
                        "start": "8192",
                        "uuid": "7D87-0B8D"
                    }
                },
                "removable": "0",
                "rotational": "1",
                "sas_address": null,
                "sas_device_handle": null,
                "scheduler_mode": "none",
                "sectors": 104857600,
                "sectorsize": "512",
                "size": "50.00 GB",
                "support_discard": "4096",
                "vendor": "QEMU",
                "virtual": 1
            },
            "sdb": {
                "holders": [],
                "host": "SCSI storage controller: Red Hat, Inc. Virtio SCSI",
                "links": {
                    "ids": [
                        "scsi-0QEMU_QEMU_HARDDISK_drive-scsi1"
                    ],
                    "labels": [],
                    "masters": [],
                    "uuids": []
                },
                "model": "QEMU HARDDISK",
                "partitions": {},
                "removable": "0",
                "rotational": "1",
                "sas_address": null,
                "sas_device_handle": null,
                "scheduler_mode": "none",
                "sectors": 629145600,
                "sectorsize": "512",
                "size": "300.00 GB",
                "support_discard": "4096",
                "vendor": "QEMU",
                "virtual": 1
            },
            "sr0": {
                "holders": [],
                "host": "SATA controller: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode] (rev 02)",
                "links": {
                    "ids": [
                        "ata-QEMU_DVD-ROM_QM00003"
                    ],
                    "labels": [
                        "cidata"
                    ],
                    "masters": [],
                    "uuids": [
                        "2025-09-01-15-51-07-00"
                    ]
                },
                "model": "QEMU DVD-ROM",
                "partitions": {},
                "removable": "1",
                "rotational": "0",
                "sas_address": null,
                "sas_device_handle": null,
                "scheduler_mode": "mq-deadline",
                "sectors": 2048,
                "sectorsize": "2048",
                "size": "4.00 MB",
                "support_discard": "0",
                "vendor": "QEMU",
                "virtual": 1
            }
        }
    },
    "changed": false
}

```

I’ve been banging my head on this problem with some filters and I can get the item in the ansible\_devices dict that matches, but the name of the disk is not part of the dict keys, so I don’t know how to go back one step and get the actual device name from my match.

```yaml
- name: Find the first unformatted disk that is not the root device
  ansible.builtin.set_fact:
    data_disk: >
      {{
        ansible_devices.keys()
        | select('match', '^[sv]d[a-z]$')
        | map('extract', ansible_devices)
        | selectattr('partitions', 'eq', {})
        | first
      }}

- name: Debug
  debug:
    msg: "{{ data_disk }}"

```

The above play would produce this output.

```auto
Debug...       
  nfs01 ok: {
    "changed": false,
    "msg": {              
        "holders": [], 
        "host": "SCSI storage controller: Red Hat, Inc. Virtio SCSI",
        "links": {  
            "ids": [
                "scsi-0QEMU_QEMU_HARDDISK_drive-scsi1"
            ],        
            "labels": [],
            "masters": [],              
            "uuids": []        
        },     
        "model": "QEMU HARDDISK",
        "partitions": {},
        "removable": "0",        
        "rotational": "1",
        "sas_address": null,
        "sas_device_handle": null,
        "scheduler_mode": "none",
        "sectors": 629145600,     
        "sectorsize": "512",
        "size": "300.00 GB",
        "support_discard": "4096",
        "vendor": "QEMU",
        "virtual": 1  
    }          
}              

```

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [September 1, 2025, 4:13pm UTC](https://forum.ansible.com/t/filter-ansible-devices-to-get-the-first-disk-without-partitions/44399/2 "2025-09-01T16:13:04Z")

</div>

You’re very close. Try this:

```yaml
- name: Find the first unformatted disk that is not the root device
  ansible.builtin.set_fact:
    data_disk: >
      {{
        [ansible_devices
         | dict2items
         | selectattr('value.partitions', 'eq', {})
         | first
        ] | items2dict
      }}

```

The filter `dict2items` takes a dictionary and transforms it into a list of dictionaries, with each having a `key` and `value` keys. Then your `selectattr()` checks `value.partitions` instead of `partitions` like it was doing before. Then the `first` filter gets the one you wanted. All of that gets wrapped in `[…]` so that `items2dict` (which expects a list of dicts rather than the single dict) can undo what `dict2items` did.

Edit: I see I left out the `select('match', '^[sv]d[a-z]$')` part. You should be able to add that back in easily enough. I started to, but didn’t want to detract from the salient part of this answer, which is that a `dict2items | <do some stuff> | items2dict` pattern is really handy when you need to filter dicts and retain the keys of the matching values.

---

<div class="post-metadata">

**Author:** ![stemid](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/stemid/32/9338_2.png) [@stemid](https://forum.ansible.com/u/stemid)\
**Post date:** [September 1, 2025, 7:44pm UTC](https://forum.ansible.com/t/filter-ansible-devices-to-get-the-first-disk-without-partitions/44399/3 "2025-09-01T19:44:39Z")

</div>

Thank you! You definitely helped me solve it but I’m not sure I fully understand what is going on. Or of I’m doing it right. But it is working now.

Maybe it could be done in a nicer or more robust way?

```yaml
- name: Find the first unformatted disk that is not the root device
  ansible.builtin.set_fact:
    disk_info: >
      {{
        [ansible_devices
          | dict2items
          | selectattr('value.partitions', 'eq', {})
          | first
        ] | items2dict
      }}

- name: Set data_disk value
  ansible.builtin.set_fact:
    data_disk: "/dev/{{ disk_info.keys() | first }}"

- name: Create a filesystem on the data disk
  community.general.filesystem:
    fstype: xfs
    dev: "{{ data_disk }}"

```

If I fully understood this solution I’d probably keep my select match to ensure I only match with valid disk names. But I just couldn’t sort it out.

Ah nevermind, I figured it out, was so simple.

```yaml
- name: Find the first unformatted disk that is not the root device
  ansible.builtin.set_fact:
    disk_info: >
      {{
        [ansible_devices
          | dict2items
          | selectattr('key', 'match', '^[sv]d[a-z]$')
          | selectattr('value.partitions', 'eq', {})
          | first
        ] | items2dict
      }}

```

Now it’s just what I wanted.

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [September 1, 2025, 8:08pm UTC](https://forum.ansible.com/t/filter-ansible-devices-to-get-the-first-disk-without-partitions/44399/4 "2025-09-01T20:08:46Z")

</div>

This is long-winded, but I often do this with long or confusing pipelines. Run with `-v` to see what the `set_fact`s are doing. (I dropped the `debug` steps.)

```yaml
- name: Break it down | 1 | dict2items
  ansible.builtin.set_fact:
    data_disk: >
      {{
        ansible_devices
         | dict2items
      }}

- name: Break it down | 2 | selectattr acceptable keys
  ansible.builtin.set_fact:
    data_disk: >
      {{
        ansible_devices
         | dict2items
         | selectattr('key', 'match', '^[sv]d[a-z]$')
      }}

- name: Break it down | 3 | selectattr empty partitions
  ansible.builtin.set_fact:
    data_disk: >
      {{
        ansible_devices
         | dict2items
         | selectattr('key', 'match', '^[sv]d[a-z]$')
         | selectattr('value.partitions', 'eq', {})
      }}

- name: Break it down | 4,5 | first in a one-element list
  ansible.builtin.set_fact:
    data_disk: >
      {{
        [ansible_devices
         | dict2items
         | selectattr('key', 'match', '^[sv]d[a-z]$')
         | selectattr('value.partitions', 'eq', {})
         | first
        ]
      }}

- name: Break it down | 6 | items2dict
  ansible.builtin.set_fact:
    data_disk: >
      {{
        [ansible_devices
         | dict2items
         | selectattr('key', 'match', '^[sv]d[a-z]$')
         | selectattr('value.partitions', 'eq', {})
         | first
        ] | items2dict
      }}

- name: But wait... you only wanted the key anyway
  ansible.builtin.set_fact:
    data_disk: >
      {{
        (ansible_devices
         | dict2items
         | selectattr('key', 'match', '^[sv]d[a-z]$')
         | selectattr('value.partitions', 'eq', {})
         | first
        ).key
      }}

```

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/ansible/original/1X/1882d9a01da5d8996a862359b0913cc568a39b84.svg) [@system](https://forum.ansible.com/u/system)\
**Post date:** [October 1, 2025, 8:09pm UTC](https://forum.ansible.com/t/filter-ansible-devices-to-get-the-first-disk-without-partitions/44399/5 "2025-10-01T20:09:44Z")

</div>

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.
