Просмотр исходного кода

Opción para subir imágenes iso

Celestino Rey 10 месяцев назад
Родитель
Сommit
4d2d5f6fb3
5 измененных файлов с 106 добавлено и 12 удалено
  1. 15 5
      README.md
  2. 25 3
      app/main.py
  3. 2 1
      requirements.txt
  4. 52 2
      static/app.js
  5. 12 1
      static/index.html

+ 15 - 5
README.md

@@ -6,10 +6,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.).
-- **Consola web**: Acceso a la consola de las VMs vía navegador usando noVNC, sin necesidad de clientes VNC locales.
-- **Interfaz web intuitiva**: Interfaz basada en Bootstrap para gestionar VMs fácilmente.
-- **Auto-inicio**: Servicio systemd para que la aplicación se inicie automáticamente con el sistema.
-- **Documentación interactiva**: API documentada con Swagger UI.
+- **Subida de ISOs**: Sube imágenes ISO directamente desde la interfaz web para usar en la creación de VMs.
 
 ## Instalación
 
@@ -22,6 +19,12 @@ sudo apt update
 sudo apt install -y libvirt-daemon-system libvirt-dev pkg-config python3-libvirt python3-gi novnc websockify
 ```
 
+Crea el directorio para ISOs (opcional, se crea automáticamente):
+
+```bash
+sudo mkdir -p /var/lib/libvirt/images/isos
+```
+
 ### Instalación del Proyecto
 
 1. Clona o descarga el proyecto en `/home/creylopez/virtmanager` (o ajusta las rutas según corresponda).
@@ -124,6 +127,12 @@ export LIBVIRT_IMAGES_PATH=/ruta/a/imagenes
   - `name`: Nombre del archivo (sin extensión).
   - `size`: Tamaño en GB.
 
+### ISOs
+
+- `GET /isos`: Lista todas las ISOs subidas.
+- `POST /upload-iso`: Sube un archivo ISO.
+  - Body: Archivo multipart (`file`).
+
 ### Consola
 
 - `GET /console/{vm_name}`: Obtiene la URL para la consola web noVNC de la VM.
@@ -133,8 +142,9 @@ export LIBVIRT_IMAGES_PATH=/ruta/a/imagenes
 Accede a `http://localhost:8000` en tu navegador.
 
 - **Lista de VMs**: Tabla con estado (badges coloreados), acciones (iniciar/detener/eliminar/consola).
-- **Crear VM**: Formulario para especificar nombre, memoria, disco e ISO.
+- **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.
 - **Consola**: Botón para abrir la consola web en una nueva pestaña (solo para VMs corriendo).
 
 ## Documentación de la API

+ 25 - 3
app/main.py

@@ -1,4 +1,4 @@
-from fastapi import FastAPI
+from fastapi import FastAPI, UploadFile, File
 from fastapi.staticfiles import StaticFiles
 from fastapi.responses import FileResponse
 import os
@@ -84,9 +84,11 @@ async def stop_vm(vm_name: str):
 
 @app.post("/vms")
 async def create_vm(name: str, memory: int, disk_size: int, iso: str):
-    images_path = os.environ.get('LIBVIRT_IMAGES_PATH', '/var/lib/libvirt/images')
+    if not iso:
+        return {"error": "ISO path is required"}
+    images_path = os.environ.get('LIBVIRT_IMAGES_PATH', '/mnt/vms/images')
     disk_path = f"{images_path}/{name}.qcow2"
-    iso_path = f"{images_path}/{iso}"
+    iso_path = iso  # iso ya es la ruta completa desde el select
     
     print(f"Using ISO path: {iso_path}")
     
@@ -235,6 +237,26 @@ async def set_boot_order(vm_name: str, boot_order: BootOrder):
     except Exception as e:
         return {"error": str(e)}
 
+@app.get("/isos")
+async def list_isos():
+    images_path = os.environ.get('LIBVIRT_IMAGES_PATH', '/mnt/vms/images')
+    iso_dir = f"{images_path}/isos"
+    if os.path.exists(iso_dir):
+        isos = [{"name": f, "path": os.path.join(iso_dir, f)} for f in os.listdir(iso_dir) if f.endswith('.iso')]
+        return {"isos": isos}
+    return {"isos": []}
+
+@app.post("/upload-iso")
+async def upload_iso(file: UploadFile = File(...)):
+    images_path = os.environ.get('LIBVIRT_IMAGES_PATH', '/mnt/vms/images')
+    iso_dir = f"{images_path}/isos"
+    os.makedirs(iso_dir, exist_ok=True)
+    file_path = os.path.join(iso_dir, file.filename)
+    with open(file_path, "wb") as f:
+        while chunk := await file.read(1024 * 1024):  # Read in 1MB chunks
+            f.write(chunk)
+    return {"message": f"ISO {file.filename} uploaded successfully", "path": file_path}
+
 @app.post("/disks")
 async def create_disk(name: str, size: int):
     images_path = os.environ.get('LIBVIRT_IMAGES_PATH', '/var/lib/libvirt/images')

