Hi guys,

I have the following variable in Ansible:

additional_lvm_disks:
  persistent:
    device: xvdb
    part: 1
    crypt: yes
    logical_volumes:
      persistent_data:
        size: 100%VG
        mount: /data
  volatile_hdd:
    device: xvdc
    part: 1
    crypt: yes
    logical_volumes:
      var_cache:
        size: 50%VG
        mount: /var/cache
      var_log:
        size: 50%VG
        mount: /var/log
  volatile_ssd:
    device: xvde
    part: 1
    crypt: yes
    logical_volumes:
      tmp:
        size: 30%VG
        mount: /tmp
      volatile_data:
        size: 70%VG
        mount: /media/volatile_data

Now I want to iterate over this structure and create encrypted disks with an LVM on top. I named the PVs according to the keys, so I came up with this (which, obviously, does not work properly):

- name: Install parted
  apt:
    name: [ 'parted' ]
    state: present

- name: Install lvm2 dependency
  package:
    name: lvm2
    state: present

- name: list the devices and mounts being specified
  debug:
    msg: "{{ item.device }} - {{ item.mount }}"
  with_items: "{{ var_devices_mounts }}"

- name: Check if devices exist
  fail:
    msg: "device {{ item.value.device }} does not exist or is corrupted }} "
  when: ansible_facts['devices'][item.value.device]['size'] | length == 0
  loop: "{{ lookup('dict', additional_lvm_disks) }}"

- name: Check Secret File Creation
  command: sh -c "dd if=/dev/urandom of={{ var_keyfile_path }} bs=1024 count=4"
  args:
    chdir:   "{{ var_keyfile_dir }}"
    creates: "{{ var_keyfile_path }}"

- name: Check Secret File Permissions
  file:
    state: file
    path:  "{{ var_keyfile_path }}"
    owner: root
    group: root
    mode:  "0400"

- name: Create Partition
  parted:
    device: "/dev/{{ item.value.device }}"
    number: 1
    flags: [ lvm ]
    state: present
  loop: "{{ lookup('dict', additional_lvm_disks) }}"

- name: Create LUKS container with a passphrase
  luks_device:
    device: "/dev/{{ item.value.device }}1"
    state: "present"
    passphrase: "123456789"
  loop: "{{ lookup('dict', additional_lvm_disks) }}"

- name: Add keyfile to the LUKS container
  luks_device:
    device: "/dev/{{ item.value.device }}1"
    new_keyfile: "{{ var_keyfile_path }}"
    passphrase: "123456789"
  loop: "{{ lookup('dict', additional_lvm_disks) }}"

- name: (Create and) open LUKS container
  luks_device:
    device: "/dev/{{ item.value.device }}1"
    state: "opened"
    name: "{{ item.value.device }}1_crypt"
    keyfile: "{{ var_keyfile_path }}"
  loop: "{{ lookup('dict', additional_lvm_disks) }}"

- name: Set the options explicitly a device which must already exist
  crypttab:
    name: "{{ item.value.device }}1_crypt"
    backing_device: "/dev/{{ item.value.device }}1"
    state: present
    password: "{{ var_keyfile_path }}"
    opts: luks
  loop: "{{ lookup('dict', additional_lvm_disks) }}"

- name: Creating Volume Group
  lvg:
    vg: "{{ item.key }}"
    pvs: "/dev/mapper/{{ item.value.device }}1_crypt"
  loop: "{{ lookup('dict', additional_lvm_disks) }}"

- name: Creating Logical Volume
  lvol:
    vg: "{{ item.value.volume_group }}"
    lv:  "{{ item.key }}"
    size: 100%VG
  loop: "{{ lookup('dict', (additional_lvm_disks | dict2items | combine(recursive=True, list_merge='append')).value.logical_volumes) }}"

- name: create directorie(s)
  file:
    path: "{{ item.value.mount }}"
    state: directory
  loop: "{{ lookup('dict', (additional_lvm_disks | dict2items | combine(recursive=True, list_merge='append')).value.logical_volumes) }}"

- name: format the ext4 filesystem
  filesystem:
    fstype: ext4
    dev: "/dev/{{ item.value.volume_group }}/{{ item.key }}"
  loop: "{{ lookup('dict', (additional_lvm_disks | dict2items | combine(recursive=True, list_merge='append')).value.logical_volumes) }}"

- name: mount the lv
  mount:
    path: "{{ item.value.mount }}"
    src: "/dev/{{ item.value.volume_group }}/{{ item.key }}"
    fstype: ext4
    state: mounted
  loop: "{{ lookup('dict', (additional_lvm_disks | dict2items | combine(recursive=True, list_merge='append')).value.logical_volumes) }}"

I found that I probably need the product filter for a loop to create a cartesian product of all the volume groups and their disks as well as all the logical volumes and their volume groups, the latter looking something like this:

- { volume_group: volatile_hdd, logical_volume: var_cache, size: 50%VG }
- { volume_group: volatile_hdd, logical_volume: var_log, size: 50%VG }

Sadly I can’t wrap my head around this and there are no good tutorials or examples I could find.

How do I iterate over the “monster dictionary” above to get what I want?