Use quick-xml to serialize domains definitions
This commit is contained in:
		@@ -128,7 +128,7 @@ impl Handler<DefineDomainReq> for LibVirtActor {
 | 
			
		||||
    type Result = anyhow::Result<XMLUuid>;
 | 
			
		||||
 | 
			
		||||
    fn handle(&mut self, mut msg: DefineDomainReq, _ctx: &mut Self::Context) -> Self::Result {
 | 
			
		||||
        let xml = msg.1.into_xml()?;
 | 
			
		||||
        let xml = msg.1.as_xml()?;
 | 
			
		||||
 | 
			
		||||
        log::debug!("Define domain:\n{}", xml);
 | 
			
		||||
        let domain = Domain::define_xml(&self.m, &xml)?;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ use crate::libvirt_lib_structures::XMLUuid;
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "os")]
 | 
			
		||||
pub struct OSXML {
 | 
			
		||||
    #[serde(rename(serialize = "@firmware"), default)]
 | 
			
		||||
    #[serde(rename = "@firmware", default)]
 | 
			
		||||
    pub firmware: String,
 | 
			
		||||
    pub r#type: OSTypeXML,
 | 
			
		||||
    pub loader: Option<OSLoaderXML>,
 | 
			
		||||
@@ -14,9 +14,9 @@ pub struct OSXML {
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "os")]
 | 
			
		||||
pub struct OSTypeXML {
 | 
			
		||||
    #[serde(rename(serialize = "@arch"))]
 | 
			
		||||
    #[serde(rename = "@arch")]
 | 
			
		||||
    pub arch: String,
 | 
			
		||||
    #[serde(rename(serialize = "@machine"))]
 | 
			
		||||
    #[serde(rename = "@machine")]
 | 
			
		||||
    pub machine: String,
 | 
			
		||||
    #[serde(rename = "$value")]
 | 
			
		||||
    pub body: String,
 | 
			
		||||
@@ -26,7 +26,7 @@ pub struct OSTypeXML {
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "loader")]
 | 
			
		||||
pub struct OSLoaderXML {
 | 
			
		||||
    #[serde(rename(serialize = "@secure"))]
 | 
			
		||||
    #[serde(rename = "@secure")]
 | 
			
		||||
    pub secure: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -45,28 +45,28 @@ pub struct ACPIXML {}
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "mac")]
 | 
			
		||||
pub struct NetMacAddress {
 | 
			
		||||
    #[serde(rename(serialize = "@address"))]
 | 
			
		||||
    #[serde(rename = "@address")]
 | 
			
		||||
    pub address: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "source")]
 | 
			
		||||
pub struct NetIntSourceXML {
 | 
			
		||||
    #[serde(rename(serialize = "@network"))]
 | 
			
		||||
    #[serde(rename = "@network")]
 | 
			
		||||
    pub network: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "model")]
 | 
			
		||||
pub struct NetIntModelXML {
 | 
			
		||||
    #[serde(rename(serialize = "@type"))]
 | 
			
		||||
    #[serde(rename = "@type")]
 | 
			
		||||
    pub r#type: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "interface")]
 | 
			
		||||
pub struct DomainNetInterfaceXML {
 | 
			
		||||
    #[serde(rename(serialize = "@type"))]
 | 
			
		||||
    #[serde(rename = "@type")]
 | 
			
		||||
    pub r#type: String,
 | 
			
		||||
    pub mac: NetMacAddress,
 | 
			
		||||
    #[serde(skip_serializing_if = "Option::is_none")]
 | 
			
		||||
@@ -78,24 +78,24 @@ pub struct DomainNetInterfaceXML {
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "input")]
 | 
			
		||||
pub struct DomainInputXML {
 | 
			
		||||
    #[serde(rename(serialize = "@type"))]
 | 
			
		||||
    #[serde(rename = "@type")]
 | 
			
		||||
    pub r#type: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "backend")]
 | 
			
		||||
pub struct TPMBackendXML {
 | 
			
		||||
    #[serde(rename(serialize = "@type"))]
 | 
			
		||||
    #[serde(rename = "@type")]
 | 
			
		||||
    pub r#type: String,
 | 
			
		||||
 | 
			
		||||
    #[serde(rename(serialize = "@version"))]
 | 
			
		||||
    #[serde(rename = "@version")]
 | 
			
		||||
    pub r#version: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "tpm")]
 | 
			
		||||
pub struct TPMDeviceXML {
 | 
			
		||||
    #[serde(rename(serialize = "@model"))]
 | 
			
		||||
    #[serde(rename = "@model")]
 | 
			
		||||
    pub model: String,
 | 
			
		||||
    pub backend: TPMBackendXML,
 | 
			
		||||
}
 | 
			
