Can assign a group to VMs
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			This commit is contained in:
		@@ -21,7 +21,7 @@ struct VMUuid {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/// Create a new VM
 | 
					/// Create a new VM
 | 
				
			||||||
pub async fn create(client: LibVirtReq, req: web::Json<VMInfo>) -> HttpResult {
 | 
					pub async fn create(client: LibVirtReq, req: web::Json<VMInfo>) -> HttpResult {
 | 
				
			||||||
    let domain = match req.0.as_tomain() {
 | 
					    let domain = match req.0.as_domain() {
 | 
				
			||||||
        Ok(d) => d,
 | 
					        Ok(d) => d,
 | 
				
			||||||
        Err(e) => {
 | 
					        Err(e) => {
 | 
				
			||||||
            log::error!("Failed to extract domain info! {e}");
 | 
					            log::error!("Failed to extract domain info! {e}");
 | 
				
			||||||
@@ -83,6 +83,8 @@ pub async fn get_single(client: LibVirtReq, id: web::Path<SingleVMUUidReq>) -> H
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log::debug!("INFO={info:#?}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let state = client.get_domain_state(id.uid).await?;
 | 
					    let state = client.get_domain_state(id.uid).await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Ok(HttpResponse::Ok().json(VMInfoAndState {
 | 
					    Ok(HttpResponse::Ok().json(VMInfoAndState {
 | 
				
			||||||
@@ -112,7 +114,7 @@ pub async fn update(
 | 
				
			|||||||
    id: web::Path<SingleVMUUidReq>,
 | 
					    id: web::Path<SingleVMUUidReq>,
 | 
				
			||||||
    req: web::Json<VMInfo>,
 | 
					    req: web::Json<VMInfo>,
 | 
				
			||||||
) -> HttpResult {
 | 
					) -> HttpResult {
 | 
				
			||||||
    let mut domain = match req.0.as_tomain() {
 | 
					    let mut domain = match req.0.as_domain() {
 | 
				
			||||||
        Ok(d) => d,
 | 
					        Ok(d) => d,
 | 
				
			||||||
        Err(e) => {
 | 
					        Err(e) => {
 | 
				
			||||||
            log::error!("Failed to extract domain info! {e}");
 | 
					            log::error!("Failed to extract domain info! {e}");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,25 @@
 | 
				
			|||||||
use crate::libvirt_lib_structures::XMLUuid;
 | 
					use crate::libvirt_lib_structures::XMLUuid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// VirtWeb specific metadata
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Default, Debug, Clone)]
 | 
				
			||||||
 | 
					#[serde(rename = "virtweb", default)]
 | 
				
			||||||
 | 
					pub struct DomainMetadataVirtWebXML {
 | 
				
			||||||
 | 
					    #[serde(rename = "@xmlns:virtweb", default)]
 | 
				
			||||||
 | 
					    pub ns: String,
 | 
				
			||||||
 | 
					    #[serde(skip_serializing_if = "Option::is_none")]
 | 
				
			||||||
 | 
					    pub group: Option<String>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Domain metadata
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Default, Debug, Clone)]
 | 
				
			||||||
 | 
					#[serde(rename = "metadata")]
 | 
				
			||||||
 | 
					pub struct DomainMetadataXML {
 | 
				
			||||||
 | 
					    #[serde(rename = "virtweb:metadata", default)]
 | 
				
			||||||
 | 
					    pub virtweb: DomainMetadataVirtWebXML,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// OS information
 | 
					/// OS information
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "os")]
 | 
					#[serde(rename = "os")]
 | 
				
			||||||
pub struct OSXML {
 | 
					pub struct OSXML {
 | 
				
			||||||
    #[serde(rename = "@firmware", default)]
 | 
					    #[serde(rename = "@firmware", default)]
 | 
				
			||||||
@@ -11,7 +29,7 @@ pub struct OSXML {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// OS Type information
 | 
					/// OS Type information
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "os")]
 | 
					#[serde(rename = "os")]
 | 
				
			||||||
pub struct OSTypeXML {
 | 
					pub struct OSTypeXML {
 | 
				
			||||||
    #[serde(rename = "@arch")]
 | 
					    #[serde(rename = "@arch")]
 | 
				
			||||||
@@ -23,7 +41,7 @@ pub struct OSTypeXML {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// OS Loader information
 | 
					/// OS Loader information
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "loader")]
 | 
					#[serde(rename = "loader")]
 | 
				
			||||||
pub struct OSLoaderXML {
 | 
					pub struct OSLoaderXML {
 | 
				
			||||||
    #[serde(rename = "@secure")]
 | 
					    #[serde(rename = "@secure")]
 | 
				
			||||||
@@ -31,39 +49,39 @@ pub struct OSLoaderXML {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Hypervisor features
 | 
					/// Hypervisor features
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize, Default)]
 | 
					#[derive(serde::Serialize, serde::Deserialize, Default, Debug)]
 | 
				
			||||||
#[serde(rename = "features")]
 | 
					#[serde(rename = "features")]
 | 
				
			||||||
pub struct FeaturesXML {
 | 
					pub struct FeaturesXML {
 | 
				
			||||||
    pub acpi: ACPIXML,
 | 
					    pub acpi: ACPIXML,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// ACPI feature
 | 
					/// ACPI feature
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize, Default)]
 | 
					#[derive(serde::Serialize, serde::Deserialize, Default, Debug)]
 | 
				
			||||||
#[serde(rename = "acpi")]
 | 
					#[serde(rename = "acpi")]
 | 
				
			||||||
pub struct ACPIXML {}
 | 
					pub struct ACPIXML {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "mac")]
 | 
					#[serde(rename = "mac")]
 | 
				
			||||||
pub struct NetMacAddress {
 | 
					pub struct NetMacAddress {
 | 
				
			||||||
    #[serde(rename = "@address")]
 | 
					    #[serde(rename = "@address")]
 | 
				
			||||||
    pub address: String,
 | 
					    pub address: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "source")]
 | 
					#[serde(rename = "source")]
 | 
				
			||||||
pub struct NetIntSourceXML {
 | 
					pub struct NetIntSourceXML {
 | 
				
			||||||
    #[serde(rename = "@network")]
 | 
					    #[serde(rename = "@network")]
 | 
				
			||||||
    pub network: String,
 | 
					    pub network: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "model")]
 | 
					#[serde(rename = "model")]
 | 
				
			||||||
pub struct NetIntModelXML {
 | 
					pub struct NetIntModelXML {
 | 
				
			||||||
    #[serde(rename = "@type")]
 | 
					    #[serde(rename = "@type")]
 | 
				
			||||||
    pub r#type: String,
 | 
					    pub r#type: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "filterref")]
 | 
					#[serde(rename = "filterref")]
 | 
				
			||||||
pub struct NetIntFilterParameterXML {
 | 
					pub struct NetIntFilterParameterXML {
 | 
				
			||||||
    #[serde(rename = "@name")]
 | 
					    #[serde(rename = "@name")]
 | 
				
			||||||
@@ -72,7 +90,7 @@ pub struct NetIntFilterParameterXML {
 | 
				
			|||||||
    pub value: String,
 | 
					    pub value: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "filterref")]
 | 
					#[serde(rename = "filterref")]
 | 
				
			||||||
pub struct NetIntfilterRefXML {
 | 
					pub struct NetIntfilterRefXML {
 | 
				
			||||||
    #[serde(rename = "@filter")]
 | 
					    #[serde(rename = "@filter")]
 | 
				
			||||||
@@ -81,7 +99,7 @@ pub struct NetIntfilterRefXML {
 | 
				
			|||||||
    pub parameters: Vec<NetIntFilterParameterXML>,
 | 
					    pub parameters: Vec<NetIntFilterParameterXML>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "interface")]
 | 
					#[serde(rename = "interface")]
 | 
				
			||||||
pub struct DomainNetInterfaceXML {
 | 
					pub struct DomainNetInterfaceXML {
 | 
				
			||||||
    #[serde(rename = "@type")]
 | 
					    #[serde(rename = "@type")]
 | 
				
			||||||
@@ -95,14 +113,14 @@ pub struct DomainNetInterfaceXML {
 | 
				
			|||||||
    pub filterref: Option<NetIntfilterRefXML>,
 | 
					    pub filterref: Option<NetIntfilterRefXML>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "input")]
 | 
					#[serde(rename = "input")]
 | 
				
			||||||
pub struct DomainInputXML {
 | 
					pub struct DomainInputXML {
 | 
				
			||||||
    #[serde(rename = "@type")]
 | 
					    #[serde(rename = "@type")]
 | 
				
			||||||
    pub r#type: String,
 | 
					    pub r#type: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "backend")]
 | 
					#[serde(rename = "backend")]
 | 
				
			||||||
pub struct TPMBackendXML {
 | 
					pub struct TPMBackendXML {
 | 
				
			||||||
    #[serde(rename = "@type")]
 | 
					    #[serde(rename = "@type")]
 | 
				
			||||||
@@ -112,7 +130,7 @@ pub struct TPMBackendXML {
 | 
				
			|||||||
    pub r#version: String,
 | 
					    pub r#version: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "tpm")]
 | 
					#[serde(rename = "tpm")]
 | 
				
			||||||
pub struct TPMDeviceXML {
 | 
					pub struct TPMDeviceXML {
 | 
				
			||||||
    #[serde(rename = "@model")]
 | 
					    #[serde(rename = "@model")]
 | 
				
			||||||
@@ -121,7 +139,7 @@ pub struct TPMDeviceXML {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Devices information
 | 
					/// Devices information
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "devices")]
 | 
					#[serde(rename = "devices")]
 | 
				
			||||||
pub struct DevicesXML {
 | 
					pub struct DevicesXML {
 | 
				
			||||||
    /// Graphics (used for VNC)
 | 
					    /// Graphics (used for VNC)
 | 
				
			||||||
@@ -150,7 +168,7 @@ pub struct DevicesXML {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Graphics information
 | 
					/// Graphics information
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "graphics")]
 | 
					#[serde(rename = "graphics")]
 | 
				
			||||||
pub struct GraphicsXML {
 | 
					pub struct GraphicsXML {
 | 
				
			||||||
    #[serde(rename = "@type")]
 | 
					    #[serde(rename = "@type")]
 | 
				
			||||||
@@ -160,14 +178,14 @@ pub struct GraphicsXML {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Video device information
 | 
					/// Video device information
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "video")]
 | 
					#[serde(rename = "video")]
 | 
				
			||||||
pub struct VideoXML {
 | 
					pub struct VideoXML {
 | 
				
			||||||
    pub model: VideoModelXML,
 | 
					    pub model: VideoModelXML,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Video model device information
 | 
					/// Video model device information
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "model")]
 | 
					#[serde(rename = "model")]
 | 
				
			||||||
pub struct VideoModelXML {
 | 
					pub struct VideoModelXML {
 | 
				
			||||||
    #[serde(rename = "@type")]
 | 
					    #[serde(rename = "@type")]
 | 
				
			||||||
@@ -175,7 +193,7 @@ pub struct VideoModelXML {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Disk information
 | 
					/// Disk information
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "disk")]
 | 
					#[serde(rename = "disk")]
 | 
				
			||||||
pub struct DiskXML {
 | 
					pub struct DiskXML {
 | 
				
			||||||
    #[serde(rename = "@type")]
 | 
					    #[serde(rename = "@type")]
 | 
				
			||||||
@@ -193,7 +211,7 @@ pub struct DiskXML {
 | 
				
			|||||||
    pub address: Option<DiskAddressXML>,
 | 
					    pub address: Option<DiskAddressXML>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "driver")]
 | 
					#[serde(rename = "driver")]
 | 
				
			||||||
pub struct DiskDriverXML {
 | 
					pub struct DiskDriverXML {
 | 
				
			||||||
    #[serde(rename = "@name")]
 | 
					    #[serde(rename = "@name")]
 | 
				
			||||||
@@ -204,14 +222,14 @@ pub struct DiskDriverXML {
 | 
				
			|||||||
    pub r#cache: String,
 | 
					    pub r#cache: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "source")]
 | 
					#[serde(rename = "source")]
 | 
				
			||||||
pub struct DiskSourceXML {
 | 
					pub struct DiskSourceXML {
 | 
				
			||||||
    #[serde(rename = "@file")]
 | 
					    #[serde(rename = "@file")]
 | 
				
			||||||
    pub file: String,
 | 
					    pub file: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "target")]
 | 
					#[serde(rename = "target")]
 | 
				
			||||||
pub struct DiskTargetXML {
 | 
					pub struct DiskTargetXML {
 | 
				
			||||||
    #[serde(rename = "@dev")]
 | 
					    #[serde(rename = "@dev")]
 | 
				
			||||||
@@ -220,18 +238,18 @@ pub struct DiskTargetXML {
 | 
				
			|||||||
    pub bus: String,
 | 
					    pub bus: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "readonly")]
 | 
					#[serde(rename = "readonly")]
 | 
				
			||||||
pub struct DiskReadOnlyXML {}
 | 
					pub struct DiskReadOnlyXML {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "boot")]
 | 
					#[serde(rename = "boot")]
 | 
				
			||||||
pub struct DiskBootXML {
 | 
					pub struct DiskBootXML {
 | 
				
			||||||
    #[serde(rename = "@order")]
 | 
					    #[serde(rename = "@order")]
 | 
				
			||||||
    pub order: String,
 | 
					    pub order: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "address")]
 | 
					#[serde(rename = "address")]
 | 
				
			||||||
pub struct DiskAddressXML {
 | 
					pub struct DiskAddressXML {
 | 
				
			||||||
    #[serde(rename = "@type")]
 | 
					    #[serde(rename = "@type")]
 | 
				
			||||||
@@ -251,7 +269,7 @@ pub struct DiskAddressXML {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Domain RAM information
 | 
					/// Domain RAM information
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "memory")]
 | 
					#[serde(rename = "memory")]
 | 
				
			||||||
pub struct DomainMemoryXML {
 | 
					pub struct DomainMemoryXML {
 | 
				
			||||||
    #[serde(rename = "@unit")]
 | 
					    #[serde(rename = "@unit")]
 | 
				
			||||||
@@ -261,7 +279,7 @@ pub struct DomainMemoryXML {
 | 
				
			|||||||
    pub memory: usize,
 | 
					    pub memory: usize,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "topology")]
 | 
					#[serde(rename = "topology")]
 | 
				
			||||||
pub struct DomainCPUTopology {
 | 
					pub struct DomainCPUTopology {
 | 
				
			||||||
    #[serde(rename = "@sockets")]
 | 
					    #[serde(rename = "@sockets")]
 | 
				
			||||||
@@ -272,14 +290,14 @@ pub struct DomainCPUTopology {
 | 
				
			|||||||
    pub threads: usize,
 | 
					    pub threads: usize,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "cpu")]
 | 
					#[serde(rename = "cpu")]
 | 
				
			||||||
pub struct DomainVCPUXML {
 | 
					pub struct DomainVCPUXML {
 | 
				
			||||||
    #[serde(rename = "$value")]
 | 
					    #[serde(rename = "$value")]
 | 
				
			||||||
    pub body: usize,
 | 
					    pub body: usize,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "cpu")]
 | 
					#[serde(rename = "cpu")]
 | 
				
			||||||
pub struct DomainCPUXML {
 | 
					pub struct DomainCPUXML {
 | 
				
			||||||
    #[serde(rename = "@mode")]
 | 
					    #[serde(rename = "@mode")]
 | 
				
			||||||
@@ -288,7 +306,7 @@ pub struct DomainCPUXML {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Domain information, see https://libvirt.org/formatdomain.html
 | 
					/// Domain information, see https://libvirt.org/formatdomain.html
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(Debug, serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "domain")]
 | 
					#[serde(rename = "domain")]
 | 
				
			||||||
pub struct DomainXML {
 | 
					pub struct DomainXML {
 | 
				
			||||||
    /// Domain type (kvm)
 | 
					    /// Domain type (kvm)
 | 
				
			||||||
@@ -300,6 +318,9 @@ pub struct DomainXML {
 | 
				
			|||||||
    pub genid: Option<uuid::Uuid>,
 | 
					    pub genid: Option<uuid::Uuid>,
 | 
				
			||||||
    pub title: Option<String>,
 | 
					    pub title: Option<String>,
 | 
				
			||||||
    pub description: Option<String>,
 | 
					    pub description: Option<String>,
 | 
				
			||||||
 | 
					    #[serde(default, skip_serializing_if = "Option::is_none")]
 | 
				
			||||||
 | 
					    pub metadata: Option<DomainMetadataXML>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub os: OSXML,
 | 
					    pub os: OSXML,
 | 
				
			||||||
    #[serde(default)]
 | 
					    #[serde(default)]
 | 
				
			||||||
    pub features: FeaturesXML,
 | 
					    pub features: FeaturesXML,
 | 
				
			||||||
@@ -319,10 +340,32 @@ pub struct DomainXML {
 | 
				
			|||||||
    pub on_crash: String,
 | 
					    pub on_crash: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const METADATA_START_MARKER: &str =
 | 
				
			||||||
 | 
					    "<virtweb:metadata xmlns:virtweb=\"https://virtweb.communiquons.org\">";
 | 
				
			||||||
 | 
					const METADATA_END_MARKER: &str = "</virtweb:metadata>";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl DomainXML {
 | 
					impl DomainXML {
 | 
				
			||||||
    /// Decode Domain structure from XML definition
 | 
					    /// Decode Domain structure from XML definition
 | 
				
			||||||
    pub fn parse_xml(xml: &str) -> anyhow::Result<Self> {
 | 
					    pub fn parse_xml(xml: &str) -> anyhow::Result<Self> {
 | 
				
			||||||
        Ok(quick_xml::de::from_str(xml)?)
 | 
					        let mut res: Self = quick_xml::de::from_str(xml)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Handle custom metadata parsing issue
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        // https://github.com/tafia/quick-xml/pull/797
 | 
				
			||||||
 | 
					        if xml.contains(METADATA_START_MARKER) && xml.contains(METADATA_END_MARKER) {
 | 
				
			||||||
 | 
					            let s = xml
 | 
				
			||||||
 | 
					                .split_once(METADATA_START_MARKER)
 | 
				
			||||||
 | 
					                .unwrap()
 | 
				
			||||||
 | 
					                .1
 | 
				
			||||||
 | 
					                .split_once(METADATA_END_MARKER)
 | 
				
			||||||
 | 
					                .unwrap()
 | 
				
			||||||
 | 
					                .0;
 | 
				
			||||||
 | 
					            let s = format!("<virtweb>{s}</virtweb>");
 | 
				
			||||||
 | 
					            let metadata: DomainMetadataVirtWebXML = quick_xml::de::from_str(&s)?;
 | 
				
			||||||
 | 
					            res.metadata = Some(DomainMetadataXML { virtweb: metadata });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(res)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Turn this domain into its XML definition
 | 
					    /// Turn this domain into its XML definition
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,6 +59,9 @@ pub struct VMInfo {
 | 
				
			|||||||
    pub genid: Option<XMLUuid>,
 | 
					    pub genid: Option<XMLUuid>,
 | 
				
			||||||
    pub title: Option<String>,
 | 
					    pub title: Option<String>,
 | 
				
			||||||
    pub description: Option<String>,
 | 
					    pub description: Option<String>,
 | 
				
			||||||
 | 
					    /// Group associated with the VM (VirtWeb specific field)
 | 
				
			||||||
 | 
					    #[serde(skip_serializing_if = "Option::is_none")]
 | 
				
			||||||
 | 
					    pub group: Option<String>,
 | 
				
			||||||
    pub boot_type: BootType,
 | 
					    pub boot_type: BootType,
 | 
				
			||||||
    pub architecture: VMArchitecture,
 | 
					    pub architecture: VMArchitecture,
 | 
				
			||||||
    /// VM allocated memory, in megabytes
 | 
					    /// VM allocated memory, in megabytes
 | 
				
			||||||
@@ -79,7 +82,7 @@ pub struct VMInfo {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
impl VMInfo {
 | 
					impl VMInfo {
 | 
				
			||||||
    /// Turn this VM into a domain
 | 
					    /// Turn this VM into a domain
 | 
				
			||||||
    pub fn as_tomain(&self) -> anyhow::Result<DomainXML> {
 | 
					    pub fn as_domain(&self) -> anyhow::Result<DomainXML> {
 | 
				
			||||||
        if !regex!("^[a-zA-Z0-9]+$").is_match(&self.name) {
 | 
					        if !regex!("^[a-zA-Z0-9]+$").is_match(&self.name) {
 | 
				
			||||||
            return Err(StructureExtraction("VM name is invalid!").into());
 | 
					            return Err(StructureExtraction("VM name is invalid!").into());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -105,6 +108,12 @@ impl VMInfo {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Some(group) = &self.group {
 | 
				
			||||||
 | 
					            if !regex!("^[a-zA-Z0-9]+$").is_match(group) {
 | 
				
			||||||
 | 
					                return Err(StructureExtraction("VM group name is invalid!").into());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.memory < constants::MIN_VM_MEMORY || self.memory > constants::MAX_VM_MEMORY {
 | 
					        if self.memory < constants::MIN_VM_MEMORY || self.memory > constants::MAX_VM_MEMORY {
 | 
				
			||||||
            return Err(StructureExtraction("VM memory is invalid!").into());
 | 
					            return Err(StructureExtraction("VM memory is invalid!").into());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -282,6 +291,12 @@ impl VMInfo {
 | 
				
			|||||||
            title: self.title.clone(),
 | 
					            title: self.title.clone(),
 | 
				
			||||||
            description: self.description.clone(),
 | 
					            description: self.description.clone(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            metadata: Some(DomainMetadataXML {
 | 
				
			||||||
 | 
					                virtweb: DomainMetadataVirtWebXML {
 | 
				
			||||||
 | 
					                    ns: "https://virtweb.communiquons.org".to_string(),
 | 
				
			||||||
 | 
					                    group: self.group.clone(),
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
            os: OSXML {
 | 
					            os: OSXML {
 | 
				
			||||||
                r#type: OSTypeXML {
 | 
					                r#type: OSTypeXML {
 | 
				
			||||||
                    arch: match self.architecture {
 | 
					                    arch: match self.architecture {
 | 
				
			||||||
@@ -369,6 +384,7 @@ impl VMInfo {
 | 
				
			|||||||
            genid: domain.genid.map(XMLUuid),
 | 
					            genid: domain.genid.map(XMLUuid),
 | 
				
			||||||
            title: domain.title,
 | 
					            title: domain.title,
 | 
				
			||||||
            description: domain.description,
 | 
					            description: domain.description,
 | 
				
			||||||
 | 
					            group: domain.metadata.clone().unwrap_or_default().virtweb.group,
 | 
				
			||||||
            boot_type: match domain.os.loader {
 | 
					            boot_type: match domain.os.loader {
 | 
				
			||||||
                None => BootType::UEFI,
 | 
					                None => BootType::UEFI,
 | 
				
			||||||
                Some(l) => match l.secure.as_str() {
 | 
					                Some(l) => match l.secure.as_str() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -79,8 +79,6 @@ function VMListWidget(p: {
 | 
				
			|||||||
    setRunningVMs(new Set([...runningVMs]));
 | 
					    setRunningVMs(new Set([...runningVMs]));
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  console.log(runningVMs);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <TableContainer component={Paper}>
 | 
					    <TableContainer component={Paper}>
 | 
				
			||||||
      <Table>
 | 
					      <Table>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user