Quellcode durchsuchen

Cambio orden de arranque. Parar y arrancar por nombre

Celestino Rey vor 7 Monaten
Ursprung
Commit
9c5b25491c
3 geänderte Dateien mit 96 neuen und 25 gelöschten Zeilen
  1. 44 19
      app/main.py
  2. 37 6
      static/app.js
  3. 15 0
      static/index.html

+ 44 - 19
app/main.py

@@ -7,6 +7,7 @@ import subprocess
 import random
 import xml.etree.ElementTree as ET
 import socket
+from pydantic import BaseModel
 
 app = FastAPI(title="VirtManager API", description="API for managing virtual machines")
 
@@ -32,6 +33,9 @@ def get_state_string(state_code):
     }
     return states.get(state_code, "unknown")
 
+class BootOrder(BaseModel):
+    order: list[str]
+
 # Connect to libvirt
 conn = libvirt.open('qemu:///system')
 
@@ -60,25 +64,23 @@ async def list_vms():
         })
     return {"vms": vms}
 
-@app.get("/vms/{vm_id}/start")
-async def start_vm(vm_id: int):
-    # try:
-    #     domain = conn.lookupByID(vm_id)
-    #     domain.create()
-    #     return {"message": f"VM {vm_id} started"}
-    # except Exception as e:
-    #     return {"error": str(e)}
-    return {"message": f"VM {vm_id} started (mock)"}
-
-@app.get("/vms/{vm_id}/stop")
-async def stop_vm(vm_id: int):
-    # try:
-    #     domain = conn.lookupByID(vm_id)
-    #     domain.destroy()
-    #     return {"message": f"VM {vm_id} stopped"}
-    # except Exception as e:
-    #     return {"error": str(e)}
-    return {"message": f"VM {vm_id} stopped (mock)"}
+@app.get("/vms/{vm_name}/start")
+async def start_vm(vm_name: str):
+    try:
+        domain = conn.lookupByName(vm_name)
+        domain.create()
+        return {"message": f"VM {vm_name} started"}
+    except Exception as e:
+        return {"error": str(e)}
+
+@app.get("/vms/{vm_name}/stop")
+async def stop_vm(vm_name: str):
+    try:
+        domain = conn.lookupByName(vm_name)
+        domain.destroy()
+        return {"message": f"VM {vm_name} stopped"}
+    except Exception as e:
+        return {"error": str(e)}
 
 @app.post("/vms")
 async def create_vm(name: str, memory: int, disk_size: int, iso: str):
@@ -210,6 +212,29 @@ async def delete_vm(vm_name: str):
     except Exception as e:
         return {"error": str(e)}
 
+@app.put("/vms/{vm_name}/boot-order")
+async def set_boot_order(vm_name: str, boot_order: BootOrder):
+    try:
+        domain = conn.lookupByName(vm_name)
+        if domain.isActive():
+            return {"error": "VM must be shut off to change boot order"}
+        xml_desc = domain.XMLDesc()
+        root = ET.fromstring(xml_desc)
+        os_section = root.find("os")
+        # Remove existing boot elements
+        for boot in os_section.findall("boot"):
+            os_section.remove(boot)
+        # Add new boot elements
+        for dev in boot_order.order:
+            ET.SubElement(os_section, "boot", {"dev": dev})
+        new_xml = ET.tostring(root, encoding='unicode')
+        # Undefine and redefine
+        domain.undefine()
+        new_domain = conn.defineXML(new_xml)
+        return {"message": f"Boot order for {vm_name} updated to {boot_order.order}"}
+    except Exception as e:
+        return {"error": str(e)}
+
 @app.post("/disks")
 async def create_disk(name: str, size: int):
     images_path = os.environ.get('LIBVIRT_IMAGES_PATH', '/var/lib/libvirt/images')

+ 37 - 6
static/app.js