		||||
@@ -133,9 +133,9 @@ pub struct DevicesXML {
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "graphics")]
 | 
			
		||||
pub struct GraphicsXML {
 | 
			
		||||
    #[serde(rename(serialize = "@type"))]
 | 
			
		||||
    #[serde(rename = "@type")]
 | 
			
		||||
    pub r#type: String,
 | 
			
		||||
    #[serde(rename(serialize = "@socket"))]
 | 
			
		||||
    #[serde(rename = "@socket")]
 | 
			
		||||
    pub socket: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -150,7 +150,7 @@ pub struct VideoXML {
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "model")]
 | 
			
		||||
pub struct VideoModelXML {
 | 
			
		||||
    #[serde(rename(serialize = "@type"))]
 | 
			
		||||
    #[serde(rename = "@type")]
 | 
			
		||||
    pub r#type: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -158,9 +158,9 @@ pub struct VideoModelXML {
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "disk")]
 | 
			
		||||
pub struct DiskXML {
 | 
			
		||||
    #[serde(rename(serialize = "@type"))]
 | 
			
		||||
    #[serde(rename = "@type")]
 | 
			
		||||
    pub r#type: String,
 | 
			
		||||
    #[serde(rename(serialize = "@device"))]
 | 
			
		||||
    #[serde(rename = "@device")]
 | 
			
		||||
    pub r#device: String,
 | 
			
		||||
 | 
			
		||||
    pub driver: DiskDriverXML,
 | 
			
		||||
@@ -176,27 +176,27 @@ pub struct DiskXML {
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "driver")]
 | 
			
		||||
pub struct DiskDriverXML {
 | 
			
		||||
    #[serde(rename(serialize = "@name"))]
 | 
			
		||||
    #[serde(rename = "@name")]
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    #[serde(rename(serialize = "@type"))]
 | 
			
		||||
    #[serde(rename = "@type")]
 | 
			
		||||
    pub r#type: String,
 | 
			
		||||
    #[serde(default, rename(serialize = "@cache"))]
 | 
			
		||||
    #[serde(default, rename = "@cache")]
 | 
			
		||||
    pub r#cache: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "source")]
 | 
			
		||||
pub struct DiskSourceXML {
 | 
			
		||||
    #[serde(rename(serialize = "@file"))]
 | 
			
		||||
    #[serde(rename = "@file")]
 | 
			
		||||
    pub file: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "target")]
 | 
			
		||||
pub struct DiskTargetXML {
 | 
			
		||||
    #[serde(rename(serialize = "@dev"))]
 | 
			
		||||
    #[serde(rename = "@dev")]
 | 
			
		||||
    pub dev: String,
 | 
			
		||||
    #[serde(rename(serialize = "@bus"))]
 | 
			
		||||
    #[serde(rename = "@bus")]
 | 
			
		||||
    pub bus: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -207,34 +207,26 @@ pub struct DiskReadOnlyXML {}
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "boot")]
 | 
			
		||||
pub struct DiskBootXML {
 | 
			
		||||
    #[serde(rename(serialize = "@order"))]
 | 
			
		||||
    #[serde(rename = "@order")]
 | 
			
		||||
    pub order: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "address")]
 | 
			
		||||
pub struct DiskAddressXML {
 | 
			
		||||
    #[serde(rename(serialize = "@type"))]
 | 
			
		||||
    #[serde(rename = "@type")]
 | 
			
		||||
    pub r#type: String,
 | 
			
		||||
    #[serde(
 | 
			
		||||
        default,
 | 
			
		||||
        skip_serializing_if = "Option::is_none",
 | 
			
		||||
        rename(serialize = "@controller")
 | 
			
		||||
        rename = "@controller"
 | 
			
		||||
    )]
 | 
			
		||||
    pub r#controller: Option<String>,
 | 
			
		||||
    #[serde(rename(serialize = "@bus"))]
 | 
			
		||||
    #[serde(rename = "@bus")]
 | 
			
		||||
    pub r#bus: String,
 | 
			
		||||
    #[serde(
 | 
			
		||||
        default,
 | 
			
		||||
        skip_serializing_if = "Option::is_none",
 | 
			
		||||
        rename(serialize = "@target")
 | 
			
		||||
    )]
 | 
			
		||||
    #[serde(default, skip_serializing_if = "Option::is_none", rename = "@target")]
 | 
			
		||||
    pub r#target: Option<String>,
 | 
			
		||||
    #[serde(
 | 
			
		||||
        default,
 | 
			
		||||
        skip_serializing_if = "Option::is_none",
 | 
			
		||||
        rename(serialize = "@unit")
 | 
			
		||||
    )]
 | 
			
		||||
    #[serde(default, skip_serializing_if = "Option::is_none", rename = "@unit")]
 | 
			
		||||
    pub r#unit: Option<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -242,7 +234,7 @@ pub struct DiskAddressXML {
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "memory")]
 | 
			
		||||
