diff --git a/virtweb_backend/src/app_config.rs b/virtweb_backend/src/app_config.rs index 2eec386..5734e63 100644 --- a/virtweb_backend/src/app_config.rs +++ b/virtweb_backend/src/app_config.rs @@ -155,6 +155,11 @@ impl AppConfig { pub fn iso_storage_path(&self) -> PathBuf { self.storage_path().join("iso") } + + /// Get VM vnc sockets + pub fn vnc_sockets_path(&self) -> PathBuf { + self.storage_path().to_path_buf() + } } #[derive(Debug, Clone, serde::Serialize)] diff --git a/virtweb_backend/src/libvirt_lib_structures.rs b/virtweb_backend/src/libvirt_lib_structures.rs index 8b04cff..e46088a 100644 --- a/virtweb_backend/src/libvirt_lib_structures.rs +++ b/virtweb_backend/src/libvirt_lib_structures.rs @@ -19,6 +19,8 @@ impl DomainXMLUuid { #[derive(serde::Serialize, serde::Deserialize)] #[serde(rename = "os")] pub struct OSXML { + #[serde(rename(serialize = "@firmware"))] + pub firmware: String, pub r#type: OSTypeXML, pub loader: Option, } @@ -41,6 +43,37 @@ pub struct OSLoaderXML { pub secure: String, } +/// Hypervisor features +#[derive(serde::Serialize, serde::Deserialize)] +#[serde(rename = "features")] +pub struct FeaturesXML { + pub acpi: ACPIXML, +} + +/// ACPI feature +#[derive(serde::Serialize, serde::Deserialize)] +#[serde(rename = "acpi")] +pub struct ACPIXML {} + +/// Devices information +#[derive(serde::Serialize, serde::Deserialize)] +#[serde(rename = "devices")] +pub struct DevicesXML { + #[serde(skip_serializing_if = "Option::is_none")] + pub graphics: Option, +} + +/// Screen information +#[derive(serde::Serialize, serde::Deserialize)] +#[serde(rename = "graphics")] +pub struct GraphicsXML { + #[serde(rename(serialize = "@type"))] + pub r#type: String, + #[serde(rename(serialize = "@socket"))] + pub socket: String, +} + +/// Domain RAM information #[derive(serde::Serialize, serde::Deserialize)] #[serde(rename = "memory")] pub struct DomainMemoryXML { @@ -65,6 +98,8 @@ pub struct DomainXML { pub title: Option, pub description: Option, pub os: OSXML, + pub features: FeaturesXML, + pub devices: DevicesXML, /// The maximum allocation of memory for the guest at boot time pub memory: DomainMemoryXML, diff --git a/virtweb_backend/src/libvirt_rest_structures.rs b/virtweb_backend/src/libvirt_rest_structures.rs index e00940c..d29f57f 100644 --- a/virtweb_backend/src/libvirt_rest_structures.rs +++ b/virtweb_backend/src/libvirt_rest_structures.rs @@ -1,6 +1,8 @@ +use crate::app_config::AppConfig; use crate::constants; use crate::libvirt_lib_structures::{ - DomainMemoryXML, DomainXML, DomainXMLUuid, OSLoaderXML, OSTypeXML, OSXML, + DevicesXML, DomainMemoryXML, DomainXML, DomainXMLUuid, FeaturesXML, GraphicsXML, OSLoaderXML, + OSTypeXML, ACPIXML, OSXML, }; use crate::libvirt_rest_structures::LibVirtStructError::StructureExtraction; use lazy_regex::regex; @@ -66,11 +68,12 @@ pub struct VMInfo { pub architecture: VMArchitecture, /// VM allocated memory, in megabytes pub memory: usize, + /// Enable VNC access through admin console + pub vnc_access: bool, // TODO : storage // TODO : iso // TODO : autostart - // TODO : vnc - // TODO : interface + // TODO : network interface } impl VMInfo { @@ -102,6 +105,18 @@ impl VMInfo { return Err(StructureExtraction("VM memory is invalid!").into()); } + let vnc_graphics = match self.vnc_access { + true => Some(GraphicsXML { + r#type: "vnc".to_string(), + socket: AppConfig::get() + .vnc_sockets_path() + .join(format!("vnc-{}", self.name)) + .to_string_lossy() + .to_string(), + }), + false => None, + }; + Ok(DomainXML { r#type: "kvm".to_string(), name: self.name, @@ -119,6 +134,7 @@ impl VMInfo { .to_string(), body: "hvm".to_string(), }, + firmware: "efi".to_string(), loader: Some(OSLoaderXML { secure: match self.boot_type { BootType::UEFI => "no".to_string(), @@ -126,6 +142,13 @@ impl VMInfo { }, }), }, + + features: FeaturesXML { acpi: ACPIXML {} }, + + devices: DevicesXML { + graphics: vnc_graphics, + }, + memory: DomainMemoryXML { unit: "MB".to_string(), memory: self.memory, @@ -163,6 +186,7 @@ impl VMInfo { } }, memory: convert_to_mb(&domain.memory.unit, domain.memory.memory)?, + vnc_access: domain.devices.graphics.is_some(), }) } }