From 8afcacbd24d3b7d44e0612fc57dcf12ae35942ce Mon Sep 17 00:00:00 2001 From: Sylvain Tremblay Date: Mon, 9 Feb 2026 09:53:16 -0500 Subject: [PATCH 1/3] feat: integrate brocade --- examples/brocade_switch/src/main.rs | 133 +----------------- harmony/src/modules/brocade/brocade.rs | 132 +++++++++++++++++ .../{brocade.rs => brocade/brocade_snmp.rs} | 0 harmony/src/modules/brocade/mod.rs | 5 + 4 files changed, 141 insertions(+), 129 deletions(-) create mode 100644 harmony/src/modules/brocade/brocade.rs rename harmony/src/modules/{brocade.rs => brocade/brocade_snmp.rs} (100%) create mode 100644 harmony/src/modules/brocade/mod.rs diff --git a/examples/brocade_switch/src/main.rs b/examples/brocade_switch/src/main.rs index a99263de..29a0e120 100644 --- a/examples/brocade_switch/src/main.rs +++ b/examples/brocade_switch/src/main.rs @@ -1,22 +1,10 @@ use std::str::FromStr; -use async_trait::async_trait; -use brocade::{BrocadeOptions, PortOperatingMode}; +use brocade::PortOperatingMode; use harmony::{ - data::Version, - infra::brocade::BrocadeSwitchClient, - interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome}, - inventory::Inventory, - score::Score, - topology::{ - HostNetworkConfig, PortConfig, PreparationError, PreparationOutcome, Switch, SwitchClient, - SwitchError, Topology, - }, + inventory::Inventory, modules::brocade::{BrocadeSwitchScore, SwitchTopology} }; -use harmony_macros::ip; -use harmony_types::{id::Id, net::MacAddress, switch::PortLocation}; -use log::{debug, info}; -use serde::Serialize; +use harmony_types::{id::Id, switch::PortLocation}; #[tokio::main] async fn main() { @@ -32,6 +20,7 @@ async fn main() { (PortLocation(1, 0, 18), PortOperatingMode::Trunk), ], }; + harmony_cli::run( Inventory::autoload(), SwitchTopology::new().await, @@ -41,117 +30,3 @@ async fn main() { .await .unwrap(); } - -#[derive(Clone, Debug, Serialize)] -struct BrocadeSwitchScore { - port_channels_to_clear: Vec, - ports_to_configure: Vec, -} - -impl Score for BrocadeSwitchScore { - fn name(&self) -> String { - "BrocadeSwitchScore".to_string() - } - - #[doc(hidden)] - fn create_interpret(&self) -> Box> { - Box::new(BrocadeSwitchInterpret { - score: self.clone(), - }) - } -} - -#[derive(Debug)] -struct BrocadeSwitchInterpret { - score: BrocadeSwitchScore, -} - -#[async_trait] -impl Interpret for BrocadeSwitchInterpret { - async fn execute( - &self, - _inventory: &Inventory, - topology: &T, - ) -> Result { - info!("Applying switch configuration {:?}", self.score); - debug!( - "Clearing port channel {:?}", - self.score.port_channels_to_clear - ); - topology - .clear_port_channel(&self.score.port_channels_to_clear) - .await - .map_err(|e| InterpretError::new(e.to_string()))?; - debug!("Configuring interfaces {:?}", self.score.ports_to_configure); - topology - .configure_interface(&self.score.ports_to_configure) - .await - .map_err(|e| InterpretError::new(e.to_string()))?; - Ok(Outcome::success("switch configured".to_string())) - } - fn get_name(&self) -> InterpretName { - InterpretName::Custom("BrocadeSwitchInterpret") - } - fn get_version(&self) -> Version { - todo!() - } - fn get_status(&self) -> InterpretStatus { - todo!() - } - fn get_children(&self) -> Vec { - todo!() - } -} - -struct SwitchTopology { - client: Box, -} - -#[async_trait] -impl Topology for SwitchTopology { - fn name(&self) -> &str { - "SwitchTopology" - } - - async fn ensure_ready(&self) -> Result { - Ok(PreparationOutcome::Noop) - } -} - -impl SwitchTopology { - async fn new() -> Self { - let mut options = BrocadeOptions::default(); - options.ssh.port = 2222; - let client = - BrocadeSwitchClient::init(&vec![ip!("127.0.0.1")], &"admin", &"password", options) - .await - .expect("Failed to connect to switch"); - - let client = Box::new(client); - Self { client } - } -} - -#[async_trait] -impl Switch for SwitchTopology { - async fn setup_switch(&self) -> Result<(), SwitchError> { - todo!() - } - - async fn get_port_for_mac_address( - &self, - _mac_address: &MacAddress, - ) -> Result, SwitchError> { - todo!() - } - - async fn configure_port_channel(&self, _config: &HostNetworkConfig) -> Result<(), SwitchError> { - todo!() - } - async fn clear_port_channel(&self, ids: &Vec) -> Result<(), SwitchError> { - self.client.clear_port_channel(ids).await - } - async fn configure_interface(&self, ports: &Vec) -> Result<(), SwitchError> { - self.client.configure_interface(ports).await - } -} diff --git a/harmony/src/modules/brocade/brocade.rs b/harmony/src/modules/brocade/brocade.rs new file mode 100644 index 00000000..7931c7c0 --- /dev/null +++ b/harmony/src/modules/brocade/brocade.rs @@ -0,0 +1,132 @@ +use async_trait::async_trait; +use brocade::{BrocadeOptions, PortOperatingMode}; + +use crate::{ + data::Version, + infra::brocade::BrocadeSwitchClient, + interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome}, + inventory::Inventory, + score::Score, + topology::{ + HostNetworkConfig, PortConfig, PreparationError, PreparationOutcome, Switch, SwitchClient, + SwitchError, Topology, + }, +}; +use harmony_macros::ip; +use harmony_types::{id::Id, net::MacAddress, switch::PortLocation}; +use log::{debug, info}; +use serde::Serialize; + +#[derive(Clone, Debug, Serialize)] +pub struct BrocadeSwitchScore { + pub port_channels_to_clear: Vec, + pub ports_to_configure: Vec, +} + +impl Score for BrocadeSwitchScore { + fn name(&self) -> String { + "BrocadeSwitchScore".to_string() + } + + #[doc(hidden)] + fn create_interpret(&self) -> Box> { + Box::new(BrocadeSwitchInterpret { + score: self.clone(), + }) + } +} + +#[derive(Debug)] +pub struct BrocadeSwitchInterpret { + score: BrocadeSwitchScore, +} + +#[async_trait] +impl Interpret for BrocadeSwitchInterpret { + async fn execute( + &self, + _inventory: &Inventory, + topology: &T, + ) -> Result { + info!("Applying switch configuration {:?}", self.score); + debug!( + "Clearing port channel {:?}", + self.score.port_channels_to_clear + ); + topology + .clear_port_channel(&self.score.port_channels_to_clear) + .await + .map_err(|e| InterpretError::new(e.to_string()))?; + debug!("Configuring interfaces {:?}", self.score.ports_to_configure); + topology + .configure_interface(&self.score.ports_to_configure) + .await + .map_err(|e| InterpretError::new(e.to_string()))?; + Ok(Outcome::success("switch configured".to_string())) + } + fn get_name(&self) -> InterpretName { + InterpretName::Custom("BrocadeSwitchInterpret") + } + fn get_version(&self) -> Version { + todo!() + } + fn get_status(&self) -> InterpretStatus { + todo!() + } + fn get_children(&self) -> Vec { + todo!() + } +} + +pub struct SwitchTopology { + client: Box, +} + +#[async_trait] +impl Topology for SwitchTopology { + fn name(&self) -> &str { + "SwitchTopology" + } + + async fn ensure_ready(&self) -> Result { + Ok(PreparationOutcome::Noop) + } +} + +impl SwitchTopology { + pub async fn new() -> Self { + let mut options = BrocadeOptions::default(); + options.ssh.port = 2222; + let client = + BrocadeSwitchClient::init(&vec![ip!("127.0.0.1")], &"admin", &"password", options) + .await + .expect("Failed to connect to switch"); + + let client = Box::new(client); + Self { client } + } +} + +#[async_trait] +impl Switch for SwitchTopology { + async fn setup_switch(&self) -> Result<(), SwitchError> { + todo!() + } + + async fn get_port_for_mac_address( + &self, + _mac_address: &MacAddress, + ) -> Result, SwitchError> { + todo!() + } + + async fn configure_port_channel(&self, _config: &HostNetworkConfig) -> Result<(), SwitchError> { + todo!() + } + async fn clear_port_channel(&self, ids: &Vec) -> Result<(), SwitchError> { + self.client.clear_port_channel(ids).await + } + async fn configure_interface(&self, ports: &Vec) -> Result<(), SwitchError> { + self.client.configure_interface(ports).await + } +} diff --git a/harmony/src/modules/brocade.rs b/harmony/src/modules/brocade/brocade_snmp.rs similarity index 100% rename from harmony/src/modules/brocade.rs rename to harmony/src/modules/brocade/brocade_snmp.rs diff --git a/harmony/src/modules/brocade/mod.rs b/harmony/src/modules/brocade/mod.rs new file mode 100644 index 00000000..1f197b9b --- /dev/null +++ b/harmony/src/modules/brocade/mod.rs @@ -0,0 +1,5 @@ +pub mod brocade; +pub use brocade::*; + +pub mod brocade_snmp; +pub use brocade_snmp::*; -- 2.39.5 From fececc2efddfc7ddad2a7f0ac323ce313dab2ac9 Mon Sep 17 00:00:00 2001 From: Sylvain Tremblay Date: Mon, 9 Feb 2026 11:24:29 -0500 Subject: [PATCH 2/3] Creating a BrocadeSwitchConfig struct --- examples/brocade_switch/src/main.rs | 23 +++++++++++++++++++--- harmony/src/infra/brocade.rs | 8 ++++++++ harmony/src/modules/brocade/brocade.rs | 27 ++++++++++++++++++-------- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/examples/brocade_switch/src/main.rs b/examples/brocade_switch/src/main.rs index 29a0e120..9f8d8cd8 100644 --- a/examples/brocade_switch/src/main.rs +++ b/examples/brocade_switch/src/main.rs @@ -1,11 +1,26 @@ use std::str::FromStr; -use brocade::PortOperatingMode; +use brocade::{BrocadeOptions, PortOperatingMode}; use harmony::{ - inventory::Inventory, modules::brocade::{BrocadeSwitchScore, SwitchTopology} + infra::brocade::BrocadeSwitchConfig, + inventory::Inventory, + modules::brocade::{BrocadeSwitchScore, SwitchTopology}, }; +use harmony_macros::ip; use harmony_types::{id::Id, switch::PortLocation}; +fn get_switch_config() -> BrocadeSwitchConfig { + let mut options = BrocadeOptions::default(); + options.ssh.port = 2222; + + BrocadeSwitchConfig { + ips: vec![ip!("127.0.0.1")], + username: "admin".to_string(), + password: "password".to_string(), + options, + } +} + #[tokio::main] async fn main() { let switch_score = BrocadeSwitchScore { @@ -23,10 +38,12 @@ async fn main() { harmony_cli::run( Inventory::autoload(), - SwitchTopology::new().await, + SwitchTopology::new(get_switch_config()).await, vec![Box::new(switch_score)], None, ) .await .unwrap(); } + + diff --git a/harmony/src/infra/brocade.rs b/harmony/src/infra/brocade.rs index 2bc90d2b..26935afb 100644 --- a/harmony/src/infra/brocade.rs +++ b/harmony/src/infra/brocade.rs @@ -9,6 +9,14 @@ use option_ext::OptionExt; use crate::topology::{PortConfig, SwitchClient, SwitchError}; +#[derive(Debug, Clone)] +pub struct BrocadeSwitchConfig { + pub ips: Vec, + pub username: String, + pub password: String, + pub options: BrocadeOptions, +} + #[derive(Debug)] pub struct BrocadeSwitchClient { brocade: Box, diff --git a/harmony/src/modules/brocade/brocade.rs b/harmony/src/modules/brocade/brocade.rs index 7931c7c0..b1331e53 100644 --- a/harmony/src/modules/brocade/brocade.rs +++ b/harmony/src/modules/brocade/brocade.rs @@ -3,7 +3,7 @@ use brocade::{BrocadeOptions, PortOperatingMode}; use crate::{ data::Version, - infra::brocade::BrocadeSwitchClient, + infra::brocade::{BrocadeSwitchClient, BrocadeSwitchConfig}, interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome}, inventory::Inventory, score::Score, @@ -78,6 +78,15 @@ impl Interpret for BrocadeSwitchInterpret { } } +/* +pub struct BrocadeSwitchConfig { + pub ips: Vec, + pub username: String, + pub password: String, + pub options: BrocadeOptions, +} +*/ + pub struct SwitchTopology { client: Box, } @@ -94,13 +103,15 @@ impl Topology for SwitchTopology { } impl SwitchTopology { - pub async fn new() -> Self { - let mut options = BrocadeOptions::default(); - options.ssh.port = 2222; - let client = - BrocadeSwitchClient::init(&vec![ip!("127.0.0.1")], &"admin", &"password", options) - .await - .expect("Failed to connect to switch"); + pub async fn new(config: BrocadeSwitchConfig) -> Self { + let client = BrocadeSwitchClient::init( + &config.ips, + &config.username, + &config.password, + config.options, + ) + .await + .expect("Failed to connect to switch"); let client = Box::new(client); Self { client } -- 2.39.5 From 2ddc9c0579e84fb43035579704ae1a9584985f99 Mon Sep 17 00:00:00 2001 From: wjro Date: Thu, 12 Feb 2026 10:31:06 -0500 Subject: [PATCH 3/3] fix:format --- examples/brocade_switch/src/main.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/brocade_switch/src/main.rs b/examples/brocade_switch/src/main.rs index 9f8d8cd8..0fff8460 100644 --- a/examples/brocade_switch/src/main.rs +++ b/examples/brocade_switch/src/main.rs @@ -45,5 +45,3 @@ async fn main() { .await .unwrap(); } - - -- 2.39.5