feat: espace LVM — thin pool data_percent + ext4 offline via tune2fs
- lvs query enrichi : lv_dm_path, data_percent, lv_attr - thin_pool_used_percent sur les thin pools (ex: Proxmox pve/data) - LV ext4 non montés lus via tune2fs sur /dev/mapper path - _format_lv() centralise la construction des entrées LV Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+38
-8
@@ -314,7 +314,7 @@ def get_lvm_map():
|
|||||||
return {}
|
return {}
|
||||||
lvs_by_vg = {}
|
lvs_by_vg = {}
|
||||||
lvs_out = run(["lvs", "--noheadings", "--reportformat", "json",
|
lvs_out = run(["lvs", "--noheadings", "--reportformat", "json",
|
||||||
"-o", "lv_name,vg_name,lv_size,lv_path"])
|
"-o", "lv_name,vg_name,lv_size,lv_path,lv_dm_path,data_percent,lv_attr"])
|
||||||
if lvs_out:
|
if lvs_out:
|
||||||
try:
|
try:
|
||||||
for lv in json.loads(lvs_out)["report"][0]["lv"]:
|
for lv in json.loads(lvs_out)["report"][0]["lv"]:
|
||||||
@@ -328,17 +328,47 @@ def get_lvm_map():
|
|||||||
if pv_name and vg_name:
|
if pv_name and vg_name:
|
||||||
result[pv_name] = {
|
result[pv_name] = {
|
||||||
"vg_name": vg_name,
|
"vg_name": vg_name,
|
||||||
"logical_volumes": [
|
"logical_volumes": [_format_lv(lv)
|
||||||
{"lv_name": lv.get("lv_name", ""),
|
for lv in lvs_by_vg.get(vg_name, [])],
|
||||||
"size_human": _lv_size_human(lv.get("lv_size", "")),
|
|
||||||
"used_human": None, "free_human": None,
|
|
||||||
"used_percent": None, "fstype": None, "mountpoint": None}
|
|
||||||
for lv in lvs_by_vg.get(vg_name, [])
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
dprint(f"LVM : {len(result)} volume(s) physique(s)")
|
dprint(f"LVM : {len(result)} volume(s) physique(s)")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def _format_lv(lv):
|
||||||
|
name = lv.get("lv_name", "")
|
||||||
|
dm_path = lv.get("lv_dm_path", "") or lv.get("lv_path", "") or ""
|
||||||
|
attr = lv.get("lv_attr", "")
|
||||||
|
|
||||||
|
entry = {
|
||||||
|
"lv_name": name,
|
||||||
|
"size_human": _lv_size_human(lv.get("lv_size", "")),
|
||||||
|
"used_human": None, "free_human": None, "used_percent": None,
|
||||||
|
"fstype": None, "mountpoint": None,
|
||||||
|
"thin_pool_used_percent": None,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Thin pool : data_percent indique le remplissage du pool
|
||||||
|
dp = lv.get("data_percent", "")
|
||||||
|
if dp and dp.strip() not in ("", "0.00"):
|
||||||
|
try:
|
||||||
|
entry["thin_pool_used_percent"] = round(float(dp), 1)
|
||||||
|
dprint(f" LV {name} thin pool : {entry['thin_pool_used_percent']}% utilise")
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# LV ext4 non monté → lecture offline via tune2fs
|
||||||
|
# (attr[0] 'V'/'v' = thin vol, 't'/'T' = thin pool; les deux ont data_percent)
|
||||||
|
is_pool = attr[:1].lower() in ("t",)
|
||||||
|
if not is_pool and dm_path:
|
||||||
|
space = _ext4_space(dm_path)
|
||||||
|
if space:
|
||||||
|
entry["used_human"] = bytes_human(space["used_bytes"])
|
||||||
|
entry["free_human"] = bytes_human(space["free_bytes"])
|
||||||
|
entry["used_percent"] = space["used_percent"]
|
||||||
|
dprint(f" LV {name} offline : {entry['used_human']} utilise ({entry['used_percent']}%)")
|
||||||
|
|
||||||
|
return entry
|
||||||
|
|
||||||
|
|
||||||
# -- /home users --------------------------------------------------------------
|
# -- /home users --------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user