Initial pve cloud backup app

This commit is contained in:
Codex
2026-07-15 01:00:08 +02:00
commit 7a4c561f8e
37 changed files with 5495 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
set -euo pipefail
INSTALL_DIR="/opt/pve-cloud-backup"
BACKEND_DIR="$INSTALL_DIR/backend"
FRONTEND_DIR="$INSTALL_DIR/frontend"
STATIC_DIR="$INSTALL_DIR/static"
DATA_DIR="$INSTALL_DIR/data"
LOG_DIR="$INSTALL_DIR/logs"
if [[ "$(id -u)" -ne 0 ]]; then
echo "Run as root. The services need pvesh access and systemd installation." >&2
exit 1
fi
if [[ ! -d "$INSTALL_DIR" ]]; then
echo "$INSTALL_DIR does not exist. Copy the application files there first." >&2
exit 1
fi
mkdir -p "$BACKEND_DIR" "$FRONTEND_DIR" "$STATIC_DIR" "$DATA_DIR" "$LOG_DIR" "$INSTALL_DIR/scripts"
command -v python3 >/dev/null || { echo "python3 is required" >&2; exit 1; }
command -v npm >/dev/null || { echo "npm is required to build the Vue frontend" >&2; exit 1; }
python3 -m venv "$BACKEND_DIR/.venv"
"$BACKEND_DIR/.venv/bin/pip" install --upgrade pip
"$BACKEND_DIR/.venv/bin/pip" install -r "$BACKEND_DIR/requirements.txt"
cd "$FRONTEND_DIR"
if [[ -f package-lock.json ]]; then
npm ci
else
npm install
fi
npm run build
cd "$BACKEND_DIR"
"$BACKEND_DIR/.venv/bin/python" -c 'from app.migrations import run_migrations; run_migrations()'
install -m 0644 "$INSTALL_DIR/systemd/pve-cloud-backup-web.service" /etc/systemd/system/pve-cloud-backup-web.service
install -m 0644 "$INSTALL_DIR/systemd/pve-cloud-backup-worker.service" /etc/systemd/system/pve-cloud-backup-worker.service
systemctl daemon-reload
systemctl enable --now pve-cloud-backup-web.service
systemctl enable --now pve-cloud-backup-worker.service
echo "Installed. Open http://<server>:8080 and complete the setup wizard."
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env bash
set -euo pipefail
API_URL="${API_URL:-http://127.0.0.1:8080}"
python3 - "$API_URL" <<'PY'
import json
import sys
import urllib.error
import urllib.request
api = sys.argv[1].rstrip("/")
def request(method, path, body=None):
data = None if body is None else json.dumps(body).encode()
req = urllib.request.Request(
api + path,
data=data,
method=method,
headers={"Content-Type": "application/json"},
)
try:
with urllib.request.urlopen(req, timeout=30) as res:
return json.loads(res.read().decode())
except urllib.error.HTTPError as exc:
raise SystemExit(f"{method} {path} failed: {exc.code} {exc.read().decode()}") from exc
settings = request("GET", "/api/settings")
if settings.get("proxmox_storage") != "hitachi":
raise SystemExit("Expected configured Proxmox storage to be 'hitachi'")
if settings.get("local_backup_dir") != "/mnt/pve/hitachi/dump":
raise SystemExit("Expected configured local backup directory to be '/mnt/pve/hitachi/dump'")
guests = request("GET", "/api/guests")
guest = next((g for g in guests if int(g["vmid"]) == 110 and g["name"] == "adguard"), None)
if not guest:
raise SystemExit("Expected Proxmox guest adguard with VMID 110")
job = request("POST", "/api/jobs", {
"guest_vmid": 110,
"guest_name": "adguard",
"guest_type": guest["type"],
"node": guest["node"],
"enabled": False,
"cron_schedule": "0 3 * * *",
"proxmox_storage": "hitachi",
"backup_mode": settings["default_backup_mode"],
"compression": settings["default_compression"],
"retention_type": "days",
"retention_value": 1,
})
backup = request("POST", f"/api/jobs/{job['id']}/run")
print(json.dumps({"job": job, "queued_backup": backup}, indent=2))
print("Queued integration backup for adguard VMID 110 on storage hitachi (/mnt/pve/hitachi/dump). Expected archive size is approximately 250 MB.")
PY
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -euo pipefail
INSTALL_DIR="/opt/pve-cloud-backup"
if [[ "$(id -u)" -ne 0 ]]; then
echo "Run as root." >&2
exit 1
fi
systemctl disable --now pve-cloud-backup-worker.service 2>/dev/null || true
systemctl disable --now pve-cloud-backup-web.service 2>/dev/null || true
rm -f /etc/systemd/system/pve-cloud-backup-worker.service
rm -f /etc/systemd/system/pve-cloud-backup-web.service
systemctl daemon-reload
echo "Services removed."
echo "Application data remains at $INSTALL_DIR. Remove it manually only after confirming backups and app.db are no longer needed."