pub struct DomainMemoryXML {
 | 
			
		||||
    #[serde(rename(serialize = "@unit"))]
 | 
			
		||||
    #[serde(rename = "@unit")]
 | 
			
		||||
    pub unit: String,
 | 
			
		||||
 | 
			
		||||
    #[serde(rename = "$value")]
 | 
			
		||||
@@ -252,11 +244,11 @@ pub struct DomainMemoryXML {
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "topology")]
 | 
			
		||||
pub struct DomainCPUTopology {
 | 
			
		||||
    #[serde(rename(serialize = "@sockets"))]
 | 
			
		||||
    #[serde(rename = "@sockets")]
 | 
			
		||||
    pub sockets: usize,
 | 
			
		||||
    #[serde(rename(serialize = "@cores"))]
 | 
			
		||||
    #[serde(rename = "@cores")]
 | 
			
		||||
    pub cores: usize,
 | 
			
		||||
    #[serde(rename(serialize = "@threads"))]
 | 
			
		||||
    #[serde(rename = "@threads")]
 | 
			
		||||
    pub threads: usize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -270,7 +262,7 @@ pub struct DomainVCPUXML {
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "cpu")]
 | 
			
		||||
pub struct DomainCPUXML {
 | 
			
		||||
    #[serde(rename(serialize = "@mode"))]
 | 
			
		||||
    #[serde(rename = "@mode")]
 | 
			
		||||
    pub mode: String,
 | 
			
		||||
    pub topology: Option<DomainCPUTopology>,
 | 
			
		||||
}
 | 
			
		||||
@@ -280,7 +272,7 @@ pub struct DomainCPUXML {
 | 
			
		||||
#[serde(rename = "domain")]
 | 
			
		||||
pub struct DomainXML {
 | 
			
		||||
    /// Domain type (kvm)
 | 
			
		||||
    #[serde(rename(serialize = "@type"))]
 | 
			
		||||
    #[serde(rename = "@type")]
 | 
			
		||||
    pub r#type: String,
 | 
			
		||||
 | 
			
		||||
    pub name: String,
 | 
			
		||||
@@ -310,37 +302,12 @@ pub struct DomainXML {
 | 
			
		||||
impl DomainXML {
 | 
			
		||||
    /// Decode Domain structure from XML definition
 | 
			
		||||
    pub fn parse_xml(xml: &str) -> anyhow::Result<Self> {
 | 
			
		||||
        Ok(serde_xml_rs::from_str(xml)?)
 | 
			
		||||
        Ok(quick_xml::de::from_str(xml)?)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Turn this domain into its XML definition
 | 
			
		||||
    pub fn into_xml(mut self) -> anyhow::Result<String> {
 | 
			
		||||
        // A issue with the disks & network interface definition serialization needs them to be serialized aside
 | 
			
		||||
        let mut devices_xml = Vec::with_capacity(self.devices.disks.len());
 | 
			
		||||
        for disk in self.devices.disks {
 | 
			
		||||
            let disk_xml = serde_xml_rs::to_string(&disk)?;
 | 
			
		||||
            let start_offset = disk_xml.find("<disk").unwrap();
 | 
			
		||||
            devices_xml.push(disk_xml[start_offset..].to_string());
 | 
			
		||||
        }
 | 
			
		||||
        for network in self.devices.net_interfaces {
 | 
			
		||||
            let network_xml = serde_xml_rs::to_string(&network)?;
 | 
			
		||||
            let start_offset = network_xml.find("<interface").unwrap();
 | 
			
		||||
            devices_xml.push(network_xml[start_offset..].to_string());
 | 
			
		||||
        }
 | 
			
		||||
        for input in self.devices.inputs {
 | 
			
		||||
            let input_xml = serde_xml_rs::to_string(&input)?;
 | 
			
		||||
            let start_offset = input_xml.find("<input").unwrap();
 | 
			
		||||
            devices_xml.push(input_xml[start_offset..].to_string());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.devices.disks = vec![];
 | 
			
		||||
        self.devices.net_interfaces = vec![];
 | 
			
		||||
        self.devices.inputs = vec![];
 | 
			
		||||
 | 
			
		||||
        let mut xml = serde_xml_rs::to_string(&self)?;
 | 
			
		||||
        let disks_xml = devices_xml.join("\n");
 | 
			
		||||
        xml = xml.replacen("<devices>", &format!("<devices>{disks_xml}"), 1);
 | 
			
		||||
        Ok(xml)
 | 
			
		||||
    pub fn as_xml(&self) -> anyhow::Result<String> {
 | 
			
		||||
        Ok(quick_xml::se::to_string(self)?)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user