@@ -6,6 +6,8 @@ async function loadVMs() {
         const data = await response.json();
         const tbody = document.getElementById('vmTableBody');
         tbody.innerHTML = '';
+        const select = document.getElementById('bootVM');
+        select.innerHTML = '<option value="">Select VM</option>';
         
         data.vms.forEach(vm => {
             const row = document.createElement('tr');
@@ -14,13 +16,14 @@ async function loadVMs() {
                 <td>${vm.name}</td>
                 <td>${vm.state}</td>
                 <td>
-                    <button class="btn btn-sm btn-success" onclick="startVM(${vm.id})">Lanzar</button>
-                    <button class="btn btn-sm btn-warning" onclick="stopVM(${vm.id})">Stop</button>
+                    <button class="btn btn-sm btn-success" onclick="startVM('${vm.name}')">Lanzar</button>
+                    <button class="btn btn-sm btn-warning" onclick="stopVM('${vm.name}')">Stop</button>
                     <button class="btn btn-sm btn-danger" onclick="deleteVM('${vm.name}')">Delete</button>
                     ${vm.vnc_port ? `<button class="btn btn-sm btn-info" onclick="openVNC('${vm.name}')">Console</button>` : ''}
                 </td>
             `;
             tbody.appendChild(row);
+            select.innerHTML += `<option value="${vm.name}">${vm.name}</option>`;
         });
     } catch (error) {
         console.error('Error loading VMs:', error);
@@ -28,9 +31,9 @@ async function loadVMs() {
     }
 }
 
-async function startVM(id) {
+async function startVM(name) {
     try {
-        await fetch(`${API_BASE}/vms/${id}/start`);
+        await fetch(`${API_BASE}/vms/${name}/start`);
         loadVMs();
     } catch (error) {
         console.error('Error starting VM:', error);
@@ -38,9 +41,9 @@ async function startVM(id) {
     }
 }
 
-async function stopVM(id) {
+async function stopVM(name) {
     try {
-        await fetch(`${API_BASE}/vms/${id}/stop`);
+        await fetch(`${API_BASE}/vms/${name}/stop`);
         loadVMs();
     } catch (error) {
         console.error('Error stopping VM:', error);
@@ -101,5 +104,33 @@ document.getElementById('createVMForm').addEventListener('submit', async (e) =>
     }
 });
 
+document.getElementById('setBootOrderForm').addEventListener('submit', async (e) => {
+    e.preventDefault();
+    const vm_name = document.getElementById('bootVM').value;
+    const boot_order_str = document.getElementById('bootOrder').value;
+    const order = boot_order_str.split(',').map(s => s.trim());
+    
+    try {
+        const response = await fetch(`${API_BASE}/vms/${vm_name}/boot-order`, {
+            method: 'PUT',
+            headers: {
+                'Content-Type': 'application/json'
+            },
+            body: JSON.stringify({ order: order })
+        });
+        const result = await response.json();
+        if (response.ok) {
+            alert(result.message);
+            loadVMs();
+            document.getElementById('setBootOrderForm').reset();
+        } else {
+            alert(result.error);
+        }
+    } catch (error) {
+        console.error('Error setting boot order:', error);
+        alert('Error setting boot order');
+    }
+});
+
 // Load VMs on page load
 loadVMs();

+ 15 - 0
static/index.html

@@ -49,6 +49,21 @@
                     </div>
                     <button type="submit" class="btn btn-success">Create VM</button>
                 </form>
+                
+                <h2 class="mt-4">Set Boot Order</h2>
+                <form id="setBootOrderForm">
+                    <div class="mb-3">
+                        <label for="bootVM" class="form-label">VM Name</label>
+                        <select class="form-control" id="bootVM" required>
+                            <option value="">Select VM</option>
+                        </select>
+                    </div>
+                    <div class="mb-3">
+                        <label for="bootOrder" class="form-label">Boot Order (comma separated, e.g. hd,cdrom)</label>
+                        <input type="text" class="form-control" id="bootOrder" placeholder="hd,cdrom" required>
+                    </div>
+                    <button type="submit" class="btn btn-warning">Set Boot Order</button>
+                </form>
             </div>
         </div>
     </div>