| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- from fastapi import FastAPI
- from fastapi.staticfiles import StaticFiles
- from fastapi.responses import FileResponse
- import os
- import libvirt
- import subprocess
- import random
- app = FastAPI(title="VirtManager API", description="API for managing virtual machines")
- app.mount("/static", StaticFiles(directory="static"), name="static")
- # Connect to libvirt
- conn = libvirt.open('qemu:///system')
- @app.get("/")
- async def root():
- return FileResponse("static/index.html")
- @app.get("/vms")
- async def list_vms():
- domains = conn.listAllDomains()
- vms = []
- for domain in domains:
- vms.append({
- "id": domain.ID(),
- "name": domain.name(),
- "state": domain.state()[0]
- })
- 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.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')
- disk_path = f"{images_path}/{name}.qcow2"
- iso_path = f"{images_path}/{iso}"
-
- print(f"Using ISO path: {iso_path}")
-
- # Create disk
- try:
- result = subprocess.run(['qemu-img', 'create', '-f', 'qcow2', disk_path, f'{disk_size}G'], capture_output=True, text=True)
- if result.returncode != 0:
- return {"error": f"Failed to create disk: {result.stderr}"}
- except Exception as e:
- return {"error": f"Error creating disk: {str(e)}"}
-
- # Generate unique MAC
- mac = f"52:54:00:{random.randint(0, 255):02x}:{random.randint(0, 255):02x}:{random.randint(0, 255):02x}"
-
- # Basic XML template
- xml_template = f"""<domain type='kvm'>
- <name>{name}</name>
- <memory unit='MiB'>{memory}</memory>
- <currentMemory unit='MiB'>{memory}</currentMemory>
- <vcpu placement='static'>1</vcpu>
- <os>
- <type arch='x86_64' machine='pc-i440fx-6.2'>hvm</type>
- <boot dev='cdrom'/>
- </os>
- <features>
- <acpi/>
- <apic/>
- </features>
- <cpu mode='host-model' check='partial'/>
- <clock offset='utc'>
- <timer name='rtc' tickpolicy='catchup'/>
- <timer name='pit' tickpolicy='delay'/>
- <timer name='hpet' present='no'/>
- </clock>
- <on_poweroff>destroy</on_poweroff>
- <on_reboot>restart</on_reboot>
- <on_crash>destroy</on_crash>
- <pm>
- <suspend-to-mem enabled='no'/>
- <suspend-to-disk enabled='no'/>
- </pm>
- <devices>
- <emulator>/usr/bin/kvm</emulator>
- <disk type='file' device='disk'>
- <driver name='qemu' type='qcow2'/>
- <source file='{disk_path}'/>
- <target dev='vda' bus='virtio'/>
- </disk>
- <disk type='file' device='cdrom'>
- <driver name='qemu' type='raw'/>
- <source file='{iso_path}'/>
- <target dev='hda' bus='ide'/>
- <readonly/>
- </disk>
- <interface type='network'>
- <mac address='{mac}'/>
- <source network='default'/>
- <model type='virtio'/>
- </interface>
- <console type='pty'>
- <target type='serial' port='0'/>
- </console>
- <input type='tablet' bus='usb'>
- <address type='usb' bus='0' port='1'/>
- </input>
- <input type='mouse' bus='ps2'/>
- <input type='keyboard' bus='ps2'/>
- <graphics type='vnc' port='-1' autoport='yes'/>
- <video>
- <model type='cirrus' vram='16384' heads='1' primary='yes'/>
- </video>
- <memballoon model='virtio'>
- <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
- </memballoon>
- </devices>
- </domain>"""
-
- try:
- domain = conn.defineXML(xml_template)
- domain.create()
- return {"message": f"VM {name} created with {memory} MiB memory, {disk_size}G disk, booting from {iso}"}
- except Exception as e:
- return {"error": str(e)}
- @app.delete("/vms/{vm_name}")
- async def delete_vm(vm_name: str):
- try:
- domain = conn.lookupByName(vm_name)
- if domain.isActive():
- domain.destroy()
- domain.undefine()
- return {"message": f"VM {vm_name} deleted"}
- 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')
- disk_path = f"{images_path}/{name}.qcow2"
- try:
- result = subprocess.run(['qemu-img', 'create', '-f', 'qcow2', disk_path, f'{size}G'], capture_output=True, text=True)
- if result.returncode == 0:
- return {"message": f"Disk {name}.qcow2 created with size {size}G"}
- else:
- return {"error": result.stderr}
- except Exception as e:
- return {"error": str(e)}
|