[FIX] qemu: forcer LC_ALL=C sur virsh/sgdisk/… (locale fr cassait l'état des VM)

Sur un hôte en français, « virsh domstate » renvoie « en cours d'exécution »
au lieu de « running ». Le test « state == "running" » échouait donc :
l'agrandissement à chaud tombait dans la branche « qemu-img resize » (au
lieu de « virsh blockresize ») sur une VM ALLUMÉE -> « Failed to get write
lock ».

On force désormais LC_ALL=C / LANG=C (via _qemu_c_env) sur tous les outils
dont on PARSE la sortie, pour avoir l'anglais quelle que soit la locale :
virsh domstate/domname/dominfo/domblklist/list, sgdisk -i, dumpe2fs,
resize2fs -P (todo.py) et virsh list --all (dashboard). Cela répare aussi,
en locale fr, la détection d'état (pause/éteinte), l'analyse des infos
avancées (CPU/RAM) et le parsing de la réduction (partition/GPT).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mathieu Benoit 2026-07-30 01:04:07 -04:00
parent 8be034f25e
commit ae3745a22a
2 changed files with 23 additions and 4 deletions

View file

@ -489,6 +489,9 @@ def virsh_domstates() -> dict:
capture_output=True,
text=True,
timeout=15,
# LC_ALL=C : sortie en ANGLAIS (« running »/« paused »/« shut off »
# + en-tête « Id Name State ») quelle que soit la locale de l'hôte.
env={**os.environ, "LC_ALL": "C", "LANG": "C"},
)
except (OSError, subprocess.SubprocessError):
return {}

View file

@ -1241,6 +1241,7 @@ class TODO:
capture_output=True,
text=True,
timeout=15,
env=TODO._qemu_c_env(),
)
except (OSError, subprocess.SubprocessError):
return 0, 0
@ -1489,6 +1490,17 @@ class TODO:
# ------------------------------------------------------------------ #
# Redimensionnement du disque d'une VM
# ------------------------------------------------------------------ #
@staticmethod
def _qemu_c_env():
"""Environnement forçant LC_ALL=C : la sortie des outils (virsh,
sgdisk, resize2fs, dumpe2fs) reste en ANGLAIS quelle que soit la
locale de l'hôte. Sinon « running » devient « en cours d'exécution »
(fr) et les comparaisons/parsing d'état cassent."""
env = dict(os.environ)
env["LC_ALL"] = "C"
env["LANG"] = "C"
return env
@staticmethod
def _qemu_domstate(name):
"""État libvirt de la VM (« running », « shut off », …) ou ''."""
@ -1498,6 +1510,7 @@ class TODO:
capture_output=True,
text=True,
timeout=15,
env=TODO._qemu_c_env(),
)
except (OSError, subprocess.SubprocessError):
return ""
@ -1516,6 +1529,7 @@ class TODO:
capture_output=True,
text=True,
timeout=15,
env=TODO._qemu_c_env(),
)
except (OSError, subprocess.SubprocessError):
return name
@ -1571,6 +1585,7 @@ class TODO:
capture_output=True,
text=True,
timeout=15,
env=TODO._qemu_c_env(),
)
except (OSError, subprocess.SubprocessError):
return None
@ -2001,7 +2016,7 @@ class TODO:
info = {"type": "", "uuid": "", "name": ""}
res = subprocess.run(
["sudo", "sgdisk", "-i", n, dev],
capture_output=True, text=True,
capture_output=True, text=True, env=TODO._qemu_c_env(),
)
for line in res.stdout.splitlines():
low = line.lower()
@ -2017,7 +2032,7 @@ class TODO:
def _qemu_fs_blocksize(part):
res = subprocess.run(
["sudo", "dumpe2fs", "-h", part],
capture_output=True, text=True,
capture_output=True, text=True, env=TODO._qemu_c_env(),
)
for line in res.stdout.splitlines():
if line.startswith("Block size:"):
@ -2031,7 +2046,7 @@ class TODO:
def _qemu_fs_blocks(part):
res = subprocess.run(
["sudo", "dumpe2fs", "-h", part],
capture_output=True, text=True,
capture_output=True, text=True, env=TODO._qemu_c_env(),
)
for line in res.stdout.splitlines():
if line.startswith("Block count:"):
@ -2046,7 +2061,7 @@ class TODO:
"""Taille minimale (blocs) du FS via « resize2fs -P »."""
res = subprocess.run(
["sudo", "resize2fs", "-P", part],
capture_output=True, text=True,
capture_output=True, text=True, env=TODO._qemu_c_env(),
)
for tok in res.stdout.replace(":", " ").split():
if tok.isdigit():
@ -2454,6 +2469,7 @@ class TODO:
capture_output=True,
text=True,
timeout=15,
env=self._qemu_c_env(),
)
except (OSError, subprocess.SubprocessError):
continue