Small example to show how to compose components (capabilities) in a Topology to simplify reusing existing components for different topologies
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
72
Cargo.lock
generated
Normal file
72
Cargo.lock
generated
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ambassador"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e68de4cdc6006162265d0957edb4a860fe4e711b1dc17a5746fd95f952f08285"
|
||||||
|
dependencies = [
|
||||||
|
"itertools",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "harmony-composable"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"ambassador",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.10.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.103"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.109"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||||
7
Cargo.toml
Normal file
7
Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "harmony-composable"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ambassador = "0.4.2"
|
||||||
2
src/components/mod.rs
Normal file
2
src/components/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod network_manager;
|
||||||
|
pub mod switch;
|
||||||
7
src/components/network_manager.rs
Normal file
7
src/components/network_manager.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
use ambassador::delegatable_trait;
|
||||||
|
|
||||||
|
#[delegatable_trait]
|
||||||
|
pub trait NetworkManager {
|
||||||
|
fn ensure_network_manager_installed(&self) -> Result<(), String>;
|
||||||
|
fn configure_bond(&self, bond: String) -> Result<(), String>;
|
||||||
|
}
|
||||||
7
src/components/switch.rs
Normal file
7
src/components/switch.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
use ambassador::delegatable_trait;
|
||||||
|
|
||||||
|
#[delegatable_trait]
|
||||||
|
pub trait Switch {
|
||||||
|
fn setup_switch(&self) -> Result<(), String>;
|
||||||
|
fn create_port_channel(&self, port_channel: String) -> Result<(), String>;
|
||||||
|
}
|
||||||
1
src/core/mod.rs
Normal file
1
src/core/mod.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub mod topology;
|
||||||
3
src/core/topology.rs
Normal file
3
src/core/topology.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub trait Topology {
|
||||||
|
fn name(&self) -> String;
|
||||||
|
}
|
||||||
15
src/infra/brocade.rs
Normal file
15
src/infra/brocade.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
use crate::components::switch::Switch;
|
||||||
|
|
||||||
|
pub struct BrocadeSwitch {}
|
||||||
|
|
||||||
|
impl Switch for BrocadeSwitch {
|
||||||
|
fn setup_switch(&self) -> Result<(), String> {
|
||||||
|
println!("BrocadeSwitch: Installing...");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_port_channel(&self, port_channel: String) -> Result<(), String> {
|
||||||
|
println!("BrocadeSwitch: Creating port channel {}", port_channel);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/infra/k8s_client.rs
Normal file
1
src/infra/k8s_client.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub struct Client {}
|
||||||
4
src/infra/mod.rs
Normal file
4
src/infra/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
pub mod brocade;
|
||||||
|
pub mod k8s_client;
|
||||||
|
pub mod nmcli;
|
||||||
|
pub mod openshift;
|
||||||
15
src/infra/nmcli.rs
Normal file
15
src/infra/nmcli.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
use crate::components::network_manager::NetworkManager;
|
||||||
|
|
||||||
|
pub struct NmcliNetworkManager {}
|
||||||
|
|
||||||
|
impl NetworkManager for NmcliNetworkManager {
|
||||||
|
fn ensure_network_manager_installed(&self) -> Result<(), String> {
|
||||||
|
println!("Nmcli: Installing...");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configure_bond(&self, bond: String) -> Result<(), String> {
|
||||||
|
println!("Nmcli: Configuring bond {}", bond);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/infra/openshift.rs
Normal file
22
src/infra/openshift.rs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::{components::network_manager::NetworkManager, infra::k8s_client};
|
||||||
|
|
||||||
|
pub struct OpenShiftNmStateNetworkManager {
|
||||||
|
pub k8s_client: Arc<k8s_client::Client>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NetworkManager for OpenShiftNmStateNetworkManager {
|
||||||
|
fn ensure_network_manager_installed(&self) -> Result<(), String> {
|
||||||
|
println!("OpenShift NM State: Installing...");
|
||||||
|
|
||||||
|
// self.k8s_client.apply(...)
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configure_bond(&self, bond: String) -> Result<(), String> {
|
||||||
|
println!("OpenShift NM State: Configuring bond {}", bond);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/main.rs
Normal file
38
src/main.rs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
components::{network_manager::NetworkManager, switch::Switch},
|
||||||
|
core::topology::Topology,
|
||||||
|
infra::brocade::BrocadeSwitch,
|
||||||
|
topologies::{k8s::NetworkManagerProvider, k8s_anywhere::K8sAnywhereTopology},
|
||||||
|
};
|
||||||
|
|
||||||
|
mod components;
|
||||||
|
mod core;
|
||||||
|
mod infra;
|
||||||
|
mod topologies;
|
||||||
|
|
||||||
|
fn configure_port_channel<T: Topology + Switch>(topology: &T) -> Result<(), String> {
|
||||||
|
println!(
|
||||||
|
"--- Running configure_port_channel for: {} ---",
|
||||||
|
topology.name()
|
||||||
|
);
|
||||||
|
topology.setup_switch()?;
|
||||||
|
topology.create_port_channel("pc-123".to_string())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configure_bond<T: Topology + NetworkManager>(topology: &T) -> Result<(), String> {
|
||||||
|
println!("--- Running configure_bond for: {} ---", topology.name());
|
||||||
|
topology.ensure_network_manager_installed()?;
|
||||||
|
topology.configure_bond("bond0".to_string())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let topology = K8sAnywhereTopology::new(NetworkManagerProvider {}, Arc::new(BrocadeSwitch {}));
|
||||||
|
|
||||||
|
// Simulate the execution of a Score's Interpret
|
||||||
|
configure_bond(&topology).unwrap();
|
||||||
|
configure_port_channel(&topology).unwrap();
|
||||||
|
}
|
||||||
35
src/topologies/k8s.rs
Normal file
35
src/topologies/k8s.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
components::network_manager::NetworkManager,
|
||||||
|
core::topology::Topology,
|
||||||
|
infra::{k8s_client, nmcli::NmcliNetworkManager, openshift::OpenShiftNmStateNetworkManager},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub enum K8sSource {
|
||||||
|
K3dFamily,
|
||||||
|
OpenShiftFamily,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct K8sState {
|
||||||
|
pub source: K8sSource,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait K8sClient {
|
||||||
|
fn k8s_state(&self) -> K8sState;
|
||||||
|
fn k8s_client(&self) -> Arc<k8s_client::Client>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NetworkManagerProvider {}
|
||||||
|
|
||||||
|
impl NetworkManagerProvider {
|
||||||
|
pub fn provide<T: Topology + K8sClient>(&self, topology: &T) -> Arc<dyn NetworkManager> {
|
||||||
|
match topology.k8s_state().source {
|
||||||
|
K8sSource::K3dFamily => Arc::new(NmcliNetworkManager {}),
|
||||||
|
K8sSource::OpenShiftFamily => {
|
||||||
|
let k8s_client = topology.k8s_client().clone();
|
||||||
|
Arc::new(OpenShiftNmStateNetworkManager { k8s_client })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/topologies/k8s_anywhere.rs
Normal file
60
src/topologies/k8s_anywhere.rs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
use std::{cell::OnceCell, sync::Arc};
|
||||||
|
|
||||||
|
use ambassador::delegate_to_methods;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
components::{
|
||||||
|
network_manager::{NetworkManager, ambassador_impl_NetworkManager},
|
||||||
|
switch::{Switch, ambassador_impl_Switch},
|
||||||
|
},
|
||||||
|
core::topology::Topology,
|
||||||
|
infra::k8s_client,
|
||||||
|
topologies::k8s::{K8sClient, K8sSource, K8sState, NetworkManagerProvider},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct K8sAnywhereTopology {
|
||||||
|
network_manager_provider: NetworkManagerProvider,
|
||||||
|
network_manager: OnceCell<Arc<dyn NetworkManager>>,
|
||||||
|
switch: Arc<dyn Switch>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[delegate_to_methods]
|
||||||
|
#[delegate(NetworkManager, target_ref = "network_manager")]
|
||||||
|
#[delegate(Switch, target_ref = "switch")]
|
||||||
|
impl K8sAnywhereTopology {
|
||||||
|
pub fn new(network_manager_provider: NetworkManagerProvider, switch: Arc<dyn Switch>) -> Self {
|
||||||
|
Self {
|
||||||
|
network_manager_provider,
|
||||||
|
network_manager: OnceCell::new(),
|
||||||
|
switch,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn network_manager(&self) -> &dyn NetworkManager {
|
||||||
|
self.network_manager
|
||||||
|
.get_or_init(|| self.network_manager_provider.provide(self))
|
||||||
|
.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn switch(&self) -> &dyn Switch {
|
||||||
|
self.switch.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Topology for K8sAnywhereTopology {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
"K8sAnywhere".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl K8sClient for K8sAnywhereTopology {
|
||||||
|
fn k8s_state(&self) -> K8sState {
|
||||||
|
K8sState {
|
||||||
|
source: K8sSource::OpenShiftFamily,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k8s_client(&self) -> Arc<k8s_client::Client> {
|
||||||
|
Arc::new(k8s_client::Client {})
|
||||||
|
}
|
||||||
|
}
|
||||||
2
src/topologies/mod.rs
Normal file
2
src/topologies/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod k8s;
|
||||||
|
pub mod k8s_anywhere;
|
||||||
Reference in New Issue
Block a user