feat: integrate-brocade #230
@@ -1,22 +1,25 @@
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use brocade::{BrocadeOptions, PortOperatingMode};
|
use brocade::{BrocadeOptions, PortOperatingMode};
|
||||||
use harmony::{
|
use harmony::{
|
||||||
data::Version,
|
infra::brocade::BrocadeSwitchConfig,
|
||||||
infra::brocade::BrocadeSwitchClient,
|
|
||||||
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
|
|
||||||
inventory::Inventory,
|
inventory::Inventory,
|
||||||
score::Score,
|
modules::brocade::{BrocadeSwitchScore, SwitchTopology},
|
||||||
topology::{
|
|
||||||
HostNetworkConfig, PortConfig, PreparationError, PreparationOutcome, Switch, SwitchClient,
|
|
||||||
SwitchError, Topology,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use harmony_macros::ip;
|
use harmony_macros::ip;
|
||||||
use harmony_types::{id::Id, net::MacAddress, switch::PortLocation};
|
use harmony_types::{id::Id, switch::PortLocation};
|
||||||
use log::{debug, info};
|
|
||||||
use serde::Serialize;
|
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]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
@@ -32,126 +35,13 @@ async fn main() {
|
|||||||
(PortLocation(1, 0, 18), PortOperatingMode::Trunk),
|
(PortLocation(1, 0, 18), PortOperatingMode::Trunk),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
harmony_cli::run(
|
harmony_cli::run(
|
||||||
Inventory::autoload(),
|
Inventory::autoload(),
|
||||||
SwitchTopology::new().await,
|
SwitchTopology::new(get_switch_config()).await,
|
||||||
vec![Box::new(switch_score)],
|
vec![Box::new(switch_score)],
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -9,6 +9,14 @@ use option_ext::OptionExt;
|
|||||||
|
|
||||||
use crate::topology::{PortConfig, SwitchClient, SwitchError};
|
use crate::topology::{PortConfig, SwitchClient, SwitchError};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct BrocadeSwitchConfig {
|
||||||
|
pub ips: Vec<IpAddress>,
|
||||||
|
pub username: String,
|
||||||
|
pub password: String,
|
||||||
|
pub options: BrocadeOptions,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BrocadeSwitchClient {
|
pub struct BrocadeSwitchClient {
|
||||||
brocade: Box<dyn BrocadeClient + Send + Sync>,
|
brocade: Box<dyn BrocadeClient + Send + Sync>,
|
||||||
|
|||||||
143
harmony/src/modules/brocade/brocade.rs
Normal file
143
harmony/src/modules/brocade/brocade.rs
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
use async_trait::async_trait;
|
||||||
|
use brocade::{BrocadeOptions, PortOperatingMode};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
data::Version,
|
||||||
|
infra::brocade::{BrocadeSwitchClient, BrocadeSwitchConfig},
|
||||||
|
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<Id>,
|
||||||
|
pub 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)]
|
||||||
|
pub 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!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
pub struct BrocadeSwitchConfig {
|
||||||
|
pub ips: Vec<harmony_types::net::IpAddress>,
|
||||||
|
pub username: String,
|
||||||
|
pub password: String,
|
||||||
|
pub options: BrocadeOptions,
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub 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 {
|
||||||
|
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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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
|
||||||
|
}
|
||||||
|
}
|
||||||
5
harmony/src/modules/brocade/mod.rs
Normal file
5
harmony/src/modules/brocade/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
pub mod brocade;
|
||||||
|
pub use brocade::*;
|
||||||
|
|
||||||
|
pub mod brocade_snmp;
|
||||||
|
pub use brocade_snmp::*;
|
||||||
Reference in New Issue
Block a user