Bei fehlgeschlagenen Tasks das Proxmox-Task-Log mitmelden
Bisher stand im Fehlerfall nur der Exit-Status da ("cfs-lock ... error: got
lock request timeout"), nicht aber, was Proxmox davor protokolliert hat.
Fuer die Fehlersuche fehlte damit genau der interessante Teil.
* Schlaegt ein Task fehl, werden die letzten Zeilen des Task-Logs an die
Meldung angehaengt; identische Wiederholungen werden zusammengefasst
("trying to acquire cfs lock 'storage-data' ... (9x)").
* Die Meldung wiederholt nicht mehr VM und Snapshot-Namen, die der
Aufrufer ohnehin voranstellt.
Ausserdem ein Fehler in der Wiederholung: schlug der Task fehl, blieb der
Snapshot-Eintrag teils in der VM-Konfiguration stehen. Der zweite Versuch
lief dann in "snapshot already exists" - und diese Meldung verdeckte die
eigentliche Ursache. Ist der Snapshot bereits vorhanden, wird jetzt nicht
wiederholt und der urspruengliche Fehler gemeldet.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
e9aeaf9e62
commit
e26d966a8b
+45
-3
@@ -169,7 +169,14 @@ class Proxmox:
|
||||
log.info("[TESTLAUF] wuerde Snapshot anlegen: %s -> %s", guest.label, name)
|
||||
return None
|
||||
what = "Snapshot %s fuer %s" % (name, guest.label)
|
||||
return self._retry(what, lambda: self._task(guest, args, what))
|
||||
|
||||
def exists():
|
||||
try:
|
||||
return any(snap.name == name for snap in self.list_snapshots(guest))
|
||||
except ProxmoxError:
|
||||
return False
|
||||
|
||||
return self._retry(what, lambda: self._task(guest, args, what), skip_retry=exists)
|
||||
|
||||
def delete_snapshot(self, guest, name):
|
||||
if self.dry_run:
|
||||
@@ -204,7 +211,7 @@ class Proxmox:
|
||||
text = str(message).lower()
|
||||
return any(marker in text for marker in cls._TRANSIENT)
|
||||
|
||||
def _retry(self, what, action):
|
||||
def _retry(self, what, action, skip_retry=None):
|
||||
attempt = 0
|
||||
while True:
|
||||
try:
|
||||
@@ -212,6 +219,13 @@ class Proxmox:
|
||||
except ProxmoxError as exc:
|
||||
if attempt >= self.retries or not self._is_transient(exc):
|
||||
raise
|
||||
if skip_retry is not None and skip_retry():
|
||||
# Der Snapshot ist trotz Fehler schon da - ein zweiter
|
||||
# Versuch scheiterte nur an "already exists" und wuerde
|
||||
# die eigentliche Ursache verdecken.
|
||||
log.warning("%s: Snapshot ist trotz Fehler vorhanden - "
|
||||
"keine Wiederholung", what)
|
||||
raise
|
||||
attempt += 1
|
||||
log.warning("%s: %s - Versuch %d von %d in %ds",
|
||||
what, exc, attempt + 1, self.retries + 1, self.retry_delay)
|
||||
@@ -238,7 +252,9 @@ class Proxmox:
|
||||
if status.get("status") == "stopped":
|
||||
exit_status = status.get("exitstatus") or "unbekannt"
|
||||
if exit_status != "OK":
|
||||
raise ProxmoxError("%s fehlgeschlagen: %s" % (what, exit_status))
|
||||
# Nur die Ursache melden - wer und was, ergaenzt der Aufrufer.
|
||||
raise ProxmoxError("%s%s" % (exit_status,
|
||||
self._task_log_tail(guest.node, upid)))
|
||||
return upid
|
||||
if time.time() > deadline:
|
||||
raise ProxmoxError("%s: Zeitueberschreitung nach %ds (Task laeuft weiter: %s)"
|
||||
@@ -246,6 +262,32 @@ class Proxmox:
|
||||
time.sleep(delay)
|
||||
delay = min(delay * 1.5, 5.0)
|
||||
|
||||
def _task_log_tail(self, node, upid, lines=4):
|
||||
"""Die letzten Zeilen des Task-Logs - dort steht, woran es lag.
|
||||
|
||||
Wiederholungen wie "trying to acquire cfs lock ..." werden
|
||||
zusammengefasst, sonst besteht die Meldung nur noch daraus.
|
||||
"""
|
||||
try:
|
||||
entries = self._json(["get", "/nodes/%s/tasks/%s/log" % (node, upid),
|
||||
"--limit", "100"]) or []
|
||||
except ProxmoxError:
|
||||
return ""
|
||||
|
||||
texts = []
|
||||
for entry in entries:
|
||||
text = str(entry.get("t") or "").strip()
|
||||
if not text:
|
||||
continue
|
||||
if texts and texts[-1][0] == text:
|
||||
texts[-1][1] += 1
|
||||
else:
|
||||
texts.append([text, 1])
|
||||
|
||||
tail = ["%s%s" % (text, " (%dx)" % count if count > 1 else "")
|
||||
for text, count in texts[-lines:]]
|
||||
return " [Task-Log: %s]" % " | ".join(tail) if tail else ""
|
||||
|
||||
def _wait_unlocked(self, guest, timeout=None):
|
||||
"""Wartet, bis der Gast keine laufende Sperre mehr hat."""
|
||||
deadline = time.time() + (timeout or self.task_timeout)
|
||||
|
||||
Reference in New Issue
Block a user