+ 2 - 1
requirements.txt

@@ -1,2 +1,3 @@
 fastapi
-uvicorn[standard]
+uvicorn[standard]
+python-multipart

+ 52 - 2
static/app.js

@@ -10,6 +10,20 @@ function getStateClass(state) {
     }
 }
 
+async function loadIsos() {
+    try {
+        const response = await fetch(`${API_BASE}/isos`);
+        const data = await response.json();
+        const select = document.getElementById('iso');
+        select.innerHTML = '<option value="">Select ISO</option>';
+        data.isos.forEach(iso => {
+            select.innerHTML += `<option value="${iso.path}">${iso.name}</option>`;
+        });
+    } catch (error) {
+        console.error('Error loading ISOs:', error);
+    }
+}
+
 async function loadVMs() {
     try {
         const response = await fetch(`${API_BASE}/vms`);
@@ -35,6 +49,7 @@ async function loadVMs() {
             tbody.appendChild(row);
             select.innerHTML += `<option value="${vm.name}">${vm.name}</option>`;
         });
+        loadIsos();  // Load ISOs after loading VMs
     } catch (error) {
         console.error('Error loading VMs:', error);
         alert('Error loading VMs');
@@ -100,13 +115,18 @@ document.getElementById('createVMForm').addEventListener('submit', async (e) =>
         const response = await fetch(`${API_BASE}/vms?name=${name}&memory=${memory}&disk_size=${disk_size}&iso=${iso}`, {
             method: 'POST'
         });
-        const result = await response.json();
+        let result;
+        try {
+            result = await response.json();
+        } catch {
+            result = { error: 'Unknown error' };
+        }
         if (response.ok) {
             alert(result.message);
             loadVMs();
             document.getElementById('createVMForm').reset();
         } else {
-            alert(result.error);
+            alert(result.error || 'Error creating VM');
         }
     } catch (error) {
         console.error('Error creating VM:', error);
@@ -142,5 +162,35 @@ document.getElementById('setBootOrderForm').addEventListener('submit', async (e)
     }
 });
 
+document.getElementById('uploadIsoForm').addEventListener('submit', async (e) => {
+    e.preventDefault();
+    const fileInput = document.getElementById('isoFile');
+    const file = fileInput.files[0];
+    if (!file) {
+        alert('Please select a file');
+        return;
+    }
+    const formData = new FormData();
+    formData.append('file', file);
+    
+    try {
+        const response = await fetch(`${API_BASE}/upload-iso`, {
+            method: 'POST',
+            body: formData
+        });
+        const result = await response.json();
+        if (response.ok) {
+            alert(result.message);
+            loadIsos();  // Refresh ISO list
+            document.getElementById('uploadIsoForm').reset();
+        } else {
+            alert(result.error || 'Error uploading ISO');
+        }
+    } catch (error) {
+        console.error('Error uploading ISO:', error);
+        alert('Error uploading ISO');
+    }
+});
+
 // Load VMs on page load
 loadVMs();

+ 12 - 1
static/index.html

@@ -45,7 +45,9 @@
                     </div>
                     <div class="mb-3">
                         <label for="iso" class="form-label">ISO File</label>
-                        <input type="text" class="form-control" id="iso" required>
+                        <select class="form-control" id="iso" required>
+                            <option value="">Select ISO</option>
+                        </select>
                     </div>
                     <button type="submit" class="btn btn-success">Create VM</button>
                 </form>
@@ -64,6 +66,15 @@
                     </div>
                     <button type="submit" class="btn btn-warning">Set Boot Order</button>
                 </form>
+                
+                <h2 class="mt-4">Upload ISO</h2>
+                <form id="uploadIsoForm" enctype="multipart/form-data">
+                    <div class="mb-3">
+                        <label for="isoFile" class="form-label">Select ISO File</label>
+                        <input type="file" class="form-control" id="isoFile" accept=".iso" required>
+                    </div>
+                    <button type="submit" class="btn btn-secondary">Upload ISO</button>
+                </form>
             </div>
         </div>
     </div>