Search code examples
automationansibleredhat

Double loop in ansible


I am trying to use a double loop in order to create an LVM for the disks detected and then mount the LVM created to a specific path.

Intil now I can use with_items to create the LVM but I cannot find a way to automate the creation of the LVM with the specific "application" variable for >= 3 disks.

PS: application I use for the lv/vg name and the path

Example: for sda, sdb, sdc

  • sda: will be skipped since it's already partionned from template
  • sdb: I will use the name postgres ==> vg-postgres & lv-postgres & /opt/postgres
  • sdc: I will use the name data ===> vg-data & lv-data & /opt/data

How can this be done?

main.yml

---
- name: get a list of block devices (excludes loop and child devices)
  command: lsblk -n -o NAME --nodeps --exclude 7
  register: lsblk_out
 
- include_tasks: lvm.yml
  with_items: '{{ lsblk_out.stdout_lines }}'
  when: sdx != 'sda'
  loop_control:
    loop_var: sdx

lvm.yml

---
- name: task for creating volume group with disk {{ sdx }}
  lvg:
    vg: vg-{{application}}
    pvs: /dev/{{ sdx }}
    pesize: 16
    state: present
   
- name: task for creating logical volume
  lvol:
    vg: vg-{{application}}
    lv:  lv-{{application}}
    size: 100%FREE
    force: yes
    state: present

- name: Create a ext4 filesystem on lvm "/dev/{{ sdx }}".
  filesystem:
    fstype: ext4
    dev: "/dev/vg-{{application}}/lv-{{application}}"
    force: no

- name: Create a directory to mount the filesystem.
  file:
    path: "/opt/{{application}}"
    state: directory
    mode: '0755'

- name: Mount the created  filesystem.
  mount:
    path: "/opt/{{application}}"
    src: "/dev/vg-{{application}}/lv-{{application}}"
    fstype: ext4
    opts: defaults
    state: mounted

Solution

  • there are lot of solutions, you could use a dictionary:

    - include_tasks: lvm.yml
      with_items: '{{ lsblk_out.stdout_lines }}'
      when: sdx != 'sda'
      loop_control:
        loop_var: sdx
      vars:
        listsdx:
          sdb: item1
          sdc: item2
        application: "{{  listsdx[sdx] }}"
    

    if you want ot use a list like this sdb = item1, sdc = item2, i take the last char of each sdx and consider 'a' =0 , 'b' = 1 and so on

    i need to create custom filter for the python function ord which transform a char to codeascii:

    the custom filter: create a folder filter_plugins in same level than your playbook, create a file customfilter.py and i have named the filter ord

    the file customfilters.py

    #!/usr/bin/python
    class FilterModule(object):
        def filters(self):
            return {
                'ord': self.ord
            }
    
        def ord(self, c):
            return ord(c) - ord('a')
    

    the playbook:

    - include_tasks: lvm.yml
      with_items: '{{ lsblk_out.stdout_lines }}'
      when: sdx != 'sda'
      loop_control:
        loop_var: sdx
      vars:
        apps: ["", 'item1', 'item2']
        application: "{{  apps[sdx | last | ord] }}"