fix: fallback to derive jobs from sessions when API fails

- veeam_client: try 6 URL variants (states/config with source/typeFilter),
  then legacy on 9419, then legacy on port 9398
- main.py: if jobs_data empty but sessions available, aggregate sessions
  by jobName to build synthetic job list with name/type/result/state
- Ensures jobs tab always shows data even when API has FileBackup enum bug
This commit is contained in:
2026-06-09 17:22:07 +07:00
parent ba8a413e85
commit 0689a46638
2 changed files with 48 additions and 6 deletions

21
main.py
View File

@@ -146,6 +146,27 @@ async def _collect_instance(inst) -> dict | None:
except Exception as e:
errors.append(f"sessions: {e}")
if not jobs_data and sessions_data:
job_map: dict[str, dict] = {}
for s in sessions_data:
name = s.get("jobName") or s.get("name") or s.get("Name") or ""
if not name:
continue
ts = s.get("endTime") or s.get("creationTime") or ""
if name not in job_map or ts > (job_map[name].get("_ts") or ""):
job_map[name] = {
"name": name,
"type": s.get("jobType") or s.get("type") or "",
"result": s.get("result") or "",
"state": s.get("state") or "",
"last_backup": ts,
"schedule_enabled": True,
"_ts": ts,
}
for j in job_map.values():
j.pop("_ts", None)
jobs_data = list(job_map.values())
try:
repos_data = await client.fetch_repositories()
except Exception as e:

View File

@@ -204,14 +204,35 @@ class VeeamClient:
async def fetch_jobs(self) -> list[dict]:
if self._is_v12():
last_err = None
for url in ("/api/v1/jobs/states", "/api/v1/jobs", "/api/v1/jobs/states?typeFilter=Backup"):
for path in (
"/api/v1/jobs/states",
"/api/v1/jobs",
"/api/v1/jobs/states?source=Backup",
"/api/v1/jobs?source=Backup",
"/api/v1/jobs/states?typeFilter=Backup",
"/api/v1/jobs?typeFilter=Backup",
):
try:
return await self._fetch_json_list(url)
except Exception as e:
last_err = e
return await self._fetch_json_list(path)
except Exception:
continue
raise ConnectionError(f"all job endpoints failed: {last_err}")
try:
return await self._fetch_legacy_jobs()
except Exception:
pass
try:
legacy_url = f"https://{self.host}:9398/api/jobs"
resp = await self._http.get(legacy_url, headers={"Accept": "application/json"})
if resp.status_code < 400:
data = self._parse(resp)
jobs = data.get("Jobs") or data.get("jobs") or data.get("Refs", {}).get("Job") or []
if isinstance(jobs, dict):
jobs = [jobs]
if jobs:
return [self._normalize_legacy_job(j) for j in jobs]
except Exception:
pass
raise ConnectionError("all job endpoints failed (v12 REST + legacy XML)")
return await self._fetch_legacy_jobs()
async def fetch_sessions(self, limit: int = 50) -> list[dict]: