diff --git a/opendut-carl/src/actions/peers.rs b/opendut-carl/src/actions/peers.rs index 557ff6047..17202782c 100644 --- a/opendut-carl/src/actions/peers.rs +++ b/opendut-carl/src/actions/peers.rs @@ -15,10 +15,10 @@ pub use opendut_carl_api::carl::peer::{ use opendut_carl_api::proto::services::peer_messaging_broker::{ApplyPeerConfiguration, downstream}; use opendut_types::cluster::ClusterAssignment; use opendut_types::peer::{PeerDescriptor, PeerId, PeerName, PeerSetup}; -use opendut_types::peer::configuration::PeerConfiguration; +use opendut_types::peer::configuration::{PeerConfiguration, PeerNetworkConfiguration}; use opendut_types::proto; use opendut_types::topology::{DeviceDescriptor, DeviceId}; -use opendut_types::util::net::{AuthConfig, Certificate, ClientCredentials}; +use opendut_types::util::net::{AuthConfig, Certificate, ClientCredentials, NetworkInterfaceName}; use opendut_types::vpn::VpnPeerConfiguration; use opendut_util::ErrorOr; use crate::peer::broker::{PeerMessagingBroker, PeerMessagingBrokerRef}; @@ -78,9 +78,19 @@ pub async fn store_peer_descriptor(params: StorePeerDescriptorParams) -> Result< info!("Added device '{device_name}' <{device_id}> of peer '{peer_name}' <{peer_id}>."); }); + let peer_network_configuration = match peer_descriptor.clone().network.bridge_name { + Some(bridge_name) => { + PeerNetworkConfiguration { + bridge_name, + } + } + None => { PeerNetworkConfiguration::default() } + }; + let peer_configuration = PeerConfiguration { executors: Clone::clone(&peer_descriptor.executors), cluster_assignment: None, + network: peer_network_configuration }; resources.insert(peer_id, peer_configuration); @@ -361,7 +371,7 @@ mod test { use googletest::prelude::*; use rstest::*; - use opendut_types::peer::{PeerLocation, PeerName, PeerNetworkConfiguration}; + use opendut_types::peer::{PeerLocation, PeerName, PeerNetworkDescriptor}; use opendut_types::peer::executor::ExecutorDescriptors; use opendut_types::topology::{DeviceDescription, DeviceName, Topology}; use opendut_types::util::net::{NetworkInterfaceConfiguration, NetworkInterfaceDescriptor, NetworkInterfaceName}; @@ -453,6 +463,9 @@ mod test { let peer_configuration = PeerConfiguration { executors: ExecutorDescriptors { executors: vec![] }, cluster_assignment: None, + network: PeerNetworkConfiguration { + bridge_name: NetworkInterfaceName::try_from("br-opendut-1").unwrap() + } }; resources_manager.resources_mut(|resources| { resources.insert(peer_id, Clone::clone(&peer_configuration)); @@ -527,13 +540,14 @@ mod test { id: peer_a_id, name: PeerName::try_from("PeerA").unwrap(), location: PeerLocation::try_from("Ulm").ok(), - network_configuration: PeerNetworkConfiguration { + network: PeerNetworkDescriptor { interfaces: vec![ NetworkInterfaceDescriptor { name: NetworkInterfaceName::try_from("eth0").unwrap(), configuration: NetworkInterfaceConfiguration::Ethernet, }, - ] + ], + bridge_name: Some(NetworkInterfaceName::try_from("br-opendut-1").unwrap()), }, topology: Topology { devices: vec![ diff --git a/opendut-carl/src/cluster/manager.rs b/opendut-carl/src/cluster/manager.rs index b15509472..76785e52a 100644 --- a/opendut-carl/src/cluster/manager.rs +++ b/opendut-carl/src/cluster/manager.rs @@ -285,7 +285,7 @@ mod test { use opendut_carl_api::proto::services::peer_messaging_broker::Downstream; use opendut_carl_api::proto::services::peer_messaging_broker::downstream; use opendut_types::cluster::ClusterName; - use opendut_types::peer::{PeerDescriptor, PeerId, PeerLocation, PeerName, PeerNetworkConfiguration}; + use opendut_types::peer::{PeerDescriptor, PeerId, PeerLocation, PeerName, PeerNetworkDescriptor}; use opendut_types::peer::executor::{ContainerCommand, ContainerImage, ContainerName, Engine, ExecutorDescriptor, ExecutorDescriptors}; use opendut_types::topology::{DeviceDescription, DeviceDescriptor, DeviceId, DeviceName, Topology}; use opendut_types::util::net::{NetworkInterfaceConfiguration, NetworkInterfaceName}; @@ -449,11 +449,12 @@ mod test { id, name: PeerName::try_from(format!("peer-{id}")).unwrap(), location: PeerLocation::try_from("Ulm").ok(), - network_configuration: PeerNetworkConfiguration { + network: PeerNetworkDescriptor { interfaces: vec!(NetworkInterfaceDescriptor { name: NetworkInterfaceName::try_from("eth0").unwrap(), configuration: NetworkInterfaceConfiguration::Ethernet, - }) + }), + bridge_name: Some(NetworkInterfaceName::try_from("br-custom").unwrap()), }, topology: Topology { devices, @@ -539,13 +540,14 @@ mod test { id, name: PeerName::try_from(peer_name).unwrap(), location: PeerLocation::try_from("Ulm").ok(), - network_configuration: PeerNetworkConfiguration { + network: PeerNetworkDescriptor { interfaces: vec![ NetworkInterfaceDescriptor { name: NetworkInterfaceName::try_from("eth0").unwrap(), configuration: NetworkInterfaceConfiguration::Ethernet, } - ] + ], + bridge_name: Some(NetworkInterfaceName::try_from("br-opendut-1").unwrap()), }, topology: Topology { devices: vec![ diff --git a/opendut-carl/src/grpc/peer_manager.rs b/opendut-carl/src/grpc/peer_manager.rs index 57b9fb997..8976f7d60 100644 --- a/opendut-carl/src/grpc/peer_manager.rs +++ b/opendut-carl/src/grpc/peer_manager.rs @@ -236,7 +236,7 @@ mod tests { use crate::peer::oidc_client_manager::tests::oidc_client_manager; use url::Url; - use opendut_types::peer::{PeerLocation, PeerName, PeerNetworkConfiguration}; + use opendut_types::peer::{PeerLocation, PeerName, PeerNetworkDescriptor}; use opendut_types::peer::executor::{ContainerCommand, ContainerImage, ContainerName, Engine, ExecutorDescriptor, ExecutorDescriptors}; use opendut_types::proto; use opendut_types::topology::Topology; @@ -276,13 +276,14 @@ mod tests { id: peer_id, name: PeerName::try_from("TestPeer").unwrap(), location: PeerLocation::try_from("SiFi").ok(), - network_configuration: PeerNetworkConfiguration { + network: PeerNetworkDescriptor { interfaces: vec![ NetworkInterfaceDescriptor { name: NetworkInterfaceName::try_from("eth0").unwrap(), configuration: NetworkInterfaceConfiguration::Ethernet, }, ], + bridge_name: Some(NetworkInterfaceName::try_from("br-opendut-1").unwrap()), }, topology: Topology::default(), executors: ExecutorDescriptors { diff --git a/opendut-carl/src/resources/manager.rs b/opendut-carl/src/resources/manager.rs index 869271c05..70d36d60e 100644 --- a/opendut-carl/src/resources/manager.rs +++ b/opendut-carl/src/resources/manager.rs @@ -80,7 +80,7 @@ mod test { use googletest::prelude::*; use opendut_types::cluster::{ClusterConfiguration, ClusterId, ClusterName}; - use opendut_types::peer::{PeerDescriptor, PeerId, PeerLocation, PeerName, PeerNetworkConfiguration}; + use opendut_types::peer::{PeerDescriptor, PeerId, PeerLocation, PeerName, PeerNetworkDescriptor}; use opendut_types::peer::executor::{ContainerCommand, ContainerImage, ContainerName, Engine, ExecutorDescriptor, ExecutorDescriptors}; use opendut_types::topology::Topology; use opendut_types::util::net::{NetworkInterfaceConfiguration, NetworkInterfaceDescriptor, NetworkInterfaceName}; @@ -97,13 +97,14 @@ mod test { id: peer_resource_id, name: PeerName::try_from("TestPeer").unwrap(), location: PeerLocation::try_from("Ulm").ok(), - network_configuration: PeerNetworkConfiguration { + network: PeerNetworkDescriptor { interfaces: vec![ NetworkInterfaceDescriptor { name: NetworkInterfaceName::try_from("eth0").unwrap(), configuration: NetworkInterfaceConfiguration::Ethernet, }, - ] + ], + bridge_name: Some(NetworkInterfaceName::try_from("br-opendut-1").unwrap()), }, topology: Topology::default(), executors: ExecutorDescriptors { diff --git a/opendut-cleo/src/commands/device/create.rs b/opendut-cleo/src/commands/device/create.rs index e117c4ed2..586f6a3a4 100644 --- a/opendut-cleo/src/commands/device/create.rs +++ b/opendut-cleo/src/commands/device/create.rs @@ -36,7 +36,7 @@ impl CreateDeviceCli { let mut peer_descriptor = carl.peers.get_peer_descriptor(peer_id).await .map_err(|_| format!("Failed to get peer with ID <{}>.", peer_id))?; - let peer_network_interface_names = peer_descriptor.network_configuration.interfaces.iter().map(|peer_interface| { + let peer_network_interface_names = peer_descriptor.network.interfaces.iter().map(|peer_interface| { peer_interface.name.clone() }).collect::>(); let maybe_existing_device = peer_descriptor.topology.devices.iter_mut().find(|device| device.id == device_id); @@ -46,7 +46,7 @@ impl CreateDeviceCli { let name = self.name.ok_or(String::from("Cannot create new device because of missing device name."))?; let interface_name = self.interface.ok_or(String::from("Cannot create new device because of missing interface name."))?; - let interface = match peer_descriptor.network_configuration.interfaces.iter().find(|descriptor| descriptor.name == interface_name) { + let interface = match peer_descriptor.network.interfaces.iter().find(|descriptor| descriptor.name == interface_name) { Some(network_interface_descriptor) => network_interface_descriptor.clone(), None => { Err(format!("Cannot create new device because interface is not one of the allowed values: {} \nAllowed interfaces are configured on the peer.", @@ -83,7 +83,7 @@ impl CreateDeviceCli { .ok(); } if let Some(interface_name) = self.interface { - device.interface = match peer_descriptor.network_configuration.interfaces.iter().find(|descriptor| descriptor.name == interface_name) { + device.interface = match peer_descriptor.network.interfaces.iter().find(|descriptor| descriptor.name == interface_name) { Some(network_interface_descriptor) => network_interface_descriptor.clone(), None => { Err(format!("Cannot create new device because interface is not one of the allowed values: {} \nAllowed interfaces are configured on the peer.", diff --git a/opendut-cleo/src/commands/network_interface/create.rs b/opendut-cleo/src/commands/network_interface/create.rs index a4aa7e9c3..578a9fc17 100644 --- a/opendut-cleo/src/commands/network_interface/create.rs +++ b/opendut-cleo/src/commands/network_interface/create.rs @@ -26,7 +26,7 @@ impl CreateNetworkInterfaceCli { let mut peer_descriptor = carl.peers.get_peer_descriptor(peer_id).await .map_err(|_| format!("Failed to get peer with ID <{}>.", peer_id))?; - let peer_interface_names = peer_descriptor.network_configuration.interfaces + let peer_interface_names = peer_descriptor.network.interfaces .iter().map(|interface| interface.name.clone()).collect::>(); let interface_name = NetworkInterfaceName::try_from(self.interface_name).map_err(|error| error.to_string())?; @@ -46,7 +46,7 @@ impl CreateNetworkInterfaceCli { if peer_interface_names.contains(&interface_name) { Err(format!("Could not create peer network configuration with name '{}' because it already exists", &interface_name))? } else { - peer_descriptor.network_configuration.interfaces.push( + peer_descriptor.network.interfaces.push( NetworkInterfaceDescriptor { name: interface_name, configuration: interface_configuration, diff --git a/opendut-cleo/src/commands/network_interface/delete.rs b/opendut-cleo/src/commands/network_interface/delete.rs index c2a3afb01..c98dea95e 100644 --- a/opendut-cleo/src/commands/network_interface/delete.rs +++ b/opendut-cleo/src/commands/network_interface/delete.rs @@ -40,7 +40,7 @@ impl DeleteNetworkInterfaceCli { Err(format!("Network interface '{}' could not be deleted due to it being used in following devices: {}", name, device_interfaces_map.get(&name).unwrap().join(", ")))? } - peer.network_configuration.interfaces.retain(|interface| interface.name.name() != name.name()) + peer.network.interfaces.retain(|interface| interface.name.name() != name.name()) }; carl.peers.store_peer_descriptor(peer).await diff --git a/opendut-cleo/src/commands/peer/create.rs b/opendut-cleo/src/commands/peer/create.rs index 899c9049e..2fffe761e 100644 --- a/opendut-cleo/src/commands/peer/create.rs +++ b/opendut-cleo/src/commands/peer/create.rs @@ -3,8 +3,9 @@ use uuid::Uuid; use crate::{CreateOutputFormat}; use opendut_carl_api::carl::CarlClient; -use opendut_types::peer::{PeerDescriptor, PeerId, PeerLocation, PeerName}; +use opendut_types::peer::{PeerDescriptor, PeerId, PeerLocation, PeerName, PeerNetworkDescriptor}; use opendut_types::peer::executor::{ExecutorDescriptors}; +use opendut_types::util::net::NetworkInterfaceName; /// Create a peer #[derive(clap::Parser)] @@ -18,6 +19,11 @@ pub struct CreatePeerCli { ///Location of peer #[arg(long)] location: Option, + ///Custom bridge name; + /// Please note bridges with custom names are not automatically removed and need to be removed manually. + /// Not removing the bridge could lead to network traffic being misdirected! + #[arg(long)] + bridge_name: Option, } impl CreatePeerCli { @@ -32,11 +38,16 @@ impl CreatePeerCli { .transpose() .map_err(|error| format!("Could not create peer.\n {}", error))?; + let bridge_name = self.bridge_name; + let descriptor: PeerDescriptor = PeerDescriptor { id, name: Clone::clone(&name), location, - network_configuration: Default::default(), + network: PeerNetworkDescriptor { + interfaces: vec![], + bridge_name, + }, topology: Default::default(), executors: ExecutorDescriptors { executors: vec![], diff --git a/opendut-cleo/src/commands/peer/list.rs b/opendut-cleo/src/commands/peer/list.rs index fec30dea9..14a1482c2 100644 --- a/opendut-cleo/src/commands/peer/list.rs +++ b/opendut-cleo/src/commands/peer/list.rs @@ -22,8 +22,10 @@ struct PeerTable { status: PeerStatus, #[table(title = "Location")] location: PeerLocation, - #[table(title = "NetworkConfiguration")] - network_configuration: String + #[table(title = "NetworkInterfaces")] + network_interfaces: String, + #[table(title = "BridgeName")] + bridge_name: String, } #[derive(Debug, PartialEq, Serialize)] @@ -85,13 +87,18 @@ fn filter_connected_peers( } else { PeerStatus::Disconnected }; - let network_interfaces = Clone::clone(&peer.network_configuration.interfaces); + let network_interfaces = Clone::clone(&peer.network.interfaces); let interfaces = network_interfaces.into_iter().map(|interface| interface.name.to_string()).collect::>(); + let bridge_name = match Clone::clone(&peer.network.bridge_name) { + Some(bridge_name) => bridge_name.name(), + None => String::new() + }; PeerTable { name: Clone::clone(&peer.name), id: peer.id, location: Clone::clone(&peer.location.clone().unwrap_or_default()), - network_configuration: interfaces.join(", "), + network_interfaces: interfaces.join(", "), + bridge_name, status } }) @@ -102,7 +109,7 @@ fn filter_connected_peers( mod test { use googletest::prelude::*; - use opendut_types::peer::{PeerDescriptor, PeerId, PeerLocation, PeerName, PeerNetworkConfiguration}; + use opendut_types::peer::{PeerDescriptor, PeerId, PeerLocation, PeerName, PeerNetworkDescriptor}; use opendut_types::peer::executor::ExecutorDescriptors; use opendut_types::util::net::{NetworkInterfaceConfiguration, NetworkInterfaceDescriptor, NetworkInterfaceName}; @@ -114,11 +121,12 @@ mod test { id: PeerId::random(), name: PeerName::try_from("MyPeer").unwrap(), location: Some(PeerLocation::try_from("SiFi").unwrap()), - network_configuration: PeerNetworkConfiguration { + network: PeerNetworkDescriptor{ interfaces: vec!(NetworkInterfaceDescriptor { name: NetworkInterfaceName::try_from("eth0").unwrap(), configuration: NetworkInterfaceConfiguration::Ethernet, - }) + }), + bridge_name: Some(NetworkInterfaceName::try_from("br-opendut-1").unwrap()) }, topology: Default::default(), executors: ExecutorDescriptors { diff --git a/opendut-edgar/src/service/start.rs b/opendut-edgar/src/service/start.rs index 4a6f1d75b..33a2d33a6 100644 --- a/opendut-edgar/src/service/start.rs +++ b/opendut-edgar/src/service/start.rs @@ -87,13 +87,10 @@ pub async fn create(self_id: PeerId, settings: LoadedConfig) -> anyhow::Result<( let network_interface_management_enabled = settings.config.get::("network.interface.management.enabled")?; - let bridge_name = crate::common::default_bridge_name(); - let remote_address = vpn::retrieve_remote_host(&settings).await?; let setup_cluster_info = SetupClusterInfo { self_id, - bridge_name, network_interface_management_enabled, network_interface_manager, can_manager, @@ -159,7 +156,7 @@ async fn handle_stream_message( tx_outbound.send(message).await .inspect_err(|cause| debug!("Failed to send ping to CARL: {cause}")); } - Message::ApplyPeerConfiguration(message) => { apply_peer_configuration(message, context, setup_cluster_info).await } + Message::ApplyPeerConfiguration(message) => { apply_peer_configuration(message, context, setup_cluster_info).await? } } } else { ignore(message) @@ -169,7 +166,7 @@ async fn handle_stream_message( } #[tracing::instrument(skip(message, context, setup_cluster_info), level="trace")] -async fn apply_peer_configuration(message: ApplyPeerConfiguration, context: Option, setup_cluster_info: &SetupClusterInfo) { +async fn apply_peer_configuration(message: ApplyPeerConfiguration, context: Option, setup_cluster_info: &SetupClusterInfo) -> anyhow::Result<()> { match message.clone() { ApplyPeerConfiguration { configuration: Some(configuration) } => { @@ -182,15 +179,17 @@ async fn apply_peer_configuration(message: ApplyPeerConfiguration, context: Opti Err(error) => error!("Illegal PeerConfiguration: {error}"), Ok(configuration) => { setup_executors(configuration.executors); - let _ = setup_cluster( + setup_cluster( configuration.cluster_assignment, setup_cluster_info, - ).await; + configuration.network.bridge_name, + ).await? } }; } _ => ignore(message), } + Ok(()) } #[tracing::instrument(skip(executors))] @@ -250,7 +249,6 @@ fn setup_executors(executors: ExecutorDescriptors) { //TODO make idempotent struct SetupClusterInfo { self_id: PeerId, - bridge_name: NetworkInterfaceName, network_interface_management_enabled: bool, network_interface_manager: NetworkInterfaceManagerRef, can_manager: CanManagerRef, @@ -259,6 +257,7 @@ struct SetupClusterInfo { async fn setup_cluster( cluster_assignment: Option, info: &SetupClusterInfo, + bridge_name: NetworkInterfaceName, ) -> anyhow::Result<()> { //TODO make idempotent match cluster_assignment { @@ -270,7 +269,7 @@ async fn setup_cluster( cluster_assignment::network_interfaces_setup( cluster_assignment, info.self_id, - &info.bridge_name, + &bridge_name, Arc::clone(&info.network_interface_manager), Arc::clone(&info.can_manager) ).await diff --git a/opendut-edgar/src/setup/start.rs b/opendut-edgar/src/setup/start.rs index f1515d3bd..3f9a851c1 100644 --- a/opendut-edgar/src/setup/start.rs +++ b/opendut-edgar/src/setup/start.rs @@ -105,7 +105,7 @@ pub async fn unmanaged( Box::new(tasks::netbird::InstallService), Box::new(tasks::netbird::StartService), Box::new(tasks::netbird::Connect { management_url, setup_key, mtu }), - + Box::new(tasks::network_interface::CreateBridge { network_interface_manager: Arc::clone(&network_interface_manager), bridge_name: bridge_name.clone() }), Box::new(tasks::network_interface::CreateGreInterfaces { network_interface_manager: Arc::clone(&network_interface_manager), bridge_name: bridge_name.clone(), leader }), Box::new(tasks::network_interface::ConnectDeviceInterfaces { network_interface_manager, bridge_name, device_interfaces }), diff --git a/opendut-edgar/src/setup/tasks/network_interface/mod.rs b/opendut-edgar/src/setup/tasks/network_interface/mod.rs index c0949783f..92e7ce6f1 100644 --- a/opendut-edgar/src/setup/tasks/network_interface/mod.rs +++ b/opendut-edgar/src/setup/tasks/network_interface/mod.rs @@ -5,4 +5,4 @@ mod create_gre_interface; pub use create_gre_interface::CreateGreInterfaces; mod connect_device_interfaces; -pub use connect_device_interfaces::ConnectDeviceInterfaces; +pub use connect_device_interfaces::ConnectDeviceInterfaces; \ No newline at end of file diff --git a/opendut-lea/src/peers/configurator/mod.rs b/opendut-lea/src/peers/configurator/mod.rs index 7741251ef..080e3331a 100644 --- a/opendut-lea/src/peers/configurator/mod.rs +++ b/opendut-lea/src/peers/configurator/mod.rs @@ -8,7 +8,7 @@ use crate::components::{BasePageContainer, Breadcrumb, Initialized, UserInputErr use crate::components::use_active_tab; use crate::peers::configurator::components::Controls; use crate::peers::configurator::tabs::{DevicesTab, ExecutorTab, GeneralTab, NetworkTab, SetupTab, TabIdentifier}; -use crate::peers::configurator::types::{UserDeviceConfiguration, UserPeerConfiguration, UserPeerNetworkInterface, UserPeerExecutor, UserContainerEnv}; +use crate::peers::configurator::types::{UserDeviceConfiguration, UserPeerConfiguration, UserPeerNetworkInterface, UserPeerExecutor, UserContainerEnv, UserPeerNetwork}; use crate::routing::{navigate_to, WellKnownRoutes}; mod components; @@ -51,7 +51,10 @@ pub fn PeerConfigurator() -> impl IntoView { name: UserInputValue::Left(UserInputError::from("Enter a valid peer name.")), location: UserInputValue::Right(String::from("")), devices: Vec::new(), - network_interfaces: Vec::new(), + network: UserPeerNetwork { + network_interfaces: Vec::new(), + bridge_name: UserInputValue::Right(String::from("")), + }, is_new: true, executors: Vec::new(), }); @@ -73,7 +76,10 @@ pub fn PeerConfigurator() -> impl IntoView { is_collapsed: true }) }).collect::>(); - user_configuration.network_interfaces = configuration.network_configuration.interfaces.into_iter() + if let Some(bridge_name) = configuration.network.bridge_name { + user_configuration.network.bridge_name = UserInputValue::Right(bridge_name.name()); + } + user_configuration.network.network_interfaces = configuration.network.interfaces.into_iter() .map(|interface| { create_rw_signal(UserPeerNetworkInterface { name: interface.name diff --git a/opendut-lea/src/peers/configurator/tabs/devices/device_panel.rs b/opendut-lea/src/peers/configurator/tabs/devices/device_panel.rs index 96adab03b..be989e7b9 100644 --- a/opendut-lea/src/peers/configurator/tabs/devices/device_panel.rs +++ b/opendut-lea/src/peers/configurator/tabs/devices/device_panel.rs @@ -161,7 +161,7 @@ fn DeviceInterfaceInput( let peer_network_interfaces = create_read_slice(peer_configuration, |peer_network_interfaces| { - Clone::clone(&peer_network_interfaces.network_interfaces) + Clone::clone(&peer_network_interfaces.network.network_interfaces) } ); diff --git a/opendut-lea/src/peers/configurator/tabs/network/bridge_name_input.rs b/opendut-lea/src/peers/configurator/tabs/network/bridge_name_input.rs new file mode 100644 index 000000000..0ef8e8693 --- /dev/null +++ b/opendut-lea/src/peers/configurator/tabs/network/bridge_name_input.rs @@ -0,0 +1,55 @@ +use crate::components::{UserInput, UserInputValue}; +use crate::peers::configurator::types::UserPeerConfiguration; +use leptos::{component, create_slice, view, IntoView, RwSignal}; +use opendut_types::util::net::{NetworkInterfaceName, NetworkInterfaceNameError}; + +#[component] +pub fn BridgeNameInput(peer_configuration: RwSignal) -> impl IntoView { + let (getter, setter) = create_slice( + peer_configuration, + |config| Clone::clone(&config.network.bridge_name), + |config, input| { + config.network.bridge_name = input; + }, + ); + + let validator = |input: String| { + match NetworkInterfaceName::try_from(input) { + Ok(name) => { + UserInputValue::Right(name.name()) + } + Err(cause) => { + match cause { + NetworkInterfaceNameError::Empty => { + UserInputValue::Right(String::new()) + } + NetworkInterfaceNameError::TooLong { value, max } => { + UserInputValue::Both(format!("A bridge name must be at most {} characters long.", max), value) + }, + } + } + } + }; + + view! { +
+
+
+
+ +
+
+

"Bridges with custom names are not automatically removed and need to be removed manually. Not removing the bridge could lead to network traffic being misdirected!"

+
+
+
+ +
+ } +} diff --git a/opendut-lea/src/peers/configurator/tabs/network/mod.rs b/opendut-lea/src/peers/configurator/tabs/network/mod.rs index ce6507b3b..5c3c96b78 100644 --- a/opendut-lea/src/peers/configurator/tabs/network/mod.rs +++ b/opendut-lea/src/peers/configurator/tabs/network/mod.rs @@ -4,9 +4,11 @@ use leptos::{component, create_action, create_read_slice, create_rw_signal, crea use crate::components::{Toast, use_toaster, UserInputValue}; use crate::peers::configurator::tabs::network::network_interface_name_input::NetworkInterfaceNameInput; +use crate::peers::configurator::tabs::network::bridge_name_input::BridgeNameInput; use crate::peers::configurator::types::{UserPeerConfiguration, UserPeerNetworkInterface}; mod network_interface_name_input; +mod bridge_name_input; #[component] pub fn NetworkTab(peer_configuration: RwSignal) -> impl IntoView { @@ -15,10 +17,10 @@ pub fn NetworkTab(peer_configuration: RwSignal) -> impl I let (interfaces_getter, interfaces_setter) = create_slice(peer_configuration, |peer_configuration| { - Clone::clone(&peer_configuration.network_interfaces) + Clone::clone(&peer_configuration.network.network_interfaces) }, |peer_configuration, value| { - peer_configuration.network_interfaces = value + peer_configuration.network.network_interfaces = value } ); @@ -105,7 +107,10 @@ pub fn NetworkTab(peer_configuration: RwSignal) -> impl I }; view! { - + >, - pub network_interfaces: Vec>, + pub network: UserPeerNetwork, pub executors: Vec>, pub is_new: bool, } @@ -70,6 +70,11 @@ pub struct UserContainerEnv { pub value: UserInputValue } +#[derive(Clone, Debug)] +pub struct UserPeerNetwork { + pub network_interfaces: Vec>, + pub bridge_name: UserInputValue, +} #[derive(Clone, Debug)] pub struct UserPeerNetworkInterface { @@ -103,13 +108,26 @@ impl TryFrom for PeerDescriptor { PeerLocation::try_from(location) .map_err(|_| PeerMisconfigurationError::InvalidPeerName) })?; - let network_interfaces = configuration + let bridge_name = configuration.network + .bridge_name + .right_ok_or(PeerMisconfigurationError::InvalidPeerNetwork) + .and_then(|bridge_name| { + if bridge_name.is_empty() { + Ok(None) + } else { + match NetworkInterfaceName::try_from(bridge_name) { + Ok(name) => Ok(Some(name)), + Err(_) => Err(PeerMisconfigurationError::InvalidPeerNetwork) + } + } + })?; + let network_interfaces = configuration.network .network_interfaces .into_iter() .map(|signal| signal.get_untracked()) .map(|interface| { NetworkInterfaceDescriptor::try_from(interface) - .map_err(|_| PeerMisconfigurationError::InvalidPeerNetworkConfiguration) + .map_err(|_| PeerMisconfigurationError::InvalidPeerNetwork) }) .collect::, _>>()?; let devices = configuration @@ -134,7 +152,7 @@ impl TryFrom for PeerDescriptor { id: configuration.id, name, location: Some(location), - network_configuration: PeerNetworkConfiguration::new(network_interfaces), + network: PeerNetworkDescriptor::new(network_interfaces, bridge_name), topology: Topology::new(devices), executors: ExecutorDescriptors { executors diff --git a/opendut-types/proto/opendut/types/peer/configuration.proto b/opendut-types/proto/opendut/types/peer/configuration.proto index f04519f33..f160c6b1f 100644 --- a/opendut-types/proto/opendut/types/peer/configuration.proto +++ b/opendut-types/proto/opendut/types/peer/configuration.proto @@ -4,8 +4,14 @@ package opendut.types.peer.configuration; import "opendut/types/cluster/cluster.proto"; import "opendut/types/peer/executor.proto"; +import "opendut/types/util/net.proto"; message PeerConfiguration { opendut.types.peer.executor.ExecutorDescriptors executors = 1; optional opendut.types.cluster.ClusterAssignment cluster_assignment = 2; + opendut.types.peer.configuration.PeerNetworkConfiguration network = 3; +} + +message PeerNetworkConfiguration { + opendut.types.util.NetworkInterfaceName bridge_name = 1; } diff --git a/opendut-types/proto/opendut/types/peer/peer.proto b/opendut-types/proto/opendut/types/peer/peer.proto index e46106683..7c24f9109 100644 --- a/opendut-types/proto/opendut/types/peer/peer.proto +++ b/opendut-types/proto/opendut/types/peer/peer.proto @@ -21,15 +21,16 @@ message PeerLocation { string value = 1; } -message PeerNetworkConfiguration { +message PeerNetworkDescriptor { repeated opendut.types.util.NetworkInterfaceDescriptor interfaces = 1; + opendut.types.util.NetworkInterfaceName bridge_name = 2; } message PeerDescriptor { opendut.types.peer.PeerId id = 1; opendut.types.peer.PeerName name = 2; opendut.types.peer.PeerLocation location = 3; - opendut.types.peer.PeerNetworkConfiguration network_configuration = 4; + opendut.types.peer.PeerNetworkDescriptor network = 4; opendut.types.topology.Topology topology = 5; opendut.types.peer.executor.ExecutorDescriptors executors = 6; } diff --git a/opendut-types/src/peer/configuration.rs b/opendut-types/src/peer/configuration.rs index 003a25e6d..6fce777f3 100644 --- a/opendut-types/src/peer/configuration.rs +++ b/opendut-types/src/peer/configuration.rs @@ -1,8 +1,24 @@ +use serde::{Deserialize, Serialize}; use crate::cluster::ClusterAssignment; use crate::peer::executor::ExecutorDescriptors; +use crate::util::net::{NetworkInterfaceName}; #[derive(Clone, Debug, PartialEq, Eq)] pub struct PeerConfiguration { pub executors: ExecutorDescriptors, pub cluster_assignment: Option, + pub network: PeerNetworkConfiguration, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct PeerNetworkConfiguration { + pub bridge_name: NetworkInterfaceName, +} + +impl Default for PeerNetworkConfiguration { + fn default() -> Self { + Self { + bridge_name: NetworkInterfaceName::try_from("br-opendut").unwrap(), + } + } } diff --git a/opendut-types/src/peer/mod.rs b/opendut-types/src/peer/mod.rs index c2a6fdd98..accce8c59 100644 --- a/opendut-types/src/peer/mod.rs +++ b/opendut-types/src/peer/mod.rs @@ -10,8 +10,7 @@ use uuid::Uuid; use crate::peer::executor::ExecutorDescriptors; use crate::topology::Topology; - -use crate::util::net::{Certificate, NetworkInterfaceDescriptor, AuthConfig}; +use crate::util::net::{Certificate, NetworkInterfaceDescriptor, AuthConfig, NetworkInterfaceName}; use crate::vpn::VpnPeerConfiguration; pub mod state; @@ -220,13 +219,14 @@ impl fmt::Display for PeerLocation { } #[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] -pub struct PeerNetworkConfiguration { +pub struct PeerNetworkDescriptor { pub interfaces: Vec, + pub bridge_name: Option, } -impl PeerNetworkConfiguration { - pub fn new(interfaces: Vec) -> Self { - Self { interfaces } +impl PeerNetworkDescriptor { + pub fn new(interfaces: Vec, bridge_name: Option) -> Self { + Self { interfaces, bridge_name} } } @@ -235,7 +235,7 @@ pub struct PeerDescriptor { pub id: PeerId, pub name: PeerName, pub location: Option, - pub network_configuration: PeerNetworkConfiguration, + pub network: PeerNetworkDescriptor, pub topology: Topology, pub executors: ExecutorDescriptors, } diff --git a/opendut-types/src/proto/peer/configuration.rs b/opendut-types/src/proto/peer/configuration.rs index 351ee1690..bcd4e9339 100644 --- a/opendut-types/src/proto/peer/configuration.rs +++ b/opendut-types/src/proto/peer/configuration.rs @@ -7,6 +7,7 @@ impl From for PeerConfiguration { Self { executors: Some(value.executors.into()), cluster_assignment: value.cluster_assignment.map(|assignment| assignment.into()), + network: Some(value.network.into()) } } } @@ -25,9 +26,38 @@ impl TryFrom for crate::peer::configuration::PeerConfiguratio .map(TryInto::try_into) .transpose()?; + let network = value.network + .ok_or(ErrorBuilder::field_not_set("network"))? + .try_into()?; + Ok(crate::peer::configuration::PeerConfiguration { executors, - cluster_assignment + cluster_assignment, + network + }) + } +} + +impl From for PeerNetworkConfiguration { + fn from(value: crate::peer::configuration::PeerNetworkConfiguration) -> Self { + Self { + bridge_name: Some(value.bridge_name.into()) + } + } +} + +impl TryFrom for crate::peer::configuration::PeerNetworkConfiguration { + type Error = ConversionError; + + fn try_from(value: PeerNetworkConfiguration) -> Result { + type ErrorBuilder = ConversionErrorBuilder; + + let bridge_name = value.bridge_name + .ok_or(ErrorBuilder::field_not_set("bridge_name"))? + .try_into()?; + + Ok(crate::peer::configuration::PeerNetworkConfiguration { + bridge_name, }) } } diff --git a/opendut-types/src/proto/peer/mod.rs b/opendut-types/src/proto/peer/mod.rs index 4c3615299..17a13c7ac 100644 --- a/opendut-types/src/proto/peer/mod.rs +++ b/opendut-types/src/proto/peer/mod.rs @@ -2,7 +2,7 @@ use crate::proto; use crate::proto::{ConversionError, ConversionErrorBuilder}; use crate::proto::vpn::VpnPeerConfig; -use super::util::NetworkInterfaceDescriptor; +use super::util::{NetworkInterfaceDescriptor, NetworkInterfaceName}; pub mod configuration; pub mod executor; @@ -84,28 +84,32 @@ impl TryFrom for crate::peer::PeerLocation { } } -impl From for PeerNetworkConfiguration { - fn from(value: crate::peer::PeerNetworkConfiguration) -> Self { +impl From for PeerNetworkDescriptor { + fn from(value: crate::peer::PeerNetworkDescriptor) -> Self { Self { interfaces: value .interfaces .into_iter() .map(NetworkInterfaceDescriptor::from) .collect(), + bridge_name: value.bridge_name.map(NetworkInterfaceName::from), } } } -impl TryFrom for crate::peer::PeerNetworkConfiguration { +impl TryFrom for crate::peer::PeerNetworkDescriptor { type Error = ConversionError; - fn try_from(value: PeerNetworkConfiguration) -> Result { + fn try_from(value: PeerNetworkDescriptor) -> Result { + let bridge_name = value.bridge_name + .map(crate::util::net::NetworkInterfaceName::try_from) + .transpose()?; value .interfaces .into_iter() .map(NetworkInterfaceDescriptor::try_into) .collect::>() - .map(|interfaces| Self { interfaces }) + .map(|interfaces| Self { interfaces, bridge_name}) } } @@ -115,7 +119,7 @@ impl From for PeerDescriptor { id: Some(value.id.into()), name: Some(value.name.into()), location: Some(value.location.unwrap_or_default().into()), - network_configuration: Some(value.network_configuration.into()), + network: Some(value.network.into()), topology: Some(value.topology.into()), executors: Some(value.executors.into()), } @@ -140,8 +144,8 @@ impl TryFrom for crate::peer::PeerDescriptor { .map(crate::peer::PeerLocation::try_from) .transpose()?; - let network_configuration = value.network_configuration - .ok_or(ErrorBuilder::field_not_set("network_configuration"))? + let network = value.network + .ok_or(ErrorBuilder::field_not_set("network"))? .try_into()?; let topology = value.topology @@ -156,7 +160,7 @@ impl TryFrom for crate::peer::PeerDescriptor { id, name, location, - network_configuration, + network, topology, executors, })