Ansible for Partitions, LVM and File Systems
Storage tasks chain four modules, each from community.general except mounting (ansible.posix):
yaml - community.general.parted: device: /dev/vdb number: 1 partend: 1000MiB flags: [lvm] state: present - community.general.lvg: { vg: research, pvs: /dev/vdb1 } - community.general.lvol: { vg: research, lv: data, size: 1500m } - community.general.filesystem: { dev: /dev/research/data, fstype: xfs } - ansible.posix.mount: path: /mnt/data src: /dev/research/data fstype: xfs state: mounted
state: mounted mounts now and writes /etc/fstab, which is what "persistently" means; present only edits fstab, unmounted keeps the entry, absent removes both. The mount point is created for you.
The classic exam pattern. One playbook runs on hosts that differ: some have the VG, some have a VG that is too small, some have none. Facts tell you which (ansiblefacts.lvm), and block/rescue handles the failure:
yaml - debug: msg: Volume group does not exist when: ansiblefacts.lvm.vgs.research is not defined - when: ansiblefacts.lvm.vgs.research is defined block: - community.general.lvol: { vg: research, lv: data, size: 1500m } rescue: - debug: msg: Could not create a logical volume of that size - community.general.lvol: { vg: research, lv: data, size: 800m }
Disks are in ansiblefacts.devices (when: ansiblefacts.devices.vdb is defined). Facts are collected once at play start: a playbook that creates an LV and then tests ansiblefacts.lvm.lvs needs ansible.builtin.setup again, or a separate play.
Sizes. lvol sizes use m/g or extents (100%FREE); resizefs: true grows the file system too. parted uses units such as MiB in partstart/partend.
Checking your work. ansible storage -m command -a 'lvs' and ansible storage -m command -a 'findmnt /mnt/data' show the result on every host at once; lsblk shows partitions. Before submitting, run the whole playbook a second time: every task should be ok and the rescue path should not fire again on hosts where the LV already exists at the smaller size (lvol with a size that matches is a no-op). If the task asks for a size in MiB, write m (lvol) or MiB (parted) consistently, and remember that partitions start at 1 MiB by default.
Pitfalls. Running the partition task on hosts without the disk (guard it). Printing the message with a different spelling than the task gives. Formatting a device that is already in use (filesystem refuses unless force: true, which you almost never want). Using mount with state: present and forgetting it is not mounted now.