Add REST route to get networks list

This commit is contained in:
Pierre HUBERT 2023-10-31 10:51:13 +01:00
parent f2237d4f2f
commit 2741faa95b
7 changed files with 125 additions and 2 deletions

View File

@ -377,3 +377,39 @@ impl Handler<DefineNetwork> for LibVirtActor {
XMLUuid::parse_from_str(&network.get_uuid_string()?)
}
}
#[derive(Message)]
#[rtype(result = "anyhow::Result<Vec<XMLUuid>>")]
pub struct GetNetworksListReq;
impl Handler<GetNetworksListReq> for LibVirtActor {
type Result = anyhow::Result<Vec<XMLUuid>>;
fn handle(&mut self, _msg: GetNetworksListReq, _ctx: &mut Self::Context) -> Self::Result {
log::debug!("Get full list of networks");
let networks = self.m.list_all_networks(0)?;
let mut ids = Vec::with_capacity(networks.len());
for d in networks {
ids.push(XMLUuid::parse_from_str(&d.get_uuid_string()?)?);
}
Ok(ids)
}
}
#[derive(Message)]
#[rtype(result = "anyhow::Result<NetworkXML>")]
pub struct GetNetworkXMLReq(pub XMLUuid);
impl Handler<GetNetworkXMLReq> for LibVirtActor {
type Result = anyhow::Result<NetworkXML>;
fn handle(&mut self, msg: GetNetworkXMLReq, _ctx: &mut Self::Context) -> Self::Result {
log::debug!("Get network XML:\n{}", msg.0.as_string());
let network = Network::lookup_by_uuid_string(&self.m, &msg.0.as_string())?;
let xml = network.get_xml_desc(0)?;
log::debug!("XML = {}", xml);
Ok(serde_xml_rs::from_str(&xml)?)
}
}

View File

@ -21,3 +21,15 @@ pub async fn create(client: LibVirtReq, req: web::Json<NetworkInfo>) -> HttpResu
Ok(HttpResponse::Ok().json(NetworkID { id }))
}
/// Get the list of networks
pub async fn list(client: LibVirtReq) -> HttpResult {
let networks = client
.get_full_networks_list()
.await?
.into_iter()
.map(|n| NetworkInfo::from_xml(n).unwrap())
.collect::<Vec<_>>();
Ok(HttpResponse::Ok().json(networks))
}

View File

@ -34,7 +34,7 @@ pub async fn create(client: LibVirtReq, req: web::Json<VMInfo>) -> HttpResult {
/// Get the list of domains
pub async fn list_all(client: LibVirtReq) -> HttpResult {
let list = client.get_full_list().await?;
let list = client.get_full_domains_list().await?;
let mut out = Vec::with_capacity(list.len());
for entry in list {

View File

@ -14,7 +14,7 @@ impl LibVirtClient {
}
/// Get the full list of domain
pub async fn get_full_list(&self) -> anyhow::Result<Vec<DomainXML>> {
pub async fn get_full_domains_list(&self) -> anyhow::Result<Vec<DomainXML>> {
let ids = self.0.send(libvirt_actor::GetDomainsListReq).await??;
let mut info = Vec::with_capacity(ids.len());
for id in ids {
@ -96,4 +96,19 @@ impl LibVirtClient {
pub async fn update_network(&self, network: NetworkXML) -> anyhow::Result<XMLUuid> {
self.0.send(libvirt_actor::DefineNetwork(network)).await?
}
/// Get the full list of networks
pub async fn get_full_networks_list(&self) -> anyhow::Result<Vec<NetworkXML>> {
let ids = self.0.send(libvirt_actor::GetNetworksListReq).await??;
let mut info = Vec::with_capacity(ids.len());
for id in ids {
info.push(self.get_single_network(id).await?)
}
Ok(info)
}
/// Get the information about a single network
pub async fn get_single_network(&self, id: XMLUuid) -> anyhow::Result<NetworkXML> {
self.0.send(libvirt_actor::GetNetworkXMLReq(id)).await?
}
}

View File

@ -304,5 +304,6 @@ pub struct NetworkXML {
pub dns: Option<NetworkDNSXML>,
#[serde(skip_serializing_if = "Option::is_none")]
pub domain: Option<NetworkDomainXML>,
#[serde(default, rename = "ip")]
pub ips: Vec<NetworkIPXML>,
}

View File

@ -423,6 +423,64 @@ impl NetworkInfo {
ips,
})
}
pub fn from_xml(xml: NetworkXML) -> anyhow::Result<Self> {
Ok(Self {
name: xml.name,
uuid: xml.uuid,
title: xml.title,
description: xml.description,
forward_mode: match xml.forward {
None => NetworkForwardMode::Isolated,
Some(_) => NetworkForwardMode::NAT,
},
device: xml.forward.map(|f| f.dev).unwrap_or(None),
dns_server: xml.dns.map(|d| d.forwarder.addr),
domain: xml.domain.map(|d| d.name),
ip_v4: xml
.ips
.iter()
.find(|i| i.family != "ipv6")
.map(|i| IPV4Config {
bridge_address: extract_ipv4(i.address),
prefix: i.prefix,
dhcp_range: i
.dhcp
.as_ref()
.map(|d| [extract_ipv4(d.range.start), extract_ipv4(d.range.end)]),
}),
ip_v6: xml
.ips
.iter()
.find(|i| i.family == "ipv6")
.map(|i| IPV6Config {
bridge_address: extract_ipv6(i.address),
prefix: i.prefix,
dhcp_range: i
.dhcp
.as_ref()
.map(|d| [extract_ipv6(d.range.start), extract_ipv6(d.range.end)]),
}),
})
}
}
fn extract_ipv4(ip: IpAddr) -> Ipv4Addr {
match ip {
IpAddr::V4(i) => i,
IpAddr::V6(_) => {
panic!("IPv6 found in IPv4 definition!")
}
}
}
fn extract_ipv6(ip: IpAddr) -> Ipv6Addr {
match ip {
IpAddr::V4(_) => {
panic!("IPv4 found in IPv6 definition!")
}
IpAddr::V6(i) => i,
}
}
#[cfg(test)]

View File

@ -181,6 +181,7 @@ async fn main() -> std::io::Result<()> {
"/api/network/create",
web::post().to(network_controller::create),
)
.route("/api/network/list", web::get().to(network_controller::list))
})
.bind(&AppConfig::get().listen_address)?
.run()