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)
|
log.info("[TESTLAUF] wuerde Snapshot anlegen: %s -> %s", guest.label, name)
|
||||||
return None
|
return None
|
||||||
what = "Snapshot %s fuer %s" % (name, guest.label)
|
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):
|
def delete_snapshot(self, guest, name):
|
||||||
if self.dry_run:
|
if self.dry_run:
|
||||||
@@ -204,7 +211,7 @@ class Proxmox:
|
|||||||
text = str(message).lower()
|
text = str(message).lower()
|
||||||
return any(marker in text for marker in cls._TRANSIENT)
|
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
|
attempt = 0
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
@@ -212,6 +219,13 @@ class Proxmox:
|
|||||||
except ProxmoxError as exc:
|
except ProxmoxError as exc:
|
||||||
if attempt >= self.retries or not self._is_transient(exc):
|
if attempt >= self.retries or not self._is_transient(exc):
|
||||||
raise
|
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
|
attempt += 1
|
||||||
log.warning("%s: %s - Versuch %d von %d in %ds",
|
log.warning("%s: %s - Versuch %d von %d in %ds",
|
||||||
what, exc, attempt + 1, self.retries + 1, self.retry_delay)
|
what, exc, attempt + 1, self.retries + 1, self.retry_delay)
|
||||||
@@ -238,7 +252,9 @@ class Proxmox:
|
|||||||
if status.get("status") == "stopped":
|
if status.get("status") == "stopped":
|
||||||
exit_status = status.get("exitstatus") or "unbekannt"
|
exit_status = status.get("exitstatus") or "unbekannt"
|
||||||
if exit_status != "OK":
|
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
|
return upid
|
||||||
if time.time() > deadline:
|
if time.time() > deadline:
|
||||||
raise ProxmoxError("%s: Zeitueberschreitung nach %ds (Task laeuft weiter: %s)"
|
raise ProxmoxError("%s: Zeitueberschreitung nach %ds (Task laeuft weiter: %s)"
|
||||||
@@ -246,6 +262,32 @@ class Proxmox:
|
|||||||
time.sleep(delay)
|
time.sleep(delay)
|
||||||
delay = min(delay * 1.5, 5.0)
|
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):
|
def _wait_unlocked(self, guest, timeout=None):
|
||||||
"""Wartet, bis der Gast keine laufende Sperre mehr hat."""
|
"""Wartet, bis der Gast keine laufende Sperre mehr hat."""
|
||||||
deadline = time.time() + (timeout or self.task_timeout)
|
deadline = time.time() + (timeout or self.task_timeout)
|
||||||
|
|||||||
Reference in New Issue
Block a user