Ansible Playbook - LVM

3 minute read

Refreshed June 2026: the original used bare module names with the old key=value argument style, installed the wrong package on RHEL, and shelled out to lvextend and resize2fs. This rewrite uses FQCN and proper YAML arguments, installs lvm2 with one cross-distro task, and lets community.general.lvol grow the filesystem with resizefs instead of separate shell commands. Syntax-checked on ansible-core 2.19.

Background

I wanted Ansible to manage LVM on my Linux hosts: create a volume group and logical volume, lay down a filesystem, mount it, and grow it later. The original playbook did all of that with shell commands and the old inline argument syntax. The LVM modules have come a long way since, so most of the shelling out is gone.

The playbook keeps the same idea as the original: a set of boolean flags (config_lvm, create, extend, resize) act as a failsafe so nothing runs unless you opt in. Set config_lvm: true plus exactly one of create, extend, or resize.

Prerequisites

The LVM and mount modules live in collections. Install them on the control node:

ansible-galaxy collection install community.general ansible.posix

The Playbook

---
- hosts: db-vms
  become: true
  vars:
    config_lvm: false          # master switch; nothing runs unless true
    create: false              # create a new logical volume
    extend: false              # add a disk and grow an existing volume
    resize: false              # grow a volume to fill its volume group
    new_disk: /dev/sdb
    new_mntp: /var/lib/mysql
    create_vgname: mysql-vg
    create_lvname: mysql-lv
    create_lvsize: 100%FREE
    extend_vgname: test-vg
    extend_lvname: test-lv
    extend_disks: /dev/sda5,/dev/sdb   # existing disk first, new disk second
    resize_vgname: test-vg
    resize_lvname: test-lv
    filesystem: ext4
  tasks:
    - name: Install LVM tooling
      ansible.builtin.package:
        name: lvm2
        state: present
      when: config_lvm

    - name: Create the volume group
      community.general.lvg:
        vg: "{{ create_vgname }}"
        pvs: "{{ new_disk }}"
        state: present
      when: create and config_lvm

    - name: Create the logical volume
      community.general.lvol:
        vg: "{{ create_vgname }}"
        lv: "{{ create_lvname }}"
        size: "{{ create_lvsize }}"
      when: create and config_lvm

    - name: Create the filesystem
      community.general.filesystem:
        fstype: "{{ filesystem }}"
        dev: "/dev/{{ create_vgname }}/{{ create_lvname }}"
      when: create and config_lvm

    - name: Mount the filesystem
      ansible.posix.mount:
        path: "{{ new_mntp }}"
        src: "/dev/{{ create_vgname }}/{{ create_lvname }}"
        fstype: "{{ filesystem }}"
        state: mounted
      when: create and config_lvm

    - name: Add the new disk to the volume group
      community.general.lvg:
        vg: "{{ extend_vgname }}"
        pvs: "{{ extend_disks }}"
      when: extend and config_lvm

    - name: Extend the logical volume and grow its filesystem
      community.general.lvol:
        vg: "{{ extend_vgname }}"
        lv: "{{ extend_lvname }}"
        size: +10G
        resizefs: true
      when: extend and config_lvm

    - name: Grow a logical volume to fill its volume group
      community.general.lvol:
        vg: "{{ resize_vgname }}"
        lv: "{{ resize_lvname }}"
        size: 100%VG
        resizefs: true
      when: resize and config_lvm

What Changed From The 2015 Version

  • One install task instead of two. The original used apt for Debian and yum for RHEL, and the RHEL branch installed system-storage-manager rather than lvm2. ansible.builtin.package picks the right package manager for the host, so a single task covers both, and it installs lvm2 everywhere.
  • No more lvextend and resize2fs shell commands. community.general.lvol takes size: +10G to extend, or size: 100%VG to grow into the volume group, and resizefs: true grows the filesystem in the same task. That replaces the two command tasks the original used.
  • FQCN and YAML arguments. Every module is fully qualified, and the cramped name=lvm2 state=present style is now readable YAML.
  • become: true. The original had no privilege escalation at all, which would have failed against anything but a root connection.

The original also installed scsitools / sg3_utils and ran rescan-scsi-bus to pick up a hot-added disk without a reboot. I left that out to keep the focus on LVM. If you hot-add a disk and the host does not see it, a SCSI rescan or a reboot is still the fix.

Conclusion

Same workflow, far less shelling out. Let the LVM modules do the volume group, logical volume, filesystem, mount, and growth, and keep the failsafe flags so a stray run cannot touch your disks.

Enjoy!

Comments