fix(ha_cluster): inject switch client for better testability
Some checks are pending
Run Check Script / check (pull_request) Waiting to run
Some checks are pending
Run Check Script / check (pull_request) Waiting to run
This commit is contained in:
parent
05205f4ac1
commit
7368184917
27
Cargo.lock
generated
27
Cargo.lock
generated
@ -1780,6 +1780,7 @@ dependencies = [
|
|||||||
name = "example-nanodc"
|
name = "example-nanodc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"brocade",
|
||||||
"cidr",
|
"cidr",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"harmony",
|
"harmony",
|
||||||
@ -1788,6 +1789,7 @@ dependencies = [
|
|||||||
"harmony_tui",
|
"harmony_tui",
|
||||||
"harmony_types",
|
"harmony_types",
|
||||||
"log",
|
"log",
|
||||||
|
"serde",
|
||||||
"tokio",
|
"tokio",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
@ -1806,6 +1808,7 @@ dependencies = [
|
|||||||
name = "example-okd-install"
|
name = "example-okd-install"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"brocade",
|
||||||
"cidr",
|
"cidr",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"harmony",
|
"harmony",
|
||||||
@ -1836,13 +1839,16 @@ dependencies = [
|
|||||||
name = "example-opnsense"
|
name = "example-opnsense"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"brocade",
|
||||||
"cidr",
|
"cidr",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"harmony",
|
"harmony",
|
||||||
"harmony_macros",
|
"harmony_macros",
|
||||||
|
"harmony_secret",
|
||||||
"harmony_tui",
|
"harmony_tui",
|
||||||
"harmony_types",
|
"harmony_types",
|
||||||
"log",
|
"log",
|
||||||
|
"serde",
|
||||||
"tokio",
|
"tokio",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
@ -1851,6 +1857,7 @@ dependencies = [
|
|||||||
name = "example-pxe"
|
name = "example-pxe"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"brocade",
|
||||||
"cidr",
|
"cidr",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"harmony",
|
"harmony",
|
||||||
@ -1865,6 +1872,15 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "example-remove-rook-osd"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"harmony",
|
||||||
|
"harmony_cli",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "example-rust"
|
name = "example-rust"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -1918,8 +1934,6 @@ dependencies = [
|
|||||||
"env_logger",
|
"env_logger",
|
||||||
"harmony",
|
"harmony",
|
||||||
"harmony_macros",
|
"harmony_macros",
|
||||||
"harmony_secret",
|
|
||||||
"harmony_secret_derive",
|
|
||||||
"harmony_tui",
|
"harmony_tui",
|
||||||
"harmony_types",
|
"harmony_types",
|
||||||
"log",
|
"log",
|
||||||
@ -4613,15 +4627,6 @@ version = "0.8.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
|
checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "remove_rook_osd"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"harmony",
|
|
||||||
"harmony_cli",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.11.27"
|
version = "0.11.27"
|
||||||
|
@ -10,6 +10,7 @@ use log::{debug, info};
|
|||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::{collections::HashSet, str::FromStr};
|
use std::{collections::HashSet, str::FromStr};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct FastIronClient {
|
pub struct FastIronClient {
|
||||||
shell: BrocadeShell,
|
shell: BrocadeShell,
|
||||||
version: BrocadeInfo,
|
version: BrocadeInfo,
|
||||||
|
@ -162,7 +162,7 @@ pub async fn init(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait BrocadeClient {
|
pub trait BrocadeClient: std::fmt::Debug {
|
||||||
/// Retrieves the operating system and version details from the connected Brocade switch.
|
/// Retrieves the operating system and version details from the connected Brocade switch.
|
||||||
///
|
///
|
||||||
/// This is typically the first call made after establishing a connection to determine
|
/// This is typically the first call made after establishing a connection to determine
|
||||||
|
@ -10,6 +10,7 @@ use crate::{
|
|||||||
parse_brocade_mac_address, shell::BrocadeShell,
|
parse_brocade_mac_address, shell::BrocadeShell,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct NetworkOperatingSystemClient {
|
pub struct NetworkOperatingSystemClient {
|
||||||
shell: BrocadeShell,
|
shell: BrocadeShell,
|
||||||
version: BrocadeInfo,
|
version: BrocadeInfo,
|
||||||
|
@ -13,6 +13,7 @@ use log::info;
|
|||||||
use russh::ChannelMsg;
|
use russh::ChannelMsg;
|
||||||
use tokio::time::timeout;
|
use tokio::time::timeout;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct BrocadeShell {
|
pub struct BrocadeShell {
|
||||||
ip: IpAddr,
|
ip: IpAddr,
|
||||||
port: u16,
|
port: u16,
|
||||||
|
@ -17,3 +17,5 @@ harmony_secret = { path = "../../harmony_secret" }
|
|||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
env_logger = { workspace = true }
|
env_logger = { workspace = true }
|
||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
|
serde = { workspace = true }
|
||||||
|
brocade = { path = "../../brocade" }
|
||||||
|
@ -3,12 +3,13 @@ use std::{
|
|||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use brocade::BrocadeOptions;
|
||||||
use cidr::Ipv4Cidr;
|
use cidr::Ipv4Cidr;
|
||||||
use harmony::{
|
use harmony::{
|
||||||
config::secret::SshKeyPair,
|
config::secret::SshKeyPair,
|
||||||
data::{FileContent, FilePath},
|
data::{FileContent, FilePath},
|
||||||
hardware::{HostCategory, Location, PhysicalHost, SwitchGroup},
|
hardware::{HostCategory, Location, PhysicalHost, SwitchGroup},
|
||||||
infra::opnsense::OPNSenseManagementInterface,
|
infra::{brocade::BrocadeSwitchClient, opnsense::OPNSenseManagementInterface},
|
||||||
inventory::Inventory,
|
inventory::Inventory,
|
||||||
modules::{
|
modules::{
|
||||||
http::StaticFilesHttpScore,
|
http::StaticFilesHttpScore,
|
||||||
@ -22,8 +23,9 @@ use harmony::{
|
|||||||
topology::{LogicalHost, UnmanagedRouter},
|
topology::{LogicalHost, UnmanagedRouter},
|
||||||
};
|
};
|
||||||
use harmony_macros::{ip, mac_address};
|
use harmony_macros::{ip, mac_address};
|
||||||
use harmony_secret::SecretManager;
|
use harmony_secret::{Secret, SecretManager};
|
||||||
use harmony_types::net::Url;
|
use harmony_types::net::Url;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
@ -32,6 +34,26 @@ async fn main() {
|
|||||||
name: String::from("fw0"),
|
name: String::from("fw0"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let switch_auth = SecretManager::get_or_prompt::<BrocadeSwitchAuth>()
|
||||||
|
.await
|
||||||
|
.expect("Failed to get credentials");
|
||||||
|
|
||||||
|
let switches: Vec<IpAddr> = vec![ip!("192.168.33.101")];
|
||||||
|
let brocade_options = Some(BrocadeOptions {
|
||||||
|
dry_run: *harmony::config::DRY_RUN,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let switch_client = BrocadeSwitchClient::init(
|
||||||
|
&switches,
|
||||||
|
&switch_auth.username,
|
||||||
|
&switch_auth.password,
|
||||||
|
brocade_options,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("Failed to connect to switch");
|
||||||
|
|
||||||
|
let switch_client = Arc::new(switch_client);
|
||||||
|
|
||||||
let opnsense = Arc::new(
|
let opnsense = Arc::new(
|
||||||
harmony::infra::opnsense::OPNSenseFirewall::new(firewall, None, "root", "opnsense").await,
|
harmony::infra::opnsense::OPNSenseFirewall::new(firewall, None, "root", "opnsense").await,
|
||||||
);
|
);
|
||||||
@ -83,7 +105,7 @@ async fn main() {
|
|||||||
name: "wk2".to_string(),
|
name: "wk2".to_string(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
switch: vec![],
|
switch_client: switch_client.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let inventory = Inventory {
|
let inventory = Inventory {
|
||||||
@ -166,3 +188,9 @@ async fn main() {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Secret, Serialize, Deserialize, Debug)]
|
||||||
|
pub struct BrocadeSwitchAuth {
|
||||||
|
pub username: String,
|
||||||
|
pub password: String,
|
||||||
|
}
|
||||||
|
@ -19,3 +19,4 @@ log = { workspace = true }
|
|||||||
env_logger = { workspace = true }
|
env_logger = { workspace = true }
|
||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
brocade = { path = "../../brocade" }
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
|
use brocade::BrocadeOptions;
|
||||||
use cidr::Ipv4Cidr;
|
use cidr::Ipv4Cidr;
|
||||||
use harmony::{
|
use harmony::{
|
||||||
hardware::{Location, SwitchGroup},
|
hardware::{Location, SwitchGroup},
|
||||||
infra::opnsense::OPNSenseManagementInterface,
|
infra::{brocade::BrocadeSwitchClient, opnsense::OPNSenseManagementInterface},
|
||||||
inventory::Inventory,
|
inventory::Inventory,
|
||||||
topology::{HAClusterTopology, LogicalHost, UnmanagedRouter},
|
topology::{HAClusterTopology, LogicalHost, UnmanagedRouter},
|
||||||
};
|
};
|
||||||
@ -22,6 +23,26 @@ pub async fn get_topology() -> HAClusterTopology {
|
|||||||
name: String::from("opnsense-1"),
|
name: String::from("opnsense-1"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let switch_auth = SecretManager::get_or_prompt::<BrocadeSwitchAuth>()
|
||||||
|
.await
|
||||||
|
.expect("Failed to get credentials");
|
||||||
|
|
||||||
|
let switches: Vec<IpAddr> = vec![ip!("192.168.1.101")]; // TODO: Adjust me
|
||||||
|
let brocade_options = Some(BrocadeOptions {
|
||||||
|
dry_run: *harmony::config::DRY_RUN,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let switch_client = BrocadeSwitchClient::init(
|
||||||
|
&switches,
|
||||||
|
&switch_auth.username,
|
||||||
|
&switch_auth.password,
|
||||||
|
brocade_options,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("Failed to connect to switch");
|
||||||
|
|
||||||
|
let switch_client = Arc::new(switch_client);
|
||||||
|
|
||||||
let config = SecretManager::get_or_prompt::<OPNSenseFirewallConfig>().await;
|
let config = SecretManager::get_or_prompt::<OPNSenseFirewallConfig>().await;
|
||||||
let config = config.unwrap();
|
let config = config.unwrap();
|
||||||
|
|
||||||
@ -58,7 +79,7 @@ pub async fn get_topology() -> HAClusterTopology {
|
|||||||
name: "bootstrap".to_string(),
|
name: "bootstrap".to_string(),
|
||||||
},
|
},
|
||||||
workers: vec![],
|
workers: vec![],
|
||||||
switch: vec![],
|
switch_client: switch_client.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,3 +96,9 @@ pub fn get_inventory() -> Inventory {
|
|||||||
control_plane_host: vec![],
|
control_plane_host: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Secret, Serialize, Deserialize, Debug)]
|
||||||
|
pub struct BrocadeSwitchAuth {
|
||||||
|
pub username: String,
|
||||||
|
pub password: String,
|
||||||
|
}
|
||||||
|
@ -19,3 +19,4 @@ log = { workspace = true }
|
|||||||
env_logger = { workspace = true }
|
env_logger = { workspace = true }
|
||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
brocade = { path = "../../brocade" }
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
|
use brocade::BrocadeOptions;
|
||||||
use cidr::Ipv4Cidr;
|
use cidr::Ipv4Cidr;
|
||||||
use harmony::{
|
use harmony::{
|
||||||
config::secret::OPNSenseFirewallCredentials,
|
config::secret::OPNSenseFirewallCredentials,
|
||||||
hardware::{Location, SwitchGroup},
|
hardware::{Location, SwitchGroup},
|
||||||
infra::opnsense::OPNSenseManagementInterface,
|
infra::{brocade::BrocadeSwitchClient, opnsense::OPNSenseManagementInterface},
|
||||||
inventory::Inventory,
|
inventory::Inventory,
|
||||||
topology::{HAClusterTopology, LogicalHost, UnmanagedRouter},
|
topology::{HAClusterTopology, LogicalHost, UnmanagedRouter},
|
||||||
};
|
};
|
||||||
use harmony_macros::{ip, ipv4};
|
use harmony_macros::{ip, ipv4};
|
||||||
use harmony_secret::SecretManager;
|
use harmony_secret::{Secret, SecretManager};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{net::IpAddr, sync::Arc};
|
use std::{net::IpAddr, sync::Arc};
|
||||||
|
|
||||||
pub async fn get_topology() -> HAClusterTopology {
|
pub async fn get_topology() -> HAClusterTopology {
|
||||||
@ -16,6 +18,26 @@ pub async fn get_topology() -> HAClusterTopology {
|
|||||||
name: String::from("opnsense-1"),
|
name: String::from("opnsense-1"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let switch_auth = SecretManager::get_or_prompt::<BrocadeSwitchAuth>()
|
||||||
|
.await
|
||||||
|
.expect("Failed to get credentials");
|
||||||
|
|
||||||
|
let switches: Vec<IpAddr> = vec![ip!("192.168.1.101")]; // TODO: Adjust me
|
||||||
|
let brocade_options = Some(BrocadeOptions {
|
||||||
|
dry_run: *harmony::config::DRY_RUN,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let switch_client = BrocadeSwitchClient::init(
|
||||||
|
&switches,
|
||||||
|
&switch_auth.username,
|
||||||
|
&switch_auth.password,
|
||||||
|
brocade_options,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("Failed to connect to switch");
|
||||||
|
|
||||||
|
let switch_client = Arc::new(switch_client);
|
||||||
|
|
||||||
let config = SecretManager::get_or_prompt::<OPNSenseFirewallCredentials>().await;
|
let config = SecretManager::get_or_prompt::<OPNSenseFirewallCredentials>().await;
|
||||||
let config = config.unwrap();
|
let config = config.unwrap();
|
||||||
|
|
||||||
@ -52,7 +74,7 @@ pub async fn get_topology() -> HAClusterTopology {
|
|||||||
name: "cp0".to_string(),
|
name: "cp0".to_string(),
|
||||||
},
|
},
|
||||||
workers: vec![],
|
workers: vec![],
|
||||||
switch: vec![],
|
switch_client: switch_client.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,3 +91,9 @@ pub fn get_inventory() -> Inventory {
|
|||||||
control_plane_host: vec![],
|
control_plane_host: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Secret, Serialize, Deserialize, Debug)]
|
||||||
|
pub struct BrocadeSwitchAuth {
|
||||||
|
pub username: String,
|
||||||
|
pub password: String,
|
||||||
|
}
|
||||||
|
@ -16,3 +16,6 @@ harmony_macros = { path = "../../harmony_macros" }
|
|||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
env_logger = { workspace = true }
|
env_logger = { workspace = true }
|
||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
|
harmony_secret = { path = "../../harmony_secret" }
|
||||||
|
brocade = { path = "../../brocade" }
|
||||||
|
serde = { workspace = true }
|
||||||
|
@ -3,10 +3,11 @@ use std::{
|
|||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use brocade::BrocadeOptions;
|
||||||
use cidr::Ipv4Cidr;
|
use cidr::Ipv4Cidr;
|
||||||
use harmony::{
|
use harmony::{
|
||||||
hardware::{HostCategory, Location, PhysicalHost, SwitchGroup},
|
hardware::{HostCategory, Location, PhysicalHost, SwitchGroup},
|
||||||
infra::opnsense::OPNSenseManagementInterface,
|
infra::{brocade::BrocadeSwitchClient, opnsense::OPNSenseManagementInterface},
|
||||||
inventory::Inventory,
|
inventory::Inventory,
|
||||||
modules::{
|
modules::{
|
||||||
dummy::{ErrorScore, PanicScore, SuccessScore},
|
dummy::{ErrorScore, PanicScore, SuccessScore},
|
||||||
@ -18,7 +19,9 @@ use harmony::{
|
|||||||
topology::{LogicalHost, UnmanagedRouter},
|
topology::{LogicalHost, UnmanagedRouter},
|
||||||
};
|
};
|
||||||
use harmony_macros::{ip, mac_address};
|
use harmony_macros::{ip, mac_address};
|
||||||
|
use harmony_secret::{Secret, SecretManager};
|
||||||
use harmony_types::net::Url;
|
use harmony_types::net::Url;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
@ -27,6 +30,26 @@ async fn main() {
|
|||||||
name: String::from("opnsense-1"),
|
name: String::from("opnsense-1"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let switch_auth = SecretManager::get_or_prompt::<BrocadeSwitchAuth>()
|
||||||
|
.await
|
||||||
|
.expect("Failed to get credentials");
|
||||||
|
|
||||||
|
let switches: Vec<IpAddr> = vec![ip!("192.168.5.101")]; // TODO: Adjust me
|
||||||
|
let brocade_options = Some(BrocadeOptions {
|
||||||
|
dry_run: *harmony::config::DRY_RUN,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let switch_client = BrocadeSwitchClient::init(
|
||||||
|
&switches,
|
||||||
|
&switch_auth.username,
|
||||||
|
&switch_auth.password,
|
||||||
|
brocade_options,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("Failed to connect to switch");
|
||||||
|
|
||||||
|
let switch_client = Arc::new(switch_client);
|
||||||
|
|
||||||
let opnsense = Arc::new(
|
let opnsense = Arc::new(
|
||||||
harmony::infra::opnsense::OPNSenseFirewall::new(firewall, None, "root", "opnsense").await,
|
harmony::infra::opnsense::OPNSenseFirewall::new(firewall, None, "root", "opnsense").await,
|
||||||
);
|
);
|
||||||
@ -54,7 +77,7 @@ async fn main() {
|
|||||||
name: "cp0".to_string(),
|
name: "cp0".to_string(),
|
||||||
},
|
},
|
||||||
workers: vec![],
|
workers: vec![],
|
||||||
switch: vec![],
|
switch_client: switch_client.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let inventory = Inventory {
|
let inventory = Inventory {
|
||||||
@ -109,3 +132,9 @@ async fn main() {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Secret, Serialize, Deserialize, Debug)]
|
||||||
|
pub struct BrocadeSwitchAuth {
|
||||||
|
pub username: String,
|
||||||
|
pub password: String,
|
||||||
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use brocade::BrocadeOptions;
|
|
||||||
use harmony_macros::ip;
|
use harmony_macros::ip;
|
||||||
use harmony_secret::SecretManager;
|
|
||||||
use harmony_types::{
|
use harmony_types::{
|
||||||
net::{MacAddress, Url},
|
net::{MacAddress, Url},
|
||||||
switch::PortLocation,
|
switch::PortLocation,
|
||||||
@ -14,8 +12,6 @@ use log::info;
|
|||||||
use crate::data::FileContent;
|
use crate::data::FileContent;
|
||||||
use crate::executors::ExecutorError;
|
use crate::executors::ExecutorError;
|
||||||
use crate::hardware::PhysicalHost;
|
use crate::hardware::PhysicalHost;
|
||||||
use crate::infra::brocade::BrocadeSwitchAuth;
|
|
||||||
use crate::infra::brocade::BrocadeSwitchClient;
|
|
||||||
use crate::modules::okd::crd::{
|
use crate::modules::okd::crd::{
|
||||||
InstallPlanApproval, OperatorGroup, OperatorGroupSpec, Subscription, SubscriptionSpec,
|
InstallPlanApproval, OperatorGroup, OperatorGroupSpec, Subscription, SubscriptionSpec,
|
||||||
nmstate::{self, NMState, NodeNetworkConfigurationPolicy, NodeNetworkConfigurationPolicySpec},
|
nmstate::{self, NMState, NodeNetworkConfigurationPolicy, NodeNetworkConfigurationPolicySpec},
|
||||||
@ -30,7 +26,6 @@ use super::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::net::IpAddr;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -43,10 +38,10 @@ pub struct HAClusterTopology {
|
|||||||
pub tftp_server: Arc<dyn TftpServer>,
|
pub tftp_server: Arc<dyn TftpServer>,
|
||||||
pub http_server: Arc<dyn HttpServer>,
|
pub http_server: Arc<dyn HttpServer>,
|
||||||
pub dns_server: Arc<dyn DnsServer>,
|
pub dns_server: Arc<dyn DnsServer>,
|
||||||
|
pub switch_client: Arc<dyn SwitchClient>,
|
||||||
pub bootstrap_host: LogicalHost,
|
pub bootstrap_host: LogicalHost,
|
||||||
pub control_plane: Vec<LogicalHost>,
|
pub control_plane: Vec<LogicalHost>,
|
||||||
pub workers: Vec<LogicalHost>,
|
pub workers: Vec<LogicalHost>,
|
||||||
pub switch: Vec<LogicalHost>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@ -280,36 +275,15 @@ impl HAClusterTopology {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_switch_client(&self) -> Result<Box<dyn SwitchClient>, SwitchError> {
|
|
||||||
let auth = SecretManager::get_or_prompt::<BrocadeSwitchAuth>()
|
|
||||||
.await
|
|
||||||
.map_err(|e| SwitchError::new(format!("Failed to get credentials: {e}")))?;
|
|
||||||
|
|
||||||
// FIXME: We assume Brocade switches
|
|
||||||
let switches: Vec<IpAddr> = self.switch.iter().map(|s| s.ip).collect();
|
|
||||||
let brocade_options = Some(BrocadeOptions {
|
|
||||||
dry_run: *crate::config::DRY_RUN,
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
let client =
|
|
||||||
BrocadeSwitchClient::init(&switches, &auth.username, &auth.password, brocade_options)
|
|
||||||
.await
|
|
||||||
.map_err(|e| SwitchError::new(format!("Failed to connect to switch: {e}")))?;
|
|
||||||
|
|
||||||
Ok(Box::new(client))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn configure_port_channel(
|
async fn configure_port_channel(
|
||||||
&self,
|
&self,
|
||||||
host: &PhysicalHost,
|
host: &PhysicalHost,
|
||||||
config: &HostNetworkConfig,
|
config: &HostNetworkConfig,
|
||||||
) -> Result<(), SwitchError> {
|
) -> Result<(), SwitchError> {
|
||||||
debug!("Configuring port channel: {config:#?}");
|
debug!("Configuring port channel: {config:#?}");
|
||||||
let client = self.get_switch_client().await?;
|
|
||||||
|
|
||||||
let switch_ports = config.switch_ports.iter().map(|s| s.port.clone()).collect();
|
let switch_ports = config.switch_ports.iter().map(|s| s.port.clone()).collect();
|
||||||
|
|
||||||
client
|
self.switch_client
|
||||||
.configure_port_channel(&format!("Harmony_{}", host.id), switch_ports)
|
.configure_port_channel(&format!("Harmony_{}", host.id), switch_ports)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| SwitchError::new(format!("Failed to configure switch: {e}")))?;
|
.map_err(|e| SwitchError::new(format!("Failed to configure switch: {e}")))?;
|
||||||
@ -333,10 +307,10 @@ impl HAClusterTopology {
|
|||||||
tftp_server: dummy_infra.clone(),
|
tftp_server: dummy_infra.clone(),
|
||||||
http_server: dummy_infra.clone(),
|
http_server: dummy_infra.clone(),
|
||||||
dns_server: dummy_infra.clone(),
|
dns_server: dummy_infra.clone(),
|
||||||
|
switch_client: dummy_infra.clone(),
|
||||||
bootstrap_host: dummy_host,
|
bootstrap_host: dummy_host,
|
||||||
control_plane: vec![],
|
control_plane: vec![],
|
||||||
workers: vec![],
|
workers: vec![],
|
||||||
switch: vec![],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -494,8 +468,7 @@ impl HttpServer for HAClusterTopology {
|
|||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Switch for HAClusterTopology {
|
impl Switch for HAClusterTopology {
|
||||||
async fn setup_switch(&self) -> Result<(), SwitchError> {
|
async fn setup_switch(&self) -> Result<(), SwitchError> {
|
||||||
let client = self.get_switch_client().await?;
|
self.switch_client.setup().await?;
|
||||||
client.setup().await?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,8 +476,7 @@ impl Switch for HAClusterTopology {
|
|||||||
&self,
|
&self,
|
||||||
mac_address: &MacAddress,
|
mac_address: &MacAddress,
|
||||||
) -> Result<Option<PortLocation>, SwitchError> {
|
) -> Result<Option<PortLocation>, SwitchError> {
|
||||||
let client = self.get_switch_client().await?;
|
let port = self.switch_client.find_port(mac_address).await?;
|
||||||
let port = client.find_port(mac_address).await?;
|
|
||||||
Ok(port)
|
Ok(port)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -704,3 +676,25 @@ impl DnsServer for DummyInfra {
|
|||||||
unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA)
|
unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl SwitchClient for DummyInfra {
|
||||||
|
async fn setup(&self) -> Result<(), SwitchError> {
|
||||||
|
unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn find_port(
|
||||||
|
&self,
|
||||||
|
_mac_address: &MacAddress,
|
||||||
|
) -> Result<Option<PortLocation>, SwitchError> {
|
||||||
|
unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn configure_port_channel(
|
||||||
|
&self,
|
||||||
|
_channel_name: &str,
|
||||||
|
_switch_ports: Vec<PortLocation>,
|
||||||
|
) -> Result<u8, SwitchError> {
|
||||||
|
unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
use std::{error::Error, net::Ipv4Addr, str::FromStr, sync::Arc};
|
use std::{
|
||||||
|
error::Error,
|
||||||
|
fmt::{self, Debug},
|
||||||
|
net::Ipv4Addr,
|
||||||
|
str::FromStr,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
@ -19,8 +25,8 @@ pub struct DHCPStaticEntry {
|
|||||||
pub ip: Ipv4Addr,
|
pub ip: Ipv4Addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for DHCPStaticEntry {
|
impl fmt::Display for DHCPStaticEntry {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let mac = self
|
let mac = self
|
||||||
.mac
|
.mac
|
||||||
.iter()
|
.iter()
|
||||||
@ -42,8 +48,8 @@ pub trait Firewall: Send + Sync {
|
|||||||
fn get_host(&self) -> LogicalHost;
|
fn get_host(&self) -> LogicalHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for dyn Firewall {
|
impl Debug for dyn Firewall {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.write_fmt(format_args!("Firewall {}", self.get_ip()))
|
f.write_fmt(format_args!("Firewall {}", self.get_ip()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,7 +71,7 @@ pub struct PxeOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait DhcpServer: Send + Sync + std::fmt::Debug {
|
pub trait DhcpServer: Send + Sync + Debug {
|
||||||
async fn add_static_mapping(&self, entry: &DHCPStaticEntry) -> Result<(), ExecutorError>;
|
async fn add_static_mapping(&self, entry: &DHCPStaticEntry) -> Result<(), ExecutorError>;
|
||||||
async fn remove_static_mapping(&self, mac: &MacAddress) -> Result<(), ExecutorError>;
|
async fn remove_static_mapping(&self, mac: &MacAddress) -> Result<(), ExecutorError>;
|
||||||
async fn list_static_mappings(&self) -> Vec<(MacAddress, IpAddress)>;
|
async fn list_static_mappings(&self) -> Vec<(MacAddress, IpAddress)>;
|
||||||
@ -104,8 +110,8 @@ pub trait DnsServer: Send + Sync {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for dyn DnsServer {
|
impl Debug for dyn DnsServer {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.write_fmt(format_args!("DnsServer {}", self.get_ip()))
|
f.write_fmt(format_args!("DnsServer {}", self.get_ip()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,8 +147,8 @@ pub enum DnsRecordType {
|
|||||||
TXT,
|
TXT,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for DnsRecordType {
|
impl fmt::Display for DnsRecordType {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
DnsRecordType::A => write!(f, "A"),
|
DnsRecordType::A => write!(f, "A"),
|
||||||
DnsRecordType::AAAA => write!(f, "AAAA"),
|
DnsRecordType::AAAA => write!(f, "AAAA"),
|
||||||
@ -216,8 +222,8 @@ pub struct SwitchError {
|
|||||||
msg: String,
|
msg: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for SwitchError {
|
impl fmt::Display for SwitchError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.write_str(&self.msg)
|
f.write_str(&self.msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,7 +231,7 @@ impl std::fmt::Display for SwitchError {
|
|||||||
impl Error for SwitchError {}
|
impl Error for SwitchError {}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait SwitchClient: Send + Sync {
|
pub trait SwitchClient: Debug + Send + Sync {
|
||||||
/// Executes essential, idempotent, one-time initial configuration steps.
|
/// Executes essential, idempotent, one-time initial configuration steps.
|
||||||
///
|
///
|
||||||
/// This is an opiniated procedure that setups a switch to provide high availability
|
/// This is an opiniated procedure that setups a switch to provide high availability
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use brocade::{BrocadeClient, BrocadeOptions, InterSwitchLink, InterfaceStatus, PortOperatingMode};
|
use brocade::{BrocadeClient, BrocadeOptions, InterSwitchLink, InterfaceStatus, PortOperatingMode};
|
||||||
use harmony_secret::Secret;
|
|
||||||
use harmony_types::{
|
use harmony_types::{
|
||||||
net::{IpAddress, MacAddress},
|
net::{IpAddress, MacAddress},
|
||||||
switch::{PortDeclaration, PortLocation},
|
switch::{PortDeclaration, PortLocation},
|
||||||
};
|
};
|
||||||
use option_ext::OptionExt;
|
use option_ext::OptionExt;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::topology::{SwitchClient, SwitchError};
|
use crate::topology::{SwitchClient, SwitchError};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct BrocadeSwitchClient {
|
pub struct BrocadeSwitchClient {
|
||||||
brocade: Box<dyn BrocadeClient + Send + Sync>,
|
brocade: Box<dyn BrocadeClient + Send + Sync>,
|
||||||
}
|
}
|
||||||
@ -114,12 +113,6 @@ impl SwitchClient for BrocadeSwitchClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Secret, Serialize, Deserialize, Debug)]
|
|
||||||
pub struct BrocadeSwitchAuth {
|
|
||||||
pub username: String,
|
|
||||||
pub password: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
@ -235,7 +228,7 @@ mod tests {
|
|||||||
assert_that!(*configured_interfaces).is_empty();
|
assert_that!(*configured_interfaces).is_empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct FakeBrocadeClient {
|
struct FakeBrocadeClient {
|
||||||
stack_topology: Vec<InterSwitchLink>,
|
stack_topology: Vec<InterSwitchLink>,
|
||||||
interfaces: Vec<InterfaceInfo>,
|
interfaces: Vec<InterfaceInfo>,
|
||||||
|
Loading…
Reference in New Issue
Block a user