lxc_container: use LVM runners from _lvm module utils (#11920)

* lxc_container: use LVM runners from _lvm module utils

Replace direct run_command calls for lvs, vgdisplay, lvdisplay,
lvcreate, and lvremove with the shared CmdRunner-based runners from
module_utils/_lvm.py. Switches from human-readable text parsing to
machine-readable --noheadings/--nosuffix/--separator output.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* lxc_container: add changelog fragment for PR 11920

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* generate run_info information for commands

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Alexei Znamensky
2026-04-29 21:56:30 +12:00
committed by GitHub
parent d0f0e9d00f
commit 1f2e60f65d
3 changed files with 45 additions and 41 deletions

View File

@@ -179,7 +179,7 @@ def pvmove_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
def vgs_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(vgs). Used by: community.general.lvol, community.general.lvg,
community.general.lvg_rename.
community.general.lvg_rename, community.general.lxc_container.
Suggested arg_formats keys: noheadings nosuffix readonly units separator fields select vg
"""
@@ -341,7 +341,7 @@ def vgrename_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
def lvs_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(lvs). Used by: community.general.lvol.
Runner for C(lvs). Used by: community.general.lvol, community.general.lxc_container.
Suggested arg_formats keys: all noheadings nosuffix units separator fields select vg

View File

@@ -422,6 +422,12 @@ from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.text.converters import to_bytes, to_text
from ansible.module_utils.parsing.convert_bool import BOOLEANS_FALSE
from ansible_collections.community.general.plugins.module_utils._lvm import (
lvcreate_runner,
lvremove_runner,
lvs_runner,
vgs_runner,
)
from ansible_collections.community.general.plugins.module_utils._lxc import create_script
# LXC_COMPRESSION_MAP is a map of available compression types when creating
@@ -519,6 +525,7 @@ class LxcContainerManagement:
self.container = self.get_container_bind()
self.archive_info = None
self.clone_info = None
self.run_info = []
def get_container_bind(self):
return lxc.Container(name=self.container_name)
@@ -1045,13 +1052,13 @@ class LxcContainerManagement:
"""Return a list of all lv in a current vg."""
vg = self._get_lxc_vg()
build_command = [self.module.get_bin_path("lvs", True)]
rc, stdout, err = self.module.run_command(build_command)
with lvs_runner(self.module)("noheadings separator fields vg") as ctx:
rc, stdout, err = ctx.run(separator=";", fields="lv_name", vg=[vg])
if self.module._verbosity >= 4:
self.run_info.append(ctx.run_info)
if rc != 0:
self.failure(err=err, rc=rc, msg="Failed to get list of LVs", command=" ".join(build_command))
all_lvms = [i.split() for i in stdout.splitlines()][1:]
return [lv_entry[0] for lv_entry in all_lvms if lv_entry[1] == vg]
self.failure(err=err, rc=rc, msg="Failed to get list of LVs")
return [line.strip() for line in stdout.splitlines() if line.strip()]
def _get_vg_free_pe(self, vg_name):
"""Return the available size of a given VG.
@@ -1062,15 +1069,13 @@ class LxcContainerManagement:
:type: ``tuple``
"""
build_command = ["vgdisplay", vg_name, "--units", "g"]
rc, stdout, err = self.module.run_command(build_command)
with vgs_runner(self.module)("noheadings nosuffix units separator fields vg") as ctx:
rc, stdout, err = ctx.run(units="g", separator=";", fields="vg_free", vg=[vg_name])
if self.module._verbosity >= 4:
self.run_info.append(ctx.run_info)
if rc != 0:
self.failure(err=err, rc=rc, msg=f"failed to read vg {vg_name}", command=" ".join(build_command))
vg_info = [i.strip() for i in stdout.splitlines()][1:]
free_pe = [i for i in vg_info if i.startswith("Free")]
_free_pe = free_pe[0].split()
return float(_free_pe[-2]), _free_pe[-1]
self.failure(err=err, rc=rc, msg=f"failed to read vg {vg_name}")
return float(stdout.strip()), "g"
def _get_lv_size(self, lv_name):
"""Return the available size of a given LV.
@@ -1083,15 +1088,13 @@ class LxcContainerManagement:
vg = self._get_lxc_vg()
lv = os.path.join(vg, lv_name)
build_command = ["lvdisplay", lv, "--units", "g"]
rc, stdout, err = self.module.run_command(build_command)
with lvs_runner(self.module)("noheadings nosuffix units separator fields vg") as ctx:
rc, stdout, err = ctx.run(units="g", separator=";", fields="lv_size", vg=[lv])
if self.module._verbosity >= 4:
self.run_info.append(ctx.run_info)
if rc != 0:
self.failure(err=err, rc=rc, msg=f"failed to read lv {lv}", command=" ".join(build_command))
lv_info = [i.strip() for i in stdout.splitlines()][1:]
_free_pe = [i for i in lv_info if i.startswith("LV Size")]
free_pe = _free_pe[0].split()
return self._roundup(float(free_pe[-2])), free_pe[-1]
self.failure(err=err, rc=rc, msg=f"failed to read lv {lv}")
return self._roundup(float(stdout.strip())), "g"
def _lvm_snapshot_create(self, source_lv, snapshot_name, snapshot_size_gb=5):
"""Create an LVM snapshot.
@@ -1113,16 +1116,15 @@ class LxcContainerManagement:
)
self.failure(error="Not enough space to create snapshot", rc=2, msg=message)
# Create LVM Snapshot
build_command = [
self.module.get_bin_path("lvcreate", True),
"-n",
snapshot_name,
"-s",
os.path.join(vg, source_lv),
f"-L{snapshot_size_gb}g",
]
rc, stdout, err = self.module.run_command(build_command)
with lvcreate_runner(self.module)("size_L is_snapshot lv vg") as ctx:
rc, dummy, err = ctx.run(
size_L=f"{snapshot_size_gb}g",
is_snapshot=True,
lv=[snapshot_name],
vg=[os.path.join(vg, source_lv)],
)
if self.module._verbosity >= 4:
self.run_info.append(ctx.run_info)
if rc != 0:
self.failure(err=err, rc=rc, msg=f"Failed to Create LVM snapshot {vg}/{source_lv} --> {snapshot_name}")
@@ -1190,14 +1192,12 @@ class LxcContainerManagement:
"""
vg = self._get_lxc_vg()
build_command = [
self.module.get_bin_path("lvremove", True),
"-f",
f"{vg}/{lv_name}",
]
rc, stdout, err = self.module.run_command(build_command)
with lvremove_runner(self.module)("force lv") as ctx:
rc, dummy, err = ctx.run(force=True, lv=[f"{vg}/{lv_name}"])
if self.module._verbosity >= 4:
self.run_info.append(ctx.run_info)
if rc != 0:
self.failure(err=err, rc=rc, msg=f"Failed to remove LVM LV {vg}/{lv_name}", command=" ".join(build_command))
self.failure(err=err, rc=rc, msg=f"Failed to remove LVM LV {vg}/{lv_name}")
def _rsync_data(self, container_path, temp_dir):
"""Sync the container directory to the temp directory.
@@ -1375,6 +1375,8 @@ class LxcContainerManagement:
:param rc: ``int`` Return code while executing an Ansible command.
:param msg: ``str`` Message to report.
"""
if self.run_info:
kwargs["run_info"] = self.run_info
self.module.fail_json(**kwargs)