From 674f9fe7ede2df244cc50e341e285bd382042e86 Mon Sep 17 00:00:00 2001 From: Pierre Hubert Date: Mon, 16 Oct 2023 19:22:15 +0200 Subject: [PATCH] Can update VM settings --- virtweb_backend/src/libvirt_lib_structures.rs | 1 + .../src/libvirt_rest_structures.rs | 4 +- virtweb_frontend/src/App.tsx | 2 +- virtweb_frontend/src/api/VMApi.ts | 33 +++++++++- virtweb_frontend/src/routes/EditVMRoute.tsx | 65 +++++++++++++++++-- 5 files changed, 95 insertions(+), 10 deletions(-) diff --git a/virtweb_backend/src/libvirt_lib_structures.rs b/virtweb_backend/src/libvirt_lib_structures.rs index 39ecaa3..a64eb4f 100644 --- a/virtweb_backend/src/libvirt_lib_structures.rs +++ b/virtweb_backend/src/libvirt_lib_structures.rs @@ -11,6 +11,7 @@ impl DomainXMLUuid { } pub fn is_valid(&self) -> bool { + log::debug!("UUID version ({}): {}", self.0, self.0.get_version_num()); self.0.get_version_num() == 4 } } diff --git a/virtweb_backend/src/libvirt_rest_structures.rs b/virtweb_backend/src/libvirt_rest_structures.rs index d29f57f..5f26929 100644 --- a/virtweb_backend/src/libvirt_rest_structures.rs +++ b/virtweb_backend/src/libvirt_rest_structures.rs @@ -84,13 +84,13 @@ impl VMInfo { } if let Some(n) = &self.uuid { - if n.is_valid() { + if !n.is_valid() { return Err(StructureExtraction("VM UUID is invalid!").into()); } } if let Some(n) = &self.genid { - if n.is_valid() { + if !n.is_valid() { return Err(StructureExtraction("VM genid is invalid!").into()); } } diff --git a/virtweb_frontend/src/App.tsx b/virtweb_frontend/src/App.tsx index ea87f5f..33a96d3 100644 --- a/virtweb_frontend/src/App.tsx +++ b/virtweb_frontend/src/App.tsx @@ -41,7 +41,7 @@ export function App() { } /> } /> - } /> + } /> } /> } /> diff --git a/virtweb_frontend/src/api/VMApi.ts b/virtweb_frontend/src/api/VMApi.ts index cc97f6e..3c501e2 100644 --- a/virtweb_frontend/src/api/VMApi.ts +++ b/virtweb_frontend/src/api/VMApi.ts @@ -63,7 +63,11 @@ export class VMInfo implements VMInfoInterface { } get ViewURL(): string { - return `/api/vm/${this.uuid}`; + return `/vm/${this.uuid}`; + } + + get EditURL(): string { + return `/vm/${this.uuid}/edit`; } } @@ -93,6 +97,33 @@ export class VMApi { ).data.map((i: VMInfoInterface) => new VMInfo(i)); } + /** + * Get the information about a single VM + */ + static async GetSingle(uuid: string): Promise { + const data = ( + await APIClient.exec({ + uri: `/vm/${uuid}`, + method: "GET", + }) + ).data; + return new VMInfo(data); + } + + /** + * Update the information about a single VM + */ + static async UpdateSingle(vm: VMInfo): Promise { + const data = ( + await APIClient.exec({ + uri: `/vm/${vm.uuid!}`, + method: "PUT", + jsonData: vm, + }) + ).data; + return new VMInfo(data); + } + /** * Get the state of a VM */ diff --git a/virtweb_frontend/src/routes/EditVMRoute.tsx b/virtweb_frontend/src/routes/EditVMRoute.tsx index 5cecbef..38e5c29 100644 --- a/virtweb_frontend/src/routes/EditVMRoute.tsx +++ b/virtweb_frontend/src/routes/EditVMRoute.tsx @@ -1,5 +1,5 @@ import React, { PropsWithChildren } from "react"; -import { useNavigate } from "react-router-dom"; +import { useNavigate, useParams } from "react-router-dom"; import { VMApi, VMInfo } from "../api/VMApi"; import { useSnackbar } from "../hooks/providers/SnackbarProvider"; import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer"; @@ -9,6 +9,8 @@ import { ServerApi } from "../api/ServerApi"; import { validate as validateUUID } from "uuid"; import { SelectInput } from "../widgets/forms/SelectInput"; import { CheckboxInput } from "../widgets/forms/CheckboxInput"; +import { useAlert } from "../hooks/providers/AlertDialogProvider"; +import { AsyncWidget } from "../widgets/AsyncWidget"; export function CreateVMRoute(): React.ReactElement { const snackbar = useSnackbar(); @@ -17,10 +19,15 @@ export function CreateVMRoute(): React.ReactElement { const [vm] = React.useState(VMInfo.NewEmpty); const create = async (v: VMInfo) => { - const res = await VMApi.Create(v); - snackbar("The virtual machine was successfully created!"); - v.uuid = res.uuid; - navigate(v.ViewURL); + try { + const res = await VMApi.Create(v); + snackbar("The virtual machine was successfully created!"); + v.uuid = res.uuid; + navigate(v.ViewURL); + } catch (e) { + console.error(e); + alert("Failed to create VM!"); + } }; return ( @@ -34,7 +41,53 @@ export function CreateVMRoute(): React.ReactElement { } export function EditVMRoute(): React.ReactElement { - return <>todo; + const navigate = useNavigate(); + const alert = useAlert(); + const snackbar = useSnackbar(); + + const { uuid } = useParams(); + + const [vm, setVM] = React.useState(undefined); + + const load = async () => { + const vm = await VMApi.GetSingle(uuid!); + setVM(vm); + + const state = await VMApi.GetState(vm); + if (state !== "Shutdown" && state !== "Shutoff") { + await alert("The Virtual machine is running, you cannot edit it!"); + navigate(vm.ViewURL); + } + }; + + const save = async (v: VMInfo) => { + try { + await VMApi.UpdateSingle(v); + snackbar("The virtual machine was successfully updated!"); + navigate(v.ViewURL); + } catch (e) { + console.error(e); + alert("Failed to update VM info!"); + } + }; + + return ( + ( + { + navigate(vm!.ViewURL); + }} + onSave={save} + /> + )} + /> + ); } function EditVMInner(p: {