feat: Refactored harmony into a workspace with independent modules per client, completed RusshClient test_connection implementation. Needs refactoring though
This commit is contained in:
parent
cc01ec5fe5
commit
8592a3bc36
6
harmony-rs/Cargo.lock
generated
6
harmony-rs/Cargo.lock
generated
@ -619,6 +619,12 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "fqm"
|
name = "fqm"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"env_logger",
|
||||||
|
"harmony",
|
||||||
|
"log",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "funty"
|
name = "funty"
|
||||||
|
|||||||
@ -15,3 +15,4 @@ log = "0.4.22"
|
|||||||
env_logger = "0.11.5"
|
env_logger = "0.11.5"
|
||||||
derive-new = "0.7.0"
|
derive-new = "0.7.0"
|
||||||
async-trait = "0.1.82"
|
async-trait = "0.1.82"
|
||||||
|
tokio = { version = "1.40.0", features = ["io-std"] }
|
||||||
|
|||||||
@ -4,3 +4,8 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
harmony = { path = "../harmony" }
|
||||||
|
log = { workspace = true }
|
||||||
|
env_logger = { workspace = true }
|
||||||
|
tokio = { workspace = true }
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
use crate::domain::{
|
use harmony::domain::{
|
||||||
hardware::{Location, Host, HostCategory},
|
hardware::{Host, HostCategory, Location, NetworkInterface},
|
||||||
inventory::Inventory,
|
inventory::Inventory,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn get_fqm_inventory() -> Inventory {
|
pub fn get_inventory() -> Inventory {
|
||||||
|
let network = vec![NetworkInterface::new(1_000_000_000, "TODO MAC ADDRESS".into(), true ) ];
|
||||||
|
let storage = vec![];
|
||||||
Inventory {
|
Inventory {
|
||||||
location: Location::new(
|
location: Location::new(
|
||||||
"1134 Grande Allée Ouest 1er étage, Québec, Qc".into(),
|
"1134 Grande Allée Ouest 1er étage, Québec, Qc".into(),
|
||||||
@ -11,8 +13,8 @@ pub fn get_fqm_inventory() -> Inventory {
|
|||||||
),
|
),
|
||||||
host: vec![Host {
|
host: vec![Host {
|
||||||
category: HostCategory::Server,
|
category: HostCategory::Server,
|
||||||
network: vec![],
|
network,
|
||||||
storage: vec![],
|
storage,
|
||||||
labels: vec![],
|
labels: vec![],
|
||||||
}],
|
}],
|
||||||
switch: vec![],
|
switch: vec![],
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
pub mod inventory;
|
||||||
pub fn add(left: usize, right: usize) -> usize {
|
pub fn add(left: usize, right: usize) -> usize {
|
||||||
left + right
|
left + right
|
||||||
}
|
}
|
||||||
|
|||||||
22
harmony-rs/fqm/src/main.rs
Normal file
22
harmony-rs/fqm/src/main.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use fqm::inventory::get_inventory;
|
||||||
|
use harmony::{
|
||||||
|
domain::{
|
||||||
|
inventory::{Inventory, InventoryFilter},
|
||||||
|
maestro::Maestro,
|
||||||
|
},
|
||||||
|
modules::opnsense_dhcp::OPNSenseDhcpScore,
|
||||||
|
};
|
||||||
|
use log::info;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
info!("FQM Harmony Starting");
|
||||||
|
let maestro = Maestro::new(get_inventory());
|
||||||
|
let score = OPNSenseDhcpScore::new(InventoryFilter::new(vec![]));
|
||||||
|
let result = maestro.interpret(score).await.unwrap();
|
||||||
|
info!("{result}");
|
||||||
|
}).await;
|
||||||
|
}
|
||||||
@ -11,7 +11,7 @@ rust-ipmi = "0.1.1"
|
|||||||
semver = "1.0.23"
|
semver = "1.0.23"
|
||||||
serde = { version = "1.0.209", features = ["derive"] }
|
serde = { version = "1.0.209", features = ["derive"] }
|
||||||
serde_json = "1.0.127"
|
serde_json = "1.0.127"
|
||||||
tokio = { version = "1.40.0", features = ["io-std"] }
|
tokio = { workspace = true }
|
||||||
derive-new = { workspace = true }
|
derive-new = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
env_logger = { workspace = true }
|
env_logger = { workspace = true }
|
||||||
|
|||||||
@ -29,5 +29,5 @@ impl std::error::Error for ExecutorError {}
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait SshClient {
|
pub trait SshClient {
|
||||||
async fn test_connection(&self, username: String, password: String) -> Result<(), ExecutorError>;
|
async fn test_connection(&self, username: &str, password: &str) -> Result<(), ExecutorError>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,14 +18,15 @@ pub enum HostCategory {
|
|||||||
Switch,
|
Switch,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, new)]
|
||||||
pub struct NetworkInterface {
|
pub struct NetworkInterface {
|
||||||
speed: u64,
|
speed: u64,
|
||||||
mac_address: MacAddress,
|
mac_address: MacAddress,
|
||||||
plugged_in: bool,
|
plugged_in: bool,
|
||||||
}
|
}
|
||||||
type MacAddress = String;
|
type MacAddress = String;
|
||||||
#[derive(Debug)]
|
|
||||||
|
#[derive(Debug, new)]
|
||||||
pub enum StorageConnectionType {
|
pub enum StorageConnectionType {
|
||||||
Sata3g,
|
Sata3g,
|
||||||
Sata6g,
|
Sata6g,
|
||||||
@ -56,7 +57,10 @@ pub struct Switch {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Firewall {}
|
pub struct Firewall {}
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Label;
|
pub struct Label {
|
||||||
|
name: String,
|
||||||
|
value: String,
|
||||||
|
}
|
||||||
pub type Address = String;
|
pub type Address = String;
|
||||||
|
|
||||||
#[derive(new, Debug)]
|
#[derive(new, Debug)]
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use derive_new::new;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
data::{Id, Version},
|
data::{Id, Version}, executors::ExecutorError, inventory::Inventory, score::Score
|
||||||
inventory::Inventory,
|
|
||||||
score::Score,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum InterpretName {
|
pub enum InterpretName {
|
||||||
@ -16,19 +19,25 @@ impl std::fmt::Display for InterpretName {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
pub trait Interpret {
|
pub trait Interpret {
|
||||||
fn execute(&self, inventory: &Inventory) -> Result<Outcome, InterpretError>;
|
async fn execute(&self, inventory: &Inventory) -> Result<Outcome, InterpretError>;
|
||||||
fn get_name(&self) -> InterpretName;
|
fn get_name(&self) -> InterpretName;
|
||||||
fn get_version(&self) -> Version;
|
fn get_version(&self) -> Version;
|
||||||
fn get_status(&self) -> InterpretStatus;
|
fn get_status(&self) -> InterpretStatus;
|
||||||
fn get_children(&self) -> Vec<Id>;
|
fn get_children(&self) -> Vec<Id>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, new)]
|
||||||
pub struct Outcome {
|
pub struct Outcome {
|
||||||
status: InterpretStatus,
|
status: InterpretStatus,
|
||||||
message: String,
|
message: String,
|
||||||
}
|
}
|
||||||
|
impl std::fmt::Display for Outcome {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_fmt(format_args!("Outcome {}: {}", self.status, self.message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum InterpretStatus {
|
pub enum InterpretStatus {
|
||||||
@ -39,7 +48,34 @@ pub enum InterpretStatus {
|
|||||||
BLOCKED,
|
BLOCKED,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for InterpretStatus {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let msg = match self {
|
||||||
|
InterpretStatus::SUCCESS => "SUCCESS",
|
||||||
|
InterpretStatus::FAILURE => "FAILURE",
|
||||||
|
InterpretStatus::RUNNING => "RUNNING",
|
||||||
|
InterpretStatus::QUEUED => "QUEUED",
|
||||||
|
InterpretStatus::BLOCKED => "BLOCKED",
|
||||||
|
};
|
||||||
|
f.write_str(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InterpretError {
|
pub struct InterpretError {
|
||||||
msg: String,
|
msg: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for InterpretError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str(&self.msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Error for InterpretError {}
|
||||||
|
|
||||||
|
impl From<ExecutorError> for InterpretError{
|
||||||
|
fn from(value: ExecutorError) -> Self {
|
||||||
|
Self { msg: format!("InterpretError : {value}") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
use super::{interpret::Interpret, inventory::Inventory, score::Score};
|
use super::{interpret::{Interpret, InterpretError, Outcome}, inventory::Inventory, score::Score};
|
||||||
|
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
pub struct Maestro {
|
pub struct Maestro {
|
||||||
@ -28,11 +28,12 @@ impl Maestro {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interpret<S: Score>(&self, score: S) {
|
pub async fn interpret<S: Score>(&self, score: S) -> Result<Outcome, InterpretError> {
|
||||||
info!("Running score {score:?}");
|
info!("Running score {score:?}");
|
||||||
let interpret: S::InterpretType = score.create_interpret();
|
let interpret: S::InterpretType = score.create_interpret();
|
||||||
info!("Launching interpret {interpret:?}");
|
info!("Launching interpret {interpret:?}");
|
||||||
let result = interpret.execute(&self.inventory);
|
let result = interpret.execute(&self.inventory).await;
|
||||||
info!("Got result {result:?}");
|
info!("Got result {result:?}");
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
use log::info;
|
||||||
use russh::{client, keys::key};
|
use russh::{client, keys::key};
|
||||||
|
|
||||||
use crate::domain::executors::{ExecutorError, SshClient};
|
use crate::domain::executors::{ExecutorError, SshClient};
|
||||||
@ -9,11 +10,14 @@ pub struct RusshClient;
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl SshClient for RusshClient {
|
impl SshClient for RusshClient {
|
||||||
async fn test_connection(&self, _username: String, _password: String) -> Result<(), crate::domain::executors::ExecutorError> {
|
async fn test_connection(&self, _username: &str, _password: &str) -> Result<(), crate::domain::executors::ExecutorError> {
|
||||||
let config = client::Config::default();
|
let config = client::Config::default();
|
||||||
let c = Client{};
|
let c = Client{};
|
||||||
let _client = client::connect(Arc::new(config), ("192.168.12.1", 22), c).await?;
|
let mut client = client::connect(Arc::new(config), ("192.168.1.1", 22), c).await?;
|
||||||
Ok(())
|
match client.authenticate_password("nationtech", "opnsense").await? {
|
||||||
|
true => Ok(()),
|
||||||
|
false => Err(ExecutorError::AuthenticationError("ssh authentication failed".to_string())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,6 +40,7 @@ impl client::Handler for Client {
|
|||||||
|
|
||||||
impl From<russh::Error> for ExecutorError {
|
impl From<russh::Error> for ExecutorError {
|
||||||
fn from(_value: russh::Error) -> Self {
|
fn from(_value: russh::Error) -> Self {
|
||||||
todo!()
|
// TODO handle various russh errors properly
|
||||||
|
ExecutorError::NetworkError("Russh client error".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
use harmony::{
|
|
||||||
domain::{
|
|
||||||
inventory::{Inventory, InventoryFilter},
|
|
||||||
maestro::Maestro,
|
|
||||||
},
|
|
||||||
modules::opnsense_dhcp::OPNSenseDhcpScore,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn main() {
|
|
||||||
env_logger::init();
|
|
||||||
|
|
||||||
let maestro = Maestro::new(get_inventory());
|
|
||||||
let score = OPNSenseDhcpScore::new(InventoryFilter::new(vec![]));
|
|
||||||
maestro.interpret(score);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_inventory() -> Inventory {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
@ -1,8 +1,9 @@
|
|||||||
|
use async_trait::async_trait;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
use crate::{domain::{
|
use crate::{domain::{
|
||||||
data::{Id, Version}, hardware::NetworkInterface, interpret::{InterpretError, InterpretStatus, Outcome}, inventory::Inventory, topology::IpAddress
|
data::{Id, Version}, executors::SshClient, hardware::NetworkInterface, interpret::{InterpretError, InterpretStatus, Outcome}, inventory::Inventory, topology::IpAddress
|
||||||
}, infra::executors::russh::RusshClient};
|
}, infra::executors::russh::RusshClient};
|
||||||
|
|
||||||
use crate::domain::{
|
use crate::domain::{
|
||||||
@ -54,6 +55,7 @@ impl OPNSenseDhcpInterpret {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
impl Interpret for OPNSenseDhcpInterpret {
|
impl Interpret for OPNSenseDhcpInterpret {
|
||||||
fn get_name(&self) -> InterpretName {
|
fn get_name(&self) -> InterpretName {
|
||||||
InterpretName::OPNSenseDHCP
|
InterpretName::OPNSenseDHCP
|
||||||
@ -71,11 +73,15 @@ impl Interpret for OPNSenseDhcpInterpret {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute(&self, _inventory: &Inventory) -> Result<Outcome, InterpretError> {
|
async fn execute(&self, _inventory: &Inventory) -> Result<Outcome, InterpretError> {
|
||||||
info!("Executing {} on inventory {_inventory:?}", self.get_name());
|
info!("Executing {} on inventory {_inventory:?}", self.get_name());
|
||||||
let _ssh_client = RusshClient{};
|
let ssh_client = RusshClient{};
|
||||||
// ssh_client.test_connection("username", "password");
|
|
||||||
todo!()
|
info!("RusshClient initiated");
|
||||||
|
ssh_client.test_connection("paul", "paul").await?;
|
||||||
|
info!("Connection test complete");
|
||||||
|
|
||||||
|
Ok(Outcome::new(InterpretStatus::SUCCESS, "Connection test successful".to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user