implement port channel functions for Brocade::NetworkOperatingSystem
All checks were successful
Run Check Script / check (pull_request) Successful in 1m5s

This commit is contained in:
Ian Letourneau 2025-10-15 12:13:09 -04:00
parent da5be17cb6
commit 2edd24753a
3 changed files with 119 additions and 34 deletions

View File

@ -2,6 +2,7 @@ use std::net::{IpAddr, Ipv4Addr};
use brocade::BrocadeOptions; use brocade::BrocadeOptions;
use harmony_secret::{Secret, SecretManager}; use harmony_secret::{Secret, SecretManager};
use harmony_types::switch::PortLocation;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Secret, Clone, Debug, Serialize, Deserialize)] #[derive(Secret, Clone, Debug, Serialize, Deserialize)]
@ -42,28 +43,28 @@ async fn main() {
let entries = brocade.get_interfaces().await.unwrap(); let entries = brocade.get_interfaces().await.unwrap();
println!("Interfaces: {entries:#?}"); println!("Interfaces: {entries:#?}");
// let version = brocade.version().await.unwrap(); let version = brocade.version().await.unwrap();
// println!("Version: {version:?}"); println!("Version: {version:?}");
//
// println!("--------------"); println!("--------------");
// let mac_adddresses = brocade.show_mac_address_table().await.unwrap(); let mac_adddresses = brocade.get_mac_address_table().await.unwrap();
// println!("VLAN\tMAC\t\t\tPORT"); println!("VLAN\tMAC\t\t\tPORT");
// for mac in mac_adddresses { for mac in mac_adddresses {
// println!("{}\t{}\t{}", mac.vlan, mac.mac_address, mac.port); println!("{}\t{}\t{}", mac.vlan, mac.mac_address, mac.port);
// } }
//
// println!("--------------"); println!("--------------");
// let channel_name = "HARMONY_LAG"; let channel_name = "1";
// brocade.clear_port_channel(channel_name).await.unwrap(); brocade.clear_port_channel(channel_name).await.unwrap();
//
// println!("--------------"); println!("--------------");
// let channel_id = brocade.find_available_channel_id().await.unwrap(); let channel_id = brocade.find_available_channel_id().await.unwrap();
//
// println!("--------------"); println!("--------------");
// let channel_name = "HARMONY_LAG"; let channel_name = "HARMONY_LAG";
// let ports = [PortLocation(1, 1, 3), PortLocation(1, 1, 4)]; let ports = [PortLocation(2, 0, 35)];
// brocade brocade
// .create_port_channel(channel_id, channel_name, &ports) .create_port_channel(channel_id, channel_name, &ports)
// .await .await
// .unwrap(); .unwrap();
} }

View File

@ -76,8 +76,8 @@ impl FastIronClient {
fn build_port_channel_commands( fn build_port_channel_commands(
&self, &self,
channel_id: PortChannelId,
channel_name: &str, channel_name: &str,
channel_id: u8,
ports: &[PortLocation], ports: &[PortLocation],
) -> Vec<String> { ) -> Vec<String> {
let mut commands = vec![ let mut commands = vec![
@ -184,7 +184,7 @@ impl BrocadeClient for FastIronClient {
"[Brocade] Configuring port-channel '{channel_name} {channel_id}' with ports: {ports:?}" "[Brocade] Configuring port-channel '{channel_name} {channel_id}' with ports: {ports:?}"
); );
let commands = self.build_port_channel_commands(channel_name, channel_id, ports); let commands = self.build_port_channel_commands(channel_id, channel_name, ports);
self.shell self.shell
.run_commands(commands, ExecutionMode::Privileged) .run_commands(commands, ExecutionMode::Privileged)
.await?; .await?;

View File

@ -2,7 +2,7 @@ use std::str::FromStr;
use async_trait::async_trait; use async_trait::async_trait;
use harmony_types::switch::{PortDeclaration, PortLocation}; use harmony_types::switch::{PortDeclaration, PortLocation};
use log::debug; use log::{debug, info};
use crate::{ use crate::{
BrocadeClient, BrocadeInfo, Error, ExecutionMode, InterSwitchLink, InterfaceInfo, BrocadeClient, BrocadeInfo, Error, ExecutionMode, InterSwitchLink, InterfaceInfo,
@ -163,6 +163,8 @@ impl BrocadeClient for NetworkOperatingSystemClient {
&self, &self,
interfaces: Vec<(String, PortOperatingMode)>, interfaces: Vec<(String, PortOperatingMode)>,
) -> Result<(), Error> { ) -> Result<(), Error> {
info!("[Brocade] Configuring {} interface(s)...", interfaces.len());
let mut commands = vec!["configure terminal".to_string()]; let mut commands = vec!["configure terminal".to_string()];
for interface in interfaces { for interface in interfaces {
@ -200,23 +202,105 @@ impl BrocadeClient for NetworkOperatingSystemClient {
.run_commands(commands, ExecutionMode::Regular) .run_commands(commands, ExecutionMode::Regular)
.await?; .await?;
info!("[Brocade] Interfaces configured.");
Ok(()) Ok(())
} }
async fn find_available_channel_id(&self) -> Result<PortChannelId, Error> { async fn find_available_channel_id(&self) -> Result<PortChannelId, Error> {
todo!() info!("[Brocade] Finding next available channel id...");
let output = self
.shell
.run_command("show port-channel", ExecutionMode::Regular)
.await?;
let used_ids: Vec<u8> = output
.lines()
.skip(6)
.filter_map(|line| {
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() < 8 {
return None;
}
u8::from_str(parts[0]).ok()
})
.collect();
let mut next_id: u8 = 1;
loop {
if !used_ids.contains(&next_id) {
break;
}
next_id += 1;
}
info!("[Brocade] Found channel id: {next_id}");
Ok(next_id)
} }
async fn create_port_channel( async fn create_port_channel(
&self, &self,
_channel_id: PortChannelId, channel_id: PortChannelId,
_channel_name: &str, channel_name: &str,
_ports: &[PortLocation], ports: &[PortLocation],
) -> Result<(), Error> { ) -> Result<(), Error> {
todo!() info!(
"[Brocade] Configuring port-channel '{channel_name} {channel_id}' with ports: {ports:?}"
);
let interfaces = self.get_interfaces().await?;
let mut commands = vec![
"configure terminal".into(),
format!("interface port-channel {}", channel_id),
"no shutdown".into(),
"exit".into(),
];
for port in ports {
let interface = interfaces.iter().find(|i| i.port_location == *port);
let Some(interface) = interface else {
continue;
};
commands.push(format!("interface {}", interface.name));
commands.push("no switchport".into());
commands.push("no ip address".into());
commands.push("no fabric isl enable".into());
commands.push("no fabric trunk enable".into());
commands.push(format!("channel-group {} mode active", channel_id));
commands.push("no shutdown".into());
commands.push("exit".into());
}
commands.push("write memory".into());
self.shell
.run_commands(commands, ExecutionMode::Regular)
.await?;
info!("[Brocade] Port-channel '{channel_name}' configured.");
Ok(())
} }
async fn clear_port_channel(&self, _channel_name: &str) -> Result<(), Error> { async fn clear_port_channel(&self, channel_name: &str) -> Result<(), Error> {
todo!() info!("[Brocade] Clearing port-channel: {channel_name}");
let commands = vec![
"configure terminal".into(),
format!("no interface port-channel {}", channel_name),
"exit".into(),
"write memory".into(),
];
self.shell
.run_commands(commands, ExecutionMode::Regular)
.await?;
info!("[Brocade] Port-channel '{channel_name}' cleared.");
Ok(())
} }
} }