Spaces:
Sleeping
Sleeping
| import hashlib | |
| import os | |
| from datetime import datetime, timezone | |
| from typing import Dict | |
| from .utils import load_json, save_json | |
| BACKUPS_PATH = os.path.join(os.path.dirname(__file__), "..", "..", "infra", "backups.json") | |
| def _timestamp() -> str: | |
| return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") | |
| def _new_hash(device: str, timestamp: str) -> str: | |
| return hashlib.sha256(f"{device}-{timestamp}".encode()).hexdigest()[:8] | |
| def oob_get_last_backup(device: str) -> Dict: | |
| backups = load_json(BACKUPS_PATH) | |
| info = backups.get(device) | |
| if not info: | |
| return { | |
| "device": device, | |
| "last_backup_at": None, | |
| "config_hash": None, | |
| "snapshots": [], | |
| "risk": "high", # no backup means risky | |
| "message": "No backup found.", | |
| } | |
| age_msg = "Backup present" | |
| if info.get("last_backup_at"): | |
| age_msg = f"Last backup at {info['last_backup_at']}" | |
| risk = "low" | |
| # Optionally adjust risk based on recency; for now simple heuristic. | |
| return { | |
| "device": device, | |
| "last_backup_at": info.get("last_backup_at"), | |
| "config_hash": info.get("config_hash"), | |
| "snapshots": info.get("snapshots", []), | |
| "risk": risk, | |
| "message": age_msg, | |
| } | |
| def oob_perform_backup(device: str) -> Dict: | |
| backups = load_json(BACKUPS_PATH) | |
| now = _timestamp() | |
| cfg_hash = _new_hash(device, now) | |
| entry = backups.get(device, { | |
| "last_backup_at": None, | |
| "config_hash": None, | |
| "snapshots": [], | |
| }) | |
| entry.update({ | |
| "last_backup_at": now, | |
| "config_hash": cfg_hash, | |
| }) | |
| entry.setdefault("snapshots", []).append(cfg_hash) | |
| backups[device] = entry | |
| save_json(BACKUPS_PATH, backups) | |
| return { | |
| "device": device, | |
| "last_backup_at": now, | |
| "config_hash": cfg_hash, | |
| "snapshots": entry["snapshots"], | |
| "message": "Backup completed (simulated).", | |
| } | |