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]]
|
||||
name = "fqm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"harmony",
|
||||
"log",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
|
@ -15,3 +15,4 @@ log = "0.4.22"
|
||||
env_logger = "0.11.5"
|
||||
derive-new = "0.7.0"
|
||||
async-trait = "0.1.82"
|
||||
tokio = { version = "1.40.0", features = ["io-std"] }
|
||||
|
@ -4,3 +4,8 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
harmony = { path = "../harmony" }
|
||||
log = { workspace = true }
|
||||
env_logger = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
use crate::domain::{
|
||||
hardware::{Location, Host, HostCategory},
|
||||
use harmony::domain::{
|
||||
hardware::{Host, HostCategory, Location, NetworkInterface},
|
||||
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 {
|
||||
location: Location::new(
|
||||
"1134 Grande Allée Ouest 1er étage, Québec, Qc".into(),
|
||||
@ -11,8 +13,8 @@ pub fn get_fqm_inventory() -> Inventory {
|
||||
),
|
||||
host: vec![Host {
|
||||
category: HostCategory::Server,
|
||||
network: vec![],
|
||||
storage: vec![],
|
||||
network,
|
||||
storage,
|
||||
labels: vec![],
|
||||
}],
|
||||
switch: vec![],
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub mod inventory;
|
||||
pub fn add(left: usize, right: usize) -> usize {
|
||||
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"
|
||||
serde = { version = "1.0.209", features = ["derive"] }
|
||||
serde_json = "1.0.127"
|
||||
tokio = { version = "1.40.0", features = ["io-std"] }
|
||||
tokio = { workspace = true }
|
||||
derive-new = { workspace = true }
|
||||
log = { workspace = true }
|
||||
env_logger = { workspace = true }
|
||||
|
@ -29,5 +29,5 @@ impl std::error::Error for ExecutorError {}
|
||||
|
||||
#[async_trait]
|
||||
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,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, new)]
|
||||
pub struct NetworkInterface {
|
||||
speed: u64,
|
||||
mac_address: MacAddress,
|
||||
plugged_in: bool,
|
||||
}
|
||||
type MacAddress = String;
|
||||
#[derive(Debug)]
|
||||
|
||||
#[derive(Debug, new)]
|
||||
pub enum StorageConnectionType {
|
||||
Sata3g,
|
||||
Sata6g,
|
||||
@ -56,7 +57,10 @@ pub struct Switch {
|
||||
#[derive(Debug)]
|
||||
pub struct Firewall {}
|
||||
#[derive(Debug)]
|
||||
pub struct Label;
|
||||
pub struct Label {
|
||||
name: String,
|
||||
value: String,
|
||||
}
|
||||
pub type Address = String;
|
||||
|
||||
#[derive(new, Debug)]
|
||||
|
@ -1,7 +1,10 @@
|
||||
use std::error::Error;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use derive_new::new;
|
||||
|
||||
use super::{
|
||||
data::{Id, Version},
|
||||
inventory::Inventory,
|
||||
score::Score,
|
||||
data::{Id, Version}, executors::ExecutorError, inventory::Inventory, score::Score
|
||||
};
|
||||
|
||||
pub enum InterpretName {
|
||||
@ -16,19 +19,25 @@ impl std::fmt::Display for InterpretName {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
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_version(&self) -> Version;
|
||||
fn get_status(&self) -> InterpretStatus;
|
||||
fn get_children(&self) -> Vec<Id>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, new)]
|
||||
pub struct Outcome {
|
||||
status: InterpretStatus,
|
||||
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)]
|
||||
pub enum InterpretStatus {
|
||||
@ -39,7 +48,34 @@ pub enum InterpretStatus {
|
||||
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)]
|
||||
pub struct InterpretError {
|
||||
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 log::info;
|
||||
|
||||
use super::{interpret::Interpret, inventory::Inventory, score::Score};
|
||||
use super::{interpret::{Interpret, InterpretError, Outcome}, inventory::Inventory, score::Score};
|
||||
|
||||
#[derive(new)]
|
||||
pub struct Maestro {
|
||||
@ -28,11 +28,12 @@ impl Maestro {
|
||||
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:?}");
|
||||
let interpret: S::InterpretType = score.create_interpret();
|
||||
info!("Launching interpret {interpret:?}");
|
||||
let result = interpret.execute(&self.inventory);
|
||||
let result = interpret.execute(&self.inventory).await;
|
||||
info!("Got result {result:?}");
|
||||
result
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
use async_trait::async_trait;
|
||||
|
||||
use log::info;
|
||||
use russh::{client, keys::key};
|
||||
|
||||
use crate::domain::executors::{ExecutorError, SshClient};
|
||||
@ -9,11 +10,14 @@ pub struct RusshClient;
|
||||
|
||||
#[async_trait]
|
||||
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 c = Client{};
|
||||
let _client = client::connect(Arc::new(config), ("192.168.12.1", 22), c).await?;
|
||||
Ok(())
|
||||
let mut client = client::connect(Arc::new(config), ("192.168.1.1", 22), c).await?;
|
||||
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 {
|
||||
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 log::info;
|
||||
|
||||
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};
|
||||
|
||||
use crate::domain::{
|
||||
@ -54,6 +55,7 @@ impl OPNSenseDhcpInterpret {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Interpret for OPNSenseDhcpInterpret {
|
||||
fn get_name(&self) -> InterpretName {
|
||||
InterpretName::OPNSenseDHCP
|
||||
@ -71,11 +73,15 @@ impl Interpret for OPNSenseDhcpInterpret {
|
||||
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());
|
||||
let _ssh_client = RusshClient{};
|
||||
// ssh_client.test_connection("username", "password");
|
||||
todo!()
|
||||
let ssh_client = RusshClient{};
|
||||
|
||||
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