Use quick-xml to serialize domains definitions

This commit is contained in:
Pierre HUBERT 2024-01-02 14:40:16 +01:00
parent 9256b76495
commit d741e12653
2 changed files with 39 additions and 72 deletions

View File

@ -128,7 +128,7 @@ impl Handler<DefineDomainReq> for LibVirtActor {
type Result = anyhow::Result<XMLUuid>; type Result = anyhow::Result<XMLUuid>;
fn handle(&mut self, mut msg: DefineDomainReq, _ctx: &mut Self::Context) -> Self::Result { 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); log::debug!("Define domain:\n{}", xml);
let domain = Domain::define_xml(&self.m, &xml)?; let domain = Domain::define_xml(&self.m, &xml)?;

View File

@ -4,7 +4,7 @@ use crate::libvirt_lib_structures::XMLUuid;
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "os")] #[serde(rename = "os")]
pub struct OSXML { pub struct OSXML {
#[serde(rename(serialize = "@firmware"), default)] #[serde(rename = "@firmware", default)]
pub firmware: String, pub firmware: String,
pub r#type: OSTypeXML, pub r#type: OSTypeXML,
pub loader: Option<OSLoaderXML>, pub loader: Option<OSLoaderXML>,
@ -14,9 +14,9 @@ pub struct OSXML {
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "os")] #[serde(rename = "os")]
pub struct OSTypeXML { pub struct OSTypeXML {
#[serde(rename(serialize = "@arch"))] #[serde(rename = "@arch")]
pub arch: String, pub arch: String,
#[serde(rename(serialize = "@machine"))] #[serde(rename = "@machine")]
pub machine: String, pub machine: String,
#[serde(rename = "$value")] #[serde(rename = "$value")]
pub body: String, pub body: String,
@ -26,7 +26,7 @@ pub struct OSTypeXML {
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "loader")] #[serde(rename = "loader")]
pub struct OSLoaderXML { pub struct OSLoaderXML {
#[serde(rename(serialize = "@secure"))] #[serde(rename = "@secure")]
pub secure: String, pub secure: String,
} }
@ -45,28 +45,28 @@ pub struct ACPIXML {}
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "mac")] #[serde(rename = "mac")]
pub struct NetMacAddress { pub struct NetMacAddress {
#[serde(rename(serialize = "@address"))] #[serde(rename = "@address")]
pub address: String, pub address: String,
} }
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "source")] #[serde(rename = "source")]
pub struct NetIntSourceXML { pub struct NetIntSourceXML {
#[serde(rename(serialize = "@network"))] #[serde(rename = "@network")]
pub network: String, pub network: String,
} }
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "model")] #[serde(rename = "model")]
pub struct NetIntModelXML { pub struct NetIntModelXML {
#[serde(rename(serialize = "@type"))] #[serde(rename = "@type")]
pub r#type: String, pub r#type: String,
} }
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "interface")] #[serde(rename = "interface")]
pub struct DomainNetInterfaceXML { pub struct DomainNetInterfaceXML {
#[serde(rename(serialize = "@type"))] #[serde(rename = "@type")]
pub r#type: String, pub r#type: String,
pub mac: NetMacAddress, pub mac: NetMacAddress,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
@ -78,24 +78,24 @@ pub struct DomainNetInterfaceXML {
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "input")] #[serde(rename = "input")]
pub struct DomainInputXML { pub struct DomainInputXML {
#[serde(rename(serialize = "@type"))] #[serde(rename = "@type")]
pub r#type: String, pub r#type: String,
} }
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "backend")] #[serde(rename = "backend")]
pub struct TPMBackendXML { pub struct TPMBackendXML {
#[serde(rename(serialize = "@type"))] #[serde(rename = "@type")]
pub r#type: String, pub r#type: String,
#[serde(rename(serialize = "@version"))] #[serde(rename = "@version")]
pub r#version: String, pub r#version: String,
} }
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "tpm")] #[serde(rename = "tpm")]
pub struct TPMDeviceXML { pub struct TPMDeviceXML {
#[serde(rename(serialize = "@model"))] #[serde(rename = "@model")]
pub model: String, pub model: String,
pub backend: TPMBackendXML, pub backend: TPMBackendXML,
} }
@ -133,9 +133,9 @@ pub struct DevicesXML {
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "graphics")] #[serde(rename = "graphics")]
pub struct GraphicsXML { pub struct GraphicsXML {
#[serde(rename(serialize = "@type"))] #[serde(rename = "@type")]
pub r#type: String, pub r#type: String,
#[serde(rename(serialize = "@socket"))] #[serde(rename = "@socket")]
pub socket: String, pub socket: String,
} }
@ -150,7 +150,7 @@ pub struct VideoXML {
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "model")] #[serde(rename = "model")]
pub struct VideoModelXML { pub struct VideoModelXML {
#[serde(rename(serialize = "@type"))] #[serde(rename = "@type")]
pub r#type: String, pub r#type: String,
} }
@ -158,9 +158,9 @@ pub struct VideoModelXML {
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "disk")] #[serde(rename = "disk")]
pub struct DiskXML { pub struct DiskXML {
#[serde(rename(serialize = "@type"))] #[serde(rename = "@type")]
pub r#type: String, pub r#type: String,
#[serde(rename(serialize = "@device"))] #[serde(rename = "@device")]
pub r#device: String, pub r#device: String,
pub driver: DiskDriverXML, pub driver: DiskDriverXML,
@ -176,27 +176,27 @@ pub struct DiskXML {
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "driver")] #[serde(rename = "driver")]
pub struct DiskDriverXML { pub struct DiskDriverXML {
#[serde(rename(serialize = "@name"))] #[serde(rename = "@name")]
pub name: String, pub name: String,
#[serde(rename(serialize = "@type"))] #[serde(rename = "@type")]
pub r#type: String, pub r#type: String,
#[serde(default, rename(serialize = "@cache"))] #[serde(default, rename = "@cache")]
pub r#cache: String, pub r#cache: String,
} }
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "source")] #[serde(rename = "source")]
pub struct DiskSourceXML { pub struct DiskSourceXML {
#[serde(rename(serialize = "@file"))] #[serde(rename = "@file")]
pub file: String, pub file: String,
} }
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "target")] #[serde(rename = "target")]
pub struct DiskTargetXML { pub struct DiskTargetXML {
#[serde(rename(serialize = "@dev"))] #[serde(rename = "@dev")]
pub dev: String, pub dev: String,
#[serde(rename(serialize = "@bus"))] #[serde(rename = "@bus")]
pub bus: String, pub bus: String,
} }
@ -207,34 +207,26 @@ pub struct DiskReadOnlyXML {}
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "boot")] #[serde(rename = "boot")]
pub struct DiskBootXML { pub struct DiskBootXML {
#[serde(rename(serialize = "@order"))] #[serde(rename = "@order")]
pub order: String, pub order: String,
} }
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "address")] #[serde(rename = "address")]
pub struct DiskAddressXML { pub struct DiskAddressXML {
#[serde(rename(serialize = "@type"))] #[serde(rename = "@type")]
pub r#type: String, pub r#type: String,
#[serde( #[serde(
default, default,
skip_serializing_if = "Option::is_none", skip_serializing_if = "Option::is_none",
rename(serialize = "@controller") rename = "@controller"
)] )]
pub r#controller: Option<String>, pub r#controller: Option<String>,
#[serde(rename(serialize = "@bus"))] #[serde(rename = "@bus")]
pub r#bus: String, pub r#bus: String,
#[serde( #[serde(default, skip_serializing_if = "Option::is_none", rename = "@target")]
default,
skip_serializing_if = "Option::is_none",
rename(serialize = "@target")
)]
pub r#target: Option<String>, pub r#target: Option<String>,
#[serde( #[serde(default, skip_serializing_if = "Option::is_none", rename = "@unit")]
default,
skip_serializing_if = "Option::is_none",
rename(serialize = "@unit")
)]
pub r#unit: Option<String>, pub r#unit: Option<String>,
} }
@ -242,7 +234,7 @@ pub struct DiskAddressXML {
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "memory")] #[serde(rename = "memory")]
pub struct DomainMemoryXML { pub struct DomainMemoryXML {
#[serde(rename(serialize = "@unit"))] #[serde(rename = "@unit")]
pub unit: String, pub unit: String,
#[serde(rename = "$value")] #[serde(rename = "$value")]
@ -252,11 +244,11 @@ pub struct DomainMemoryXML {
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "topology")] #[serde(rename = "topology")]
pub struct DomainCPUTopology { pub struct DomainCPUTopology {
#[serde(rename(serialize = "@sockets"))] #[serde(rename = "@sockets")]
pub sockets: usize, pub sockets: usize,
#[serde(rename(serialize = "@cores"))] #[serde(rename = "@cores")]
pub cores: usize, pub cores: usize,
#[serde(rename(serialize = "@threads"))] #[serde(rename = "@threads")]
pub threads: usize, pub threads: usize,
} }
@ -270,7 +262,7 @@ pub struct DomainVCPUXML {
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "cpu")] #[serde(rename = "cpu")]
pub struct DomainCPUXML { pub struct DomainCPUXML {
#[serde(rename(serialize = "@mode"))] #[serde(rename = "@mode")]
pub mode: String, pub mode: String,
pub topology: Option<DomainCPUTopology>, pub topology: Option<DomainCPUTopology>,
} }
@ -280,7 +272,7 @@ pub struct DomainCPUXML {
#[serde(rename = "domain")] #[serde(rename = "domain")]
pub struct DomainXML { pub struct DomainXML {
/// Domain type (kvm) /// Domain type (kvm)
#[serde(rename(serialize = "@type"))] #[serde(rename = "@type")]
pub r#type: String, pub r#type: String,
pub name: String, pub name: String,
@ -310,37 +302,12 @@ pub struct DomainXML {
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(serde_xml_rs::from_str(xml)?) Ok(quick_xml::de::from_str(xml)?)
} }
/// Turn this domain into its XML definition /// Turn this domain into its XML definition
pub fn into_xml(mut self) -> anyhow::Result<String> { pub fn as_xml(&self) -> anyhow::Result<String> {
// A issue with the disks & network interface definition serialization needs them to be serialized aside Ok(quick_xml::se::to_string(self)?)
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)
} }
} }