/** * Virtual Machines API * * @author Pierre HUBERT */ import { APIClient } from "./ApiClient"; export type VMState = | "NoState" | "Running" | "Blocked" | "Paused" | "Shutdown" | "Shutoff" | "Crashed" | "PowerManagementSuspended" | "Other"; export type DiskAllocType = "Sparse" | "Fixed"; export interface VMDisk { size: number; name: string; alloc_type: DiskAllocType; delete: boolean; // application attribute new?: boolean; deleteType?: "keepfile" | "deletefile"; } export interface VMNetInterfaceFilterParams { name: string; value: string; } export interface VMNetInterfaceFilter { name: string; parameters: VMNetInterfaceFilterParams[]; } export type VMNetInterface = (VMNetUserspaceSLIRPStack | VMNetDefinedNetwork) & VMNetInterfaceBase; export interface VMNetInterfaceBase { mac: string; nwfilterref?: VMNetInterfaceFilter; } export interface VMNetUserspaceSLIRPStack { type: "UserspaceSLIRPStack"; } export interface VMNetDefinedNetwork { type: "DefinedNetwork"; network: string; } interface VMInfoInterface { name: string; uuid?: string; genid?: string; title?: string; description?: string; boot_type: "UEFI" | "UEFISecureBoot"; architecture: "i686" | "x86_64"; memory: number; number_vcpu: number; vnc_access: boolean; iso_files: string[]; disks: VMDisk[]; networks: VMNetInterface[]; tpm_module: boolean; } export class VMInfo implements VMInfoInterface { name: string; uuid?: string; genid?: string; title?: string; description?: string; boot_type: "UEFI" | "UEFISecureBoot"; architecture: "i686" | "x86_64"; number_vcpu: number; memory: number; vnc_access: boolean; iso_files: string[]; disks: VMDisk[]; networks: VMNetInterface[]; tpm_module: boolean; constructor(int: VMInfoInterface) { this.name = int.name; this.uuid = int.uuid; this.genid = int.genid; this.title = int.title; this.description = int.description; this.boot_type = int.boot_type; this.architecture = int.architecture; this.number_vcpu = int.number_vcpu; this.memory = int.memory; this.vnc_access = int.vnc_access; this.iso_files = int.iso_files; this.disks = int.disks; this.networks = int.networks; this.tpm_module = int.tpm_module; } static NewEmpty(): VMInfo { return new VMInfo({ name: "", boot_type: "UEFI", architecture: "x86_64", memory: 1024, number_vcpu: 1, vnc_access: true, iso_files: [], disks: [], networks: [], tpm_module: true, }); } get ViewURL(): string { return `/vm/${this.uuid}`; } get EditURL(): string { return `/vm/${this.uuid}/edit`; } get VNCURL(): string { return `/vm/${this.uuid}/vnc`; } get XMLURL(): string { return `/vm/${this.uuid}/xml`; } } export class VMApi { /** * Create a new virtual machine */ static async Create(v: VMInfo): Promise<{ uuid: string }> { return ( await APIClient.exec({ uri: `/vm/create`, method: "POST", jsonData: v, }) ).data; } /** * Get the list of defined virtual machines */ static async GetList(): Promise<VMInfo[]> { return ( await APIClient.exec({ uri: "/vm/list", method: "GET", }) ).data.map((i: VMInfoInterface) => new VMInfo(i)); } /** * Get the information about a single VM */ static async GetSingle(uuid: string): Promise<VMInfo> { const data = ( await APIClient.exec({ uri: `/vm/${uuid}`, method: "GET", }) ).data; return new VMInfo(data); } /** * Get the source XML configuration of a domain for debugging purposes */ static async GetSingleXML(uuid: string): Promise<string> { return ( await APIClient.exec({ uri: `/vm/${uuid}/src`, method: "GET", }) ).data; } /** * Update the information about a single VM */ static async UpdateSingle(vm: VMInfo): Promise<VMInfo> { // Process disks list, looking for removal vm.disks = vm.disks.filter((d) => d.deleteType !== "keepfile"); vm.disks.forEach((d) => { if (d.deleteType === "deletefile") d.delete = true; }); const data = ( await APIClient.exec({ uri: `/vm/${vm.uuid!}`, method: "PUT", jsonData: vm, }) ).data; return new VMInfo(data); } /** * Check if autostart is enabled on a VM */ static async IsAutostart(vm: VMInfo): Promise<boolean> { return ( await APIClient.exec({ uri: `/vm/${vm.uuid}/autostart`, method: "GET", }) ).data.autostart; } /** * Set autostart status of a VM */ static async SetAutostart(vm: VMInfo, enabled: boolean): Promise<void> { await APIClient.exec({ uri: `/vm/${vm.uuid}/autostart`, method: "PUT", jsonData: { autostart: enabled }, }); } /** * Get the state of a VM */ static async GetState(vm: VMInfo): Promise<VMState> { return ( await APIClient.exec({ uri: `/vm/${vm.uuid}/state`, method: "GET", }) ).data.state; } /** * Get a screenshot of a VM */ static async Screenshot(vm: VMInfo): Promise<Blob> { return ( await APIClient.exec({ uri: `/vm/${vm.uuid}/screenshot`, method: "GET", }) ).data; } /** * Start the VM */ static async StartVM(vm: VMInfo): Promise<void> { return ( await APIClient.exec({ uri: `/vm/${vm.uuid}/start`, method: "GET", }) ).data.state; } /** * Shutdown the VM */ static async ShutdownVM(vm: VMInfo): Promise<void> { return ( await APIClient.exec({ uri: `/vm/${vm.uuid}/shutdown`, method: "GET", }) ).data.state; } /** * Restt the VM */ static async ResetVM(vm: VMInfo): Promise<void> { return ( await APIClient.exec({ uri: `/vm/${vm.uuid}/reset`, method: "GET", }) ).data.state; } /** * Kill the VM */ static async KillVM(vm: VMInfo): Promise<void> { return ( await APIClient.exec({ uri: `/vm/${vm.uuid}/kill`, method: "GET", }) ).data.state; } /** * Suspend the VM */ static async SuspendVM(vm: VMInfo): Promise<void> { return ( await APIClient.exec({ uri: `/vm/${vm.uuid}/suspend`, method: "GET", }) ).data.state; } /** * Resume the VM */ static async ResumeVM(vm: VMInfo): Promise<void> { return ( await APIClient.exec({ uri: `/vm/${vm.uuid}/resume`, method: "GET", }) ).data.state; } /** * Delete a virtual machine */ static async Delete(vm: VMInfo, keep_files: boolean): Promise<void> { await APIClient.exec({ uri: `/vm/${vm.uuid}`, method: "DELETE", jsonData: { keep_files }, }); } /** * Get a oneshot VNC connect URL */ static async OneShotVNCURL(vm: VMInfo): Promise<string> { const token = ( await APIClient.exec({ uri: `/vm/${vm.uuid}/vnc_token`, method: "GET", }) ).data.token; let baseWSURL = APIClient.backendURL(); if (!baseWSURL.includes("://")) baseWSURL = window.location.protocol + "//" + window.location.host + baseWSURL; return ( baseWSURL.replace("http", "ws") + "/vnc?token=" + encodeURIComponent(token) ); } }