diff --git a/backend/__pycache__/k8s_utils.cpython-313.pyc b/backend/__pycache__/k8s_utils.cpython-313.pyc index f659c94..06e2aff 100644 Binary files a/backend/__pycache__/k8s_utils.cpython-313.pyc and b/backend/__pycache__/k8s_utils.cpython-313.pyc differ diff --git a/backend/__pycache__/main.cpython-313.pyc b/backend/__pycache__/main.cpython-313.pyc index 50ff6b0..ed4509a 100644 Binary files a/backend/__pycache__/main.cpython-313.pyc and b/backend/__pycache__/main.cpython-313.pyc differ diff --git a/backend/k8s_utils.py b/backend/k8s_utils.py index cc4c116..7791aac 100644 --- a/backend/k8s_utils.py +++ b/backend/k8s_utils.py @@ -1,5 +1,6 @@ import subprocess import json +import re def get_namespaces(): output = subprocess.check_output(["kubectl", "get", "ns", "-o", "json"]) @@ -10,3 +11,18 @@ def get_pvcs(namespace: str): output = subprocess.check_output(["kubectl", "get", "pvc", "-n", namespace, "-o", "json"]) data = json.loads(output) return [item["metadata"]["name"] for item in data["items"]] + +def get_all_backup_pvcs(): + output = subprocess.check_output(["kubectl", "get", "pvc", "-A", "-o", "json"]) + data = json.loads(output) + + backup_pvcs = [] + for item in data["items"]: + name = item["metadata"]["name"] + namespace = item["metadata"]["namespace"] + if re.match(r"^snapix-bkp-temp-", name): + backup_pvcs.append({ + "name": name, + "namespace": namespace + }) + return backup_pvcs \ No newline at end of file diff --git a/backend/main.py b/backend/main.py index 5beb868..2cf658d 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,7 +1,7 @@ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from models import BackupRequest, RestoreRequest -from k8s_utils import get_namespaces, get_pvcs +from k8s_utils import get_namespaces, get_pvcs, get_all_backup_pvcs from backup_manager import create_backup, restore_backup app = FastAPI() @@ -33,6 +33,11 @@ def restore_pvc(request: RestoreRequest): return {"message": "Restore job created."} +@app.get("/backup-pvcs") +def list_backup_pvcs(): + return get_all_backup_pvcs() + + if __name__ == "__main__": import uvicorn uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True) \ No newline at end of file diff --git a/frontend/src/api/snapix.js b/frontend/src/api/snapix.js index 3232d23..00cda1c 100644 --- a/frontend/src/api/snapix.js +++ b/frontend/src/api/snapix.js @@ -8,3 +8,5 @@ export const getNamespaces = () => api.get('/namespaces'); export const getPVCs = (namespace) => api.get(`/pvcs/${namespace}`); export const createBackup = (payload) => api.post('/backup', payload); export const restoreBackup = (payload) => api.post('/restore', payload); +export const getBackupPVCs = () => api.get('/backup-pvcs'); + diff --git a/frontend/src/components/RestoreForm.jsx b/frontend/src/components/RestoreForm.jsx index 57ad21a..7751662 100644 --- a/frontend/src/components/RestoreForm.jsx +++ b/frontend/src/components/RestoreForm.jsx @@ -1,12 +1,30 @@ -import { useState } from 'react'; -import { restoreBackup } from '../api/snapix'; -import { Button, Input } from '@mui/base' -import '../style/RestoreForm.css'; // Assuming you have some styles for the form +import { useEffect, useState } from 'react'; +import { restoreBackup, getNamespaces, getBackupPVCs } from '../api/snapix'; +import { Button } from '@mui/base'; +import '../style/RestoreForm.css'; export default function RestoreForm() { const [backupName, setBackupName] = useState(''); const [targetNs, setTargetNs] = useState(''); const [targetPvc, setTargetPvc] = useState(''); + const [namespaces, setNamespaces] = useState([]); + const [backupPvcs, setBackupPvcs] = useState([]); + + useEffect(() => { + getNamespaces().then(res => setNamespaces(res.data)); + }, []); + + useEffect(() => { + if (targetNs) { + getBackupPVCs().then(res => { + // Filter backup PVCs only for the selected namespace + const filtered = res.data.filter(pvc => pvc.namespace === targetNs); + setBackupPvcs(filtered); + }); + } else { + setBackupPvcs([]); + } + }, [targetNs]); const handleRestore = () => { if (backupName && targetNs && targetPvc) { @@ -15,45 +33,52 @@ export default function RestoreForm() { target_namespace: targetNs, target_pvc: targetPvc, }).then(() => { - alert("Restore started!"); + alert('Restore started!'); }); } }; return ( -
+

🔁 Restore PVC

-
- - + + +
+ +
+ +
-
- - setTargetNs(e.target.value)} - className='restore-input' - /> -
- -
- - + + setTargetPvc(e.target.value)} - className='restore-input' + placeholder="the exact name of the pvc of your app" />
- +
); }