Ansible | delete files from a directory if the filename doesn't contains any of the strings from a list

Viewed 18

I'm creating vm-s with libvirt, and I would like to do a housekeeping, if I delete a host (in this example a VM) from my inventory, at the next run of the playbook, it should delete that VM's qcow2 disk from the disk pool.

I don't really get, how could I create a nested loop that iterates through the file list of that specific directory and the list of vms in my inventory, checks if the name of the vm is part of any file in the filelist, and deletes the files whose have no connection into the inventory.

Here is an example from the many things I already tried:

- name: "Housekeeping: list qcow2 disks in libvirt-pool"
  find:
    paths: /mnt/hdd/libvirt-pool
    depth: 1
    patterns:
      - "*.qcow2"
  register: qcow_disks

- name: debug
  debug:
    msg: "{{item[0]}}"
  with_nested:
    - "{{ qcow_disks.files | map(attribute='path') | list }}"
    - "{{ groups.vm }}"
  when: item[1] in item[0]
  register: valid_disks

- name: debug1
  debug:
    msg: "invalid disks: {{ valid_disks.results | difference(all_disk) }}"
  variable:
    all_disk: "{{ qcow_disks.files | map(attribute='path') | list }}"

Hope you can help me out!

Thanks in advance!

1 Answers

I assume you have in groups.vm a list of names of VMs, without the extension .qcow2.

So the list groups.vm could looks like e.g:

['vm1', 'vm5', 'test']

The find command returns files like:

[
  "/mnt/hdd/libvirt-pool/bob.qcow2",
  "/mnt/hdd/libvirt-pool/daniel.qcow2",
  "/mnt/hdd/libvirt-pool/test.qcow2",
  "/mnt/hdd/libvirt-pool/vm1.qcow2",
  "/mnt/hdd/libvirt-pool/vm5.qcow2"
]

With the following command you can reduce this list to the name without extension, then you can easily compare the lists.

{{ qcow_disks.files | map(attribute='path') | map('basename') | map('splitext') | map('first') }}
  • basename returns the filename, without preceding path
  • splitext splits the filename into a list: [name, extension]
  • first takes the first element from the list, i.e. the name

More on basename and splitext in the Ansible docs.

{{ found_disks | reject('in', current_vms) }}

With the reject filter you can then discard the current elements, so that you contain a list with all old VMs.


The following tasks:

- name: "Housekeeping: list qcow2 disks in libvirt-pool"
  find:
    paths: /mnt/hdd/libvirt-pool
    depth: 1
    patterns:
      - "*.qcow2"
  register: qcow_disks

- debug:
    msg: "{{ qcow_disks.files | map(attribute='path') }}"

- debug:
    msg: "{{ old_disks }}"
  vars:
    current_vms: ['vm1', 'vm5', 'test']
    found_disks: "{{ qcow_disks.files | map(attribute='path') | map('basename') | map('splitext') | map('first') }}"
    old_disks: "{{ found_disks | reject('in', current_vms) }}"

Note: current_vms corresponds to the list you have via groups.vm.

return this result:

TASK [Housekeeping: list qcow2 disks in libvirt-pool] ************************
ok: [localhost]

TASK [debug] *****************************************************************
ok: [localhost] => {
    "msg": [
        "/mnt/hdd/libvirt-pool/bob.qcow2",
        "/mnt/hdd/libvirt-pool/daniel.qcow2",
        "/mnt/hdd/libvirt-pool/test.qcow2",
        "/mnt/hdd/libvirt-pool/vm1.qcow2",
        "/mnt/hdd/libvirt-pool/vm5.qcow2"
    ]
}

TASK [debug] *****************************************************************
ok: [localhost] => {
    "msg": [
        "bob",
        "daniel"
    ]
}

I hope this helps you.

Related