Use quick-xml to serialize network definitions

This commit is contained in:
Pierre HUBERT 2024-01-02 14:31:34 +01:00
parent e638829da7
commit 9256b76495
3 changed files with 22 additions and 71 deletions

View File

@ -389,7 +389,7 @@ impl Handler<DefineNetwork> for LibVirtActor {
log::debug!("Define network: {:?}", msg.1); log::debug!("Define network: {:?}", msg.1);
log::debug!("Source network structure: {:#?}", msg.1); log::debug!("Source network structure: {:#?}", msg.1);
let network_xml = msg.1.into_xml()?; let network_xml = msg.1.as_xml()?;
log::debug!("Define network XML: {network_xml}"); log::debug!("Define network XML: {network_xml}");
let network = Network::define_xml(&self.m, &network_xml)?; let network = Network::define_xml(&self.m, &network_xml)?;

View File

@ -5,13 +5,9 @@ use std::net::{IpAddr, Ipv4Addr};
#[derive(serde::Serialize, serde::Deserialize, Debug)] #[derive(serde::Serialize, serde::Deserialize, Debug)]
#[serde(rename = "forward")] #[serde(rename = "forward")]
pub struct NetworkForwardXML { pub struct NetworkForwardXML {
#[serde(rename(serialize = "@mode"))] #[serde(rename = "@mode")]
pub mode: String, pub mode: String,
#[serde( #[serde(default, rename = "@dev", skip_serializing_if = "String::is_empty")]
default,
rename(serialize = "@dev"),
skip_serializing_if = "String::is_empty"
)]
pub dev: String, pub dev: String,
} }
@ -19,7 +15,7 @@ pub struct NetworkForwardXML {
#[derive(serde::Serialize, serde::Deserialize, Debug)] #[derive(serde::Serialize, serde::Deserialize, Debug)]
#[serde(rename = "bridge")] #[serde(rename = "bridge")]
pub struct NetworkBridgeXML { pub struct NetworkBridgeXML {
#[serde(rename(serialize = "@name"))] #[serde(rename = "@name")]
pub name: String, pub name: String,
} }
@ -35,7 +31,7 @@ pub struct NetworkDNSXML {
#[serde(rename = "forwarder")] #[serde(rename = "forwarder")]
pub struct NetworkDNSForwarderXML { pub struct NetworkDNSForwarderXML {
/// Address of the DNS server /// Address of the DNS server
#[serde(rename(serialize = "@addr"))] #[serde(rename = "@addr")]
pub addr: Ipv4Addr, pub addr: Ipv4Addr,
} }
@ -43,7 +39,7 @@ pub struct NetworkDNSForwarderXML {
#[derive(serde::Serialize, serde::Deserialize, Debug)] #[derive(serde::Serialize, serde::Deserialize, Debug)]
#[serde(rename = "domain")] #[serde(rename = "domain")]
pub struct NetworkDomainXML { pub struct NetworkDomainXML {
#[serde(rename(serialize = "@name"))] #[serde(rename = "@name")]
pub name: String, pub name: String,
} }
@ -59,50 +55,20 @@ fn invalid_ip() -> IpAddr {
#[derive(serde::Serialize, serde::Deserialize, Debug)] #[derive(serde::Serialize, serde::Deserialize, Debug)]
#[serde(rename = "ip")] #[serde(rename = "ip")]
pub struct NetworkIPXML { pub struct NetworkIPXML {
#[serde(default, rename(serialize = "@family"))] #[serde(default, rename = "@family")]
pub family: String, pub family: String,
#[serde(rename(serialize = "@address"))] #[serde(rename = "@address")]
pub address: IpAddr, pub address: IpAddr,
/// Network Prefix /// Network Prefix
#[serde(rename(serialize = "@prefix"), default = "invalid_prefix")] #[serde(rename = "@prefix", default = "invalid_prefix")]
pub prefix: u32, pub prefix: u32,
/// Network Netmask. This field is never serialized, but because we can't know if LibVirt will /// Network Netmask. This field is never serialized, but because we can't know if LibVirt will
/// provide us netmask or prefix, we need to handle both of these fields /// provide us netmask or prefix, we need to handle both of these fields
#[serde( #[serde(rename = "@netmask", default = "invalid_ip", skip_serializing)]
rename(serialize = "@netmask"),
default = "invalid_ip",
skip_serializing
)]
pub netmask: IpAddr, pub netmask: IpAddr,
pub dhcp: Option<NetworkDHCPXML>, pub dhcp: Option<NetworkDHCPXML>,
} }
impl NetworkIPXML {
pub fn into_xml(mut self) -> anyhow::Result<String> {
let mut hosts_xml = vec![];
if let Some(dhcp) = &mut self.dhcp {
for host in &dhcp.hosts {
let mut host_xml = serde_xml_rs::to_string(&host)?;
// In case of IPv6, mac address should not be specified
host_xml = host_xml.replace("mac=\"\"", "");
// strip xml tag
let start_offset = host_xml.find("<host").unwrap();
hosts_xml.push(host_xml[start_offset..].to_string());
}
dhcp.hosts = vec![];
}
let mut res = serde_xml_rs::to_string(&self)?;
let hosts_xml = hosts_xml.join("\n");
res = res.replace("</dhcp>", &format!("{hosts_xml}</dhcp>"));
Ok(res)
}
}
#[derive(serde::Serialize, serde::Deserialize, Debug)] #[derive(serde::Serialize, serde::Deserialize, Debug)]
#[serde(rename = "dhcp")] #[serde(rename = "dhcp")]
pub struct NetworkDHCPXML { pub struct NetworkDHCPXML {
@ -114,20 +80,20 @@ pub struct NetworkDHCPXML {
#[derive(serde::Serialize, serde::Deserialize, Debug)] #[derive(serde::Serialize, serde::Deserialize, Debug)]
#[serde(rename = "host")] #[serde(rename = "host")]
pub struct NetworkDHCPHostXML { pub struct NetworkDHCPHostXML {
#[serde(rename(serialize = "@mac"), default)] #[serde(rename = "@mac", default, skip_serializing_if = "Option::is_none")]
pub mac: String, pub mac: Option<String>,
#[serde(rename(serialize = "@name"))] #[serde(rename = "@name")]
pub name: String, pub name: String,
#[serde(rename(serialize = "@ip"))] #[serde(rename = "@ip")]
pub ip: IpAddr, pub ip: IpAddr,
} }
#[derive(serde::Serialize, serde::Deserialize, Debug)] #[derive(serde::Serialize, serde::Deserialize, Debug)]
#[serde(rename = "dhcp")] #[serde(rename = "dhcp")]
pub struct NetworkDHCPRangeXML { pub struct NetworkDHCPRangeXML {
#[serde(rename(serialize = "@start"))] #[serde(rename = "@start")]
pub start: IpAddr, pub start: IpAddr,
#[serde(rename(serialize = "@end"))] #[serde(rename = "@end")]
pub end: IpAddr, pub end: IpAddr,
} }
@ -156,25 +122,10 @@ pub struct NetworkXML {
impl NetworkXML { impl NetworkXML {
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)?)
} }
pub fn into_xml(mut self) -> anyhow::Result<String> {
// A issue with the IPs definition serialization needs them to be serialized aside
let mut ips_xml = Vec::with_capacity(self.ips.len());
for ip in self.ips {
log::debug!("Serialize {ip:?}");
let ip_xml = ip.into_xml()?;
// strip xml tag
let start_offset = ip_xml.find("<ip").unwrap();
ips_xml.push(ip_xml[start_offset..].to_string());
}
self.ips = vec![];
let mut network_xml = serde_xml_rs::to_string(&self)?; pub fn as_xml(&self) -> anyhow::Result<String> {
log::trace!("Serialize network XML start: {network_xml}"); Ok(quick_xml::se::to_string(self)?)
let ips_xml = ips_xml.join("\n");
network_xml = network_xml.replacen("</network>", &format!("{ips_xml}</network>"), 1);
Ok(network_xml)
} }
} }

View File

@ -123,7 +123,7 @@ impl NetworkInfo {
.hosts .hosts
.iter() .iter()
.map(|c| NetworkDHCPHostXML { .map(|c| NetworkDHCPHostXML {
mac: c.mac.to_string(), mac: Some(c.mac.to_string()),
name: c.name.to_string(), name: c.name.to_string(),
ip: c.ip.into(), ip: c.ip.into(),
}) })
@ -150,7 +150,7 @@ impl NetworkInfo {
.hosts .hosts
.iter() .iter()
.map(|h| NetworkDHCPHostXML { .map(|h| NetworkDHCPHostXML {
mac: "".to_string(), mac: None,
name: h.name.to_string(), name: h.name.to_string(),
ip: h.ip.into(), ip: h.ip.into(),
}) })
@ -221,7 +221,7 @@ impl NetworkInfo {
.hosts .hosts
.iter() .iter()
.map(|h| DHCPv4HostReservation { .map(|h| DHCPv4HostReservation {
mac: h.mac.to_string(), mac: h.mac.clone().unwrap_or_default(),
name: h.name.to_string(), name: h.name.to_string(),
ip: extract_ipv4(h.ip), ip: extract_ipv4(h.ip),
}) })