148 lines
6.2 KiB
YAML
148 lines
6.2 KiB
YAML
---
|
|
# ============================================================================
|
|
# expand-root-lv / main
|
|
# ----------------------------------------------------------------------------
|
|
# 0. Ensure growpart is available (cloud-guest-utils provides the growpart binary)
|
|
# 1. Grow the partition (growpart) if a PV partition device is defined
|
|
# 2. Resize the physical volume (pvresize) to pick up the new partition size
|
|
# 3. Confirm the target VG exists (skip role cleanly on non-LVM hosts).
|
|
# 4. Read free physical-extent count for the VG.
|
|
# 5. Extend the LV to +100%FREE only when free_pe > 0.
|
|
# 6. Grow the filesystem on the mountpoint (ext4 -> resize2fs, xfs -> xfs_growfs).
|
|
# Each step is idempotent and skips when there's nothing to do.
|
|
# ============================================================================
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 0: Ensure growpart is available
|
|
# ---------------------------------------------------------------------------
|
|
- name: Ensure cloud-guest-utils (growpart) is installed
|
|
ansible.builtin.package:
|
|
name: cloud-guest-utils
|
|
state: present
|
|
when: expand_root_lv_pv_partition is defined
|
|
tags: [growpart, always]
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 1: Grow the partition that backs the PV
|
|
# ---------------------------------------------------------------------------
|
|
# growpart expects: growpart <device> <partition_number>
|
|
# e.g. growpart /dev/sda 3 — NOT growpart /dev/sda3
|
|
# We split expand_root_lv_pv_partition (e.g. /dev/sda3) into device and part_no.
|
|
|
|
- name: Derive device and partition number from PV partition path
|
|
ansible.builtin.set_fact:
|
|
expand_root_lv_pv_device: "{{ expand_root_lv_pv_partition | regex_replace('p?(\\d+)$', '') }}"
|
|
expand_root_lv_pv_part_no: "{{ expand_root_lv_pv_partition | regex_replace('.*p?(\\d+)$', '\\1') }}"
|
|
when: expand_root_lv_pv_partition is defined
|
|
tags: [growpart, always]
|
|
|
|
- name: Grow partition to fill disk (growpart)
|
|
ansible.builtin.command:
|
|
cmd: "growpart {{ expand_root_lv_pv_device }} {{ expand_root_lv_pv_part_no }}"
|
|
register: growpart_result
|
|
when: expand_root_lv_pv_partition is defined
|
|
changed_when: growpart_result.rc == 0 and "NO CHANGE" not in growpart_result.stdout
|
|
tags: [growpart, always]
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 2: Resize the physical volume to claim the new partition space
|
|
# ---------------------------------------------------------------------------
|
|
- name: Resize physical volume (pvresize)
|
|
ansible.builtin.command:
|
|
cmd: "pvresize {{ expand_root_lv_pv_partition }}"
|
|
register: pvresize_result
|
|
when: expand_root_lv_pv_partition is defined
|
|
changed_when: pvresize_result.rc == 0
|
|
tags: [pvresize, always]
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 3: Confirm the target VG exists (skip role cleanly on non-LVM hosts).
|
|
# ---------------------------------------------------------------------------
|
|
- name: Gather LVM facts
|
|
ansible.builtin.command:
|
|
cmd: "vgs --noheadings --nosuffix --units b -o vg_name,vg_free_count {{ expand_root_lv_vg_name }}"
|
|
register: vg_info
|
|
changed_when: false
|
|
failed_when: false
|
|
tags: [lvm, always]
|
|
|
|
- name: Skip role when target VG is absent
|
|
ansible.builtin.meta: end_play
|
|
when: vg_info.rc != 0
|
|
tags: [lvm, always]
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 4: Parse free PE count for the VG
|
|
# ---------------------------------------------------------------------------
|
|
- name: Parse free PE count
|
|
ansible.builtin.set_fact:
|
|
expand_root_lv_free_pe: "{{ (vg_info.stdout.split() | last | int) if vg_info.stdout | length > 0 else 0 }}"
|
|
tags: [lvm, always]
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 5: Extend the LV to +100%FREE only when free_pe > 0
|
|
# ---------------------------------------------------------------------------
|
|
- name: Extend LV to fill VG (only if free PE > 0)
|
|
ansible.builtin.command:
|
|
cmd: "lvextend -l +100%FREE /dev/{{ expand_root_lv_vg_name }}/{{ expand_root_lv_lv_name }}"
|
|
register: lvextend_result
|
|
when: expand_root_lv_free_pe | int > 0
|
|
changed_when: lvextend_result.rc == 0
|
|
tags: [lvm, always]
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 6: Detect filesystem type at mountpoint and grow
|
|
# ---------------------------------------------------------------------------
|
|
- name: Detect filesystem type at mountpoint
|
|
ansible.builtin.command:
|
|
cmd: "findmnt {{ expand_root_lv_mountpoint }} -no FSTYPE"
|
|
register: fstype_result
|
|
changed_when: false
|
|
tags: [filesystem, always]
|
|
|
|
- name: Set filesystem type fact
|
|
ansible.builtin.set_fact:
|
|
expand_root_lv_fstype: "{{ fstype_result.stdout | trim }}"
|
|
tags: [filesystem, always]
|
|
|
|
- name: Grow ext4 filesystem
|
|
ansible.builtin.command:
|
|
cmd: "resize2fs /dev/{{ expand_root_lv_vg_name }}/{{ expand_root_lv_lv_name }}"
|
|
register: resize_result
|
|
when:
|
|
- expand_root_lv_fstype == "ext4"
|
|
- (growpart_result is defined and growpart_result.changed) or
|
|
(pvresize_result is defined and pvresize_result.changed) or
|
|
(lvextend_result is defined and lvextend_result.changed) or
|
|
(growpart_result is not defined)
|
|
changed_when: resize_result.rc == 0
|
|
tags: [filesystem, always]
|
|
|
|
- name: Grow xfs filesystem
|
|
ansible.builtin.command:
|
|
cmd: "xfs_growfs {{ expand_root_lv_mountpoint }}"
|
|
register: xfs_result
|
|
when:
|
|
- expand_root_lv_fstype == "xfs"
|
|
- (growpart_result is defined and growpart_result.changed) or
|
|
(pvresize_result is defined and pvresize_result.changed) or
|
|
(lvextend_result is defined and lvextend_result.changed) or
|
|
(growpart_result is not defined)
|
|
changed_when: xfs_result.rc == 0
|
|
tags: [filesystem, always]
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 7: Report current root size
|
|
# ---------------------------------------------------------------------------
|
|
- name: Report current root size
|
|
ansible.builtin.command:
|
|
cmd: "df -h {{ expand_root_lv_mountpoint }}"
|
|
register: df_result
|
|
changed_when: false
|
|
tags: [always]
|
|
|
|
- name: Show post-resize disk usage
|
|
ansible.builtin.debug:
|
|
msg: "{{ df_result.stdout_lines }}"
|
|
tags: [always]
|