Celestino Rey 10 месяцев назад
Родитель
Сommit
ea7f5d8a3d
4 измененных файлов с 74 добавлено и 4 удалено
  1. 3 0
      README.md
  2. 11 0
      app/main.py
  3. 47 4
      static/app.js
  4. 13 0
      static/index.html

+ 3 - 0
README.md

@@ -7,6 +7,7 @@ Una API REST y interfaz web para gestionar máquinas virtuales en Ubuntu usando
 - **Gestión completa de VMs**: Crear, listar, iniciar, detener y eliminar máquinas virtuales.
 - **Configuración de arranque**: Cambiar el orden de arranque de las VMs (disco duro, CD-ROM, etc.).
 - **Subida de ISOs**: Sube imágenes ISO directamente desde la interfaz web para usar en la creación de VMs.
+- **Gestión de ISOs**: Lista y elimina ISOs subidas.
 
 ## Instalación
 
@@ -132,6 +133,7 @@ export LIBVIRT_IMAGES_PATH=/ruta/a/imagenes
 - `GET /isos`: Lista todas las ISOs subidas.
 - `POST /upload-iso`: Sube un archivo ISO.
   - Body: Archivo multipart (`file`).
+- `DELETE /isos/{iso_name}`: Elimina una ISO por nombre.
 
 ### Consola
 
@@ -145,6 +147,7 @@ Accede a `http://localhost:8000` en tu navegador.
 - **Crear VM**: Formulario para especificar nombre, memoria, disco e ISO (seleccionar de ISOs subidas).
 - **Set Boot Order**: Selecciona una VM y define el orden de arranque (ej. "hd,cdrom").
 - **Upload ISO**: Sube archivos ISO para usar en la creación de VMs.
+- **Manage ISOs**: Tabla con ISOs subidas, opción para eliminar.
 - **Consola**: Botón para abrir la consola web en una nueva pestaña (solo para VMs corriendo).
 
 ## Documentación de la API

+ 11 - 0
app/main.py

@@ -257,6 +257,17 @@ async def upload_iso(file: UploadFile = File(...)):
             f.write(chunk)
     return {"message": f"ISO {file.filename} uploaded successfully", "path": file_path}
 
+@app.delete("/isos/{iso_name}")
+async def delete_iso(iso_name: str):
+    images_path = os.environ.get('LIBVIRT_IMAGES_PATH', '/mnt/vms/images')
+    iso_dir = f"{images_path}/isos"
+    file_path = os.path.join(iso_dir, iso_name)
+    if os.path.exists(file_path) and iso_name.endswith('.iso'):
+        os.remove(file_path)
+        return {"message": f"ISO {iso_name} deleted successfully"}
+    else:
+        return {"error": "ISO not found or invalid"}
+
 @app.post("/disks")
 async def create_disk(name: str, size: int):
     images_path = os.environ.get('LIBVIRT_IMAGES_PATH', '/var/lib/libvirt/images')

+ 47 - 4
static/app.js

@@ -10,7 +10,49 @@ function getStateClass(state) {
     }
 }
 
-async function loadIsos() {
+async function loadISOs() {
+    try {
+        const response = await fetch(`${API_BASE}/isos`);
+        const data = await response.json();
+        const tbody = document.getElementById('isoTableBody');
+        tbody.innerHTML = '';
+        
+        data.isos.forEach(iso => {
+            const row = document.createElement('tr');
+            row.innerHTML = `
+                <td>${iso.name}</td>
+                <td>
+                    <button class="btn btn-sm btn-danger" onclick="deleteISO('${iso.name}')">Delete</button>
+                </td>
+            `;
+            tbody.appendChild(row);
+        });
+    } catch (error) {
+        console.error('Error loading ISOs:', error);
+        alert('Error loading ISOs');
+    }
+}
+
+async function deleteISO(name) {
+    if (confirm(`Delete ISO ${name}?`)) {
+        try {
+            const response = await fetch(`${API_BASE}/isos/${name}`, { method: 'DELETE' });
+            const result = await response.json();
+            if (response.ok) {
+                alert(result.message);
+                loadISOs();
+                loadISOsForSelect();  // Refresh the select
+            } else {
+                alert(result.error);
+            }
+        } catch (error) {
+            console.error('Error deleting ISO:', error);
+            alert('Error deleting ISO');
+        }
+    }
+}
+
+async function loadISOsForSelect() {
     try {
         const response = await fetch(`${API_BASE}/isos`);
         const data = await response.json();
@@ -49,7 +91,7 @@ async function loadVMs() {
             tbody.appendChild(row);
             select.innerHTML += `<option value="${vm.name}">${vm.name}</option>`;
         });
-        loadIsos();  // Load ISOs after loading VMs
+        loadISOsForSelect();  // Load ISOs after loading VMs
     } catch (error) {
         console.error('Error loading VMs:', error);
         alert('Error loading VMs');
@@ -181,7 +223,7 @@ document.getElementById('uploadIsoForm').addEventListener('submit', async (e) =>
         const result = await response.json();
         if (response.ok) {
             alert(result.message);
-            loadIsos();  // Refresh ISO list
+            loadISOsForSelect();  // Refresh ISO list
             document.getElementById('uploadIsoForm').reset();
         } else {
             alert(result.error || 'Error uploading ISO');
@@ -193,4 +235,5 @@ document.getElementById('uploadIsoForm').addEventListener('submit', async (e) =>
 });
 
 // Load VMs on page load
-loadVMs();
+loadVMs();
+loadISOs();

+ 13 - 0
static/index.html

@@ -75,6 +75,19 @@
                     </div>
                     <button type="submit" class="btn btn-secondary">Upload ISO</button>
                 </form>
+                
+                <h2 class="mt-4">Manage ISOs</h2>
+                <button class="btn btn-info mb-3" onclick="loadISOs()">Refresh ISOs</button>
+                <table class="table table-striped" id="isoTable">
+                    <thead>
+                        <tr>
+                            <th>Name</th>
+                            <th>Actions</th>
+                        </tr>
+                    </thead>
+                    <tbody id="isoTableBody">
+                    </tbody>
+                </table>
             </div>
         </div>
     </div>