158 lines
4.3 KiB
Rust
158 lines
4.3 KiB
Rust
use std::str::FromStr;
|
|
|
|
use async_trait::async_trait;
|
|
use brocade::{BrocadeOptions, 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,
|
|
},
|
|
};
|
|
use harmony_macros::ip;
|
|
use harmony_types::{id::Id, net::MacAddress, switch::PortLocation};
|
|
use log::{debug, info};
|
|
use serde::Serialize;
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
let switch_score = BrocadeSwitchScore {
|
|
port_channels_to_clear: vec![
|
|
Id::from_str("17").unwrap(),
|
|
Id::from_str("19").unwrap(),
|
|
Id::from_str("18").unwrap(),
|
|
],
|
|
ports_to_configure: vec![
|
|
(PortLocation(2, 0, 17), PortOperatingMode::Trunk),
|
|
(PortLocation(2, 0, 19), PortOperatingMode::Trunk),
|
|
(PortLocation(1, 0, 18), PortOperatingMode::Trunk),
|
|
],
|
|
};
|
|
harmony_cli::run(
|
|
Inventory::autoload(),
|
|
SwitchTopology::new().await,
|
|
vec![Box::new(switch_score)],
|
|
None,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize)]
|
|
struct BrocadeSwitchScore {
|
|
port_channels_to_clear: Vec<Id>,
|
|
ports_to_configure: Vec<PortConfig>,
|
|
}
|
|
|
|
impl<T: Topology + Switch> Score<T> for BrocadeSwitchScore {
|
|
fn name(&self) -> String {
|
|
"BrocadeSwitchScore".to_string()
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
|
Box::new(BrocadeSwitchInterpret {
|
|
score: self.clone(),
|
|
})
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct BrocadeSwitchInterpret {
|
|
score: BrocadeSwitchScore,
|
|
}
|
|
|
|
#[async_trait]
|
|
impl<T: Topology + Switch> Interpret<T> for BrocadeSwitchInterpret {
|
|
async fn execute(
|
|
&self,
|
|
_inventory: &Inventory,
|
|
topology: &T,
|
|
) -> Result<Outcome, InterpretError> {
|
|
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<Id> {
|
|
todo!()
|
|
}
|
|
}
|
|
|
|
struct SwitchTopology {
|
|
client: Box<dyn SwitchClient>,
|
|
}
|
|
|
|
#[async_trait]
|
|
impl Topology for SwitchTopology {
|
|
fn name(&self) -> &str {
|
|
"SwitchTopology"
|
|
}
|
|
|
|
async fn ensure_ready(&self) -> Result<PreparationOutcome, PreparationError> {
|
|
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<Option<PortLocation>, SwitchError> {
|
|
todo!()
|
|
}
|
|
|
|
async fn configure_port_channel(&self, _config: &HostNetworkConfig) -> Result<(), SwitchError> {
|
|
todo!()
|
|
}
|
|
async fn clear_port_channel(&self, ids: &Vec<Id>) -> Result<(), SwitchError> {
|
|
self.client.clear_port_channel(ids).await
|
|
}
|
|
async fn configure_interface(&self, ports: &Vec<PortConfig>) -> Result<(), SwitchError> {
|
|
self.client.configure_interface(ports).await
|
|
}
|
|
}
|