diff --git a/virtweb_backend/src/controllers/network_controller.rs b/virtweb_backend/src/controllers/network_controller.rs index 562fc40..1382630 100644 --- a/virtweb_backend/src/controllers/network_controller.rs +++ b/virtweb_backend/src/controllers/network_controller.rs @@ -71,7 +71,15 @@ pub async fn update( path: web::Path, body: web::Json, ) -> HttpResult { - let mut network = body.0.to_virt_network()?; + let mut network = match body.0.to_virt_network() { + Ok(n) => n, + Err(e) => { + log::error!("Failed to extract network info! {e}"); + return Ok( + HttpResponse::BadRequest().json(format!("Failed to extract network info!\n${e}")) + ); + } + }; network.uuid = Some(path.uid); if let Err(e) = client.update_network(network).await { diff --git a/virtweb_backend/src/libvirt_lib_structures.rs b/virtweb_backend/src/libvirt_lib_structures.rs index d17d136..34ac820 100644 --- a/virtweb_backend/src/libvirt_lib_structures.rs +++ b/virtweb_backend/src/libvirt_lib_structures.rs @@ -378,6 +378,14 @@ pub struct NetworkForwardXML { pub dev: String, } +/// Network bridge information +#[derive(serde::Serialize, serde::Deserialize, Debug)] +#[serde(rename = "bridge")] +pub struct NetworkBridgeXML { + #[serde(rename(serialize = "@name"))] + pub name: String, +} + /// Network DNS information #[derive(serde::Serialize, serde::Deserialize, Debug)] #[serde(rename = "dns")] @@ -500,6 +508,8 @@ pub struct NetworkXML { #[serde(skip_serializing_if = "Option::is_none")] pub forward: Option, #[serde(skip_serializing_if = "Option::is_none")] + pub bridge: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub dns: Option, #[serde(skip_serializing_if = "Option::is_none")] pub domain: Option, diff --git a/virtweb_backend/src/libvirt_rest_structures.rs b/virtweb_backend/src/libvirt_rest_structures.rs index 98fcff1..c5ea09d 100644 --- a/virtweb_backend/src/libvirt_rest_structures.rs +++ b/virtweb_backend/src/libvirt_rest_structures.rs @@ -4,9 +4,10 @@ use crate::libvirt_lib_structures::{ DevicesXML, DiskBootXML, DiskDriverXML, DiskReadOnlyXML, DiskSourceXML, DiskTargetXML, DiskXML, DomainCPUTopology, DomainCPUXML, DomainInputXML, DomainMemoryXML, DomainNetInterfaceXML, DomainVCPUXML, DomainXML, FeaturesXML, GraphicsXML, NetIntSourceXML, NetMacAddress, - NetworkDHCPHostXML, NetworkDHCPRangeXML, NetworkDHCPXML, NetworkDNSForwarderXML, NetworkDNSXML, - NetworkDomainXML, NetworkForwardXML, NetworkIPXML, NetworkXML, OSLoaderXML, OSTypeXML, - TPMBackendXML, TPMDeviceXML, VideoModelXML, VideoXML, XMLUuid, ACPIXML, OSXML, + NetworkBridgeXML, NetworkDHCPHostXML, NetworkDHCPRangeXML, NetworkDHCPXML, + NetworkDNSForwarderXML, NetworkDNSXML, NetworkDomainXML, NetworkForwardXML, NetworkIPXML, + NetworkXML, OSLoaderXML, OSTypeXML, TPMBackendXML, TPMDeviceXML, VideoModelXML, VideoXML, + XMLUuid, ACPIXML, OSXML, }; use crate::libvirt_rest_structures::LibVirtStructError::StructureExtraction; use crate::utils::disks_utils::Disk; @@ -492,6 +493,7 @@ pub struct NetworkInfo { description: Option, forward_mode: NetworkForwardMode, device: Option, + bridge_name: Option, dns_server: Option, domain: Option, ip_v4: Option, @@ -516,6 +518,12 @@ impl NetworkInfo { } } + if let Some(bridge) = &self.bridge_name { + if !regex!("^[a-zA-Z0-9]+$").is_match(bridge) { + return Err(StructureExtraction("Network bridge name is invalid!").into()); + } + } + if let Some(domain) = &self.domain { if !regex!("^[a-zA-Z0-9.]+$").is_match(domain) { return Err(StructureExtraction("Domain name is invalid!").into()); @@ -594,6 +602,9 @@ impl NetworkInfo { }), NetworkForwardMode::Isolated => None, }, + bridge: self.bridge_name.map(|b| NetworkBridgeXML { + name: b.to_string(), + }), dns: self.dns_server.map(|addr| NetworkDNSXML { forwarder: NetworkDNSForwarderXML { addr }, }), @@ -619,6 +630,7 @@ impl NetworkInfo { false => Some(f.dev), }) .unwrap_or(None), + bridge_name: xml.bridge.map(|b| b.name), dns_server: xml.dns.map(|d| d.forwarder.addr), domain: xml.domain.map(|d| d.name), ip_v4: xml diff --git a/virtweb_frontend/src/api/NetworksApi.ts b/virtweb_frontend/src/api/NetworksApi.ts index 4ceadaf..a7f6702 100644 --- a/virtweb_frontend/src/api/NetworksApi.ts +++ b/virtweb_frontend/src/api/NetworksApi.ts @@ -26,6 +26,7 @@ export interface NetworkInfo { description?: string; forward_mode: "NAT" | "Isolated"; device?: string; + bridge_name?: string; dns_server?: string; domain?: string; ip_v4?: IpConfig; diff --git a/virtweb_frontend/src/widgets/net/NetworkDetails.tsx b/virtweb_frontend/src/widgets/net/NetworkDetails.tsx index 1b71aca..1b20276 100644 --- a/virtweb_frontend/src/widgets/net/NetworkDetails.tsx +++ b/virtweb_frontend/src/widgets/net/NetworkDetails.tsx @@ -128,6 +128,17 @@ function NetworkDetailsInner( /> )} + { + p.net.bridge_name = v; + p.onChange?.(); + }} + value={p.net.bridge_name} + checkValue={(v) => v === "" || /^[a-zA-Z0-9]+$/.test(v)} + /> +