snapix/backend/backup_manager.py
2025-06-10 02:06:20 +03:00

126 lines
4.2 KiB
Python

import subprocess
import yaml
import tempfile
import time
def create_backup(namespace: str, pvc: str, backup_name: str):
temp_pvc_name = f"snapix-bkp-temp-{backup_name}"
pvc_manifest = {
"apiVersion": "v1",
"kind": "PersistentVolumeClaim",
"metadata": {"name": temp_pvc_name},
"spec": {
"accessModes": ["ReadWriteMany"],
"resources": {"requests": {"storage": "5Gi"}},
"storageClassName": "nfs-client"
}
}
with tempfile.NamedTemporaryFile("w", delete=False) as f:
yaml.dump(pvc_manifest, f)
pvc_file = f.name
subprocess.run(["kubectl", "apply", "-f", pvc_file, "-n", namespace], check=True)
for _ in range(30):
status = subprocess.check_output([
"kubectl", "get", "pvc", temp_pvc_name, "-n", namespace, "-o", "jsonpath={.status.phase}"
]).decode().strip()
if status == "Bound":
break
time.sleep(1)
else:
raise TimeoutError(f"PVC {temp_pvc_name} did not reach Bound state")
job_spec = {
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": {
"name": f"snapix-backup-{backup_name}",
"namespace": namespace
},
"spec": {
"template": {
"spec": {
"restartPolicy": "Never",
"containers": [
{
"name": "backup",
"image": "busybox",
"command": ["sh", "-c", f"mkdir -p /backup/{backup_name} && cp -r /source/* /backup/{backup_name}/"],
"volumeMounts": [
{"mountPath": "/source", "name": "source-vol"},
{"mountPath": "/backup", "name": "backup-vol"}
]
}
],
"volumes": [
{"name": "source-vol", "persistentVolumeClaim": {"claimName": pvc}},
{"name": "backup-vol", "persistentVolumeClaim": {"claimName": temp_pvc_name}}
]
}
}
}
}
try:
subprocess.run(
["kubectl", "apply", "-f", "-", "-n", namespace],
input=yaml.dump(job_spec).encode(),
check=True,
capture_output=True
)
except subprocess.CalledProcessError as e:
print("❌ kubectl apply failed:")
print(e.stderr.decode())
raise
def restore_backup(namespace: str, target_pvc: str, backup_name: str):
job_spec = {
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": {
"name": f"snapix-restore-{backup_name}",
"namespace": namespace
},
"spec": {
"template": {
"spec": {
"restartPolicy": "Never",
"containers": [
{
"name": "restore",
"image": "busybox",
"command": ["sh", "-c", f"cp -r /backup/{backup_name}/* /restore/"],
"volumeMounts": [
{"mountPath": "/restore", "name": "restore-vol"},
{"mountPath": "/backup", "name": "backup-vol"}
]
}
],
"volumes": [
{"name": "restore-vol", "persistentVolumeClaim": {"claimName": target_pvc}},
{"name": "backup-vol", "persistentVolumeClaim": {"claimName": f"snapix-bkp-temp-{backup_name}"}}
]
}
}
}
}
try:
subprocess.run(
["kubectl", "apply", "-f", "-", "-n", namespace],
input=yaml.dump(job_spec).encode(),
check=True,
capture_output=True
)
except subprocess.CalledProcessError as e:
print("❌ kubectl apply failed:")
print("STDOUT:\n", e.stdout.decode())
print("STDERR:\n", e.stderr.decode())
print("YAML:\n", yaml.dump(job_spec))
raise