fix: update Score trait implementation and TUI initialization

Update the `Score` trait implementations to return a `Box<dyn Interpret>` instead of concrete types or clones where necessary. Additionally, refactor the initialization and cleanup in `HarmonyTUI` to use utility functions provided by `ratatui`.
This commit is contained in:
Jean-Gabriel Gill-Couture 2025-01-25 12:36:22 -05:00
parent 4bbe8e84d8
commit 651266d71c
19 changed files with 57 additions and 62 deletions

View File

@ -92,5 +92,5 @@ async fn main() {
// maestro.interpret(dhcp_score).await.unwrap(); // maestro.interpret(dhcp_score).await.unwrap();
// maestro.interpret(load_balancer_score).await.unwrap(); // maestro.interpret(load_balancer_score).await.unwrap();
// maestro.interpret(tftp_score).await.unwrap(); // maestro.interpret(tftp_score).await.unwrap();
maestro.interpret(http_score).await.unwrap(); maestro.interpret(&http_score).await.unwrap();
} }

View File

@ -31,7 +31,7 @@ impl std::fmt::Display for InterpretName {
} }
#[async_trait] #[async_trait]
pub trait Interpret { pub trait Interpret: std::fmt::Debug {
async fn execute( async fn execute(
&self, &self,
inventory: &Inventory, inventory: &Inventory,

View File

@ -1,4 +1,5 @@
use derive_new::new; use std::sync::{Arc, RwLock};
use log::info; use log::info;
use super::{ use super::{
@ -8,20 +9,35 @@ use super::{
topology::HAClusterTopology, topology::HAClusterTopology,
}; };
#[derive(new)] type ScoreVec = Vec<Box<dyn Score>>;
pub struct Maestro { pub struct Maestro {
inventory: Inventory, inventory: Inventory,
topology: HAClusterTopology, topology: HAClusterTopology,
scores: Arc<RwLock<ScoreVec>>,
} }
impl Maestro { impl Maestro {
pub fn new(inventory: Inventory, topology: HAClusterTopology) -> Self {
Self {
inventory,
topology,
scores: Arc::new(RwLock::new(Vec::new())),
}
}
pub fn start(&mut self) { pub fn start(&mut self) {
info!("Starting Maestro"); info!("Starting Maestro");
} }
pub async fn interpret<S: Score>(&self, score: S) -> Result<Outcome, InterpretError> { pub fn register_all(&mut self, mut scores: ScoreVec) {
let mut score_mut = self.scores.write().expect("Should acquire lock");
score_mut.append(&mut scores);
}
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 = score.create_interpret();
info!("Launching interpret {interpret:?}"); info!("Launching interpret {interpret:?}");
let result = interpret.execute(&self.inventory, &self.topology).await; let result = interpret.execute(&self.inventory, &self.topology).await;
info!("Got result {result:?}"); info!("Got result {result:?}");

View File

@ -1,6 +1,5 @@
use super::interpret::Interpret; use super::interpret::Interpret;
pub trait Score: std::fmt::Debug { pub trait Score: std::fmt::Debug {
type InterpretType: Interpret + std::fmt::Debug; fn create_interpret(&self) -> Box<dyn Interpret>;
fn create_interpret(self) -> Self::InterpretType;
} }

View File

@ -33,14 +33,14 @@ impl std::fmt::Debug for dyn LoadBalancer {
f.write_fmt(format_args!("LoadBalancer {}", self.get_ip())) f.write_fmt(format_args!("LoadBalancer {}", self.get_ip()))
} }
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Clone)]
pub struct LoadBalancerService { pub struct LoadBalancerService {
pub backend_servers: Vec<BackendServer>, pub backend_servers: Vec<BackendServer>,
pub listening_port: SocketAddr, pub listening_port: SocketAddr,
pub health_check: Option<HealthCheck>, pub health_check: Option<HealthCheck>,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Clone)]
pub struct BackendServer { pub struct BackendServer {
pub address: String, pub address: String,
pub port: u16, pub port: u16,

View File

@ -21,10 +21,8 @@ pub struct DhcpScore {
} }
impl Score for DhcpScore { impl Score for DhcpScore {
type InterpretType = DhcpInterpret; fn create_interpret(&self) -> Box<dyn Interpret> {
Box::new(DhcpInterpret::new(self.clone()))
fn create_interpret(self) -> DhcpInterpret {
DhcpInterpret::new(self)
} }
} }

View File

@ -17,10 +17,8 @@ pub struct DnsScore {
} }
impl Score for DnsScore { impl Score for DnsScore {
type InterpretType = DnsInterpret; fn create_interpret(&self) -> Box<dyn Interpret> {
Box::new(DnsInterpret::new(self.clone()))
fn create_interpret(self) -> Self::InterpretType {
DnsInterpret::new(self)
} }
} }

View File

@ -15,10 +15,8 @@ pub struct HttpScore {
} }
impl Score for HttpScore { impl Score for HttpScore {
type InterpretType = HttpInterpret; fn create_interpret(&self) -> Box<dyn Interpret> {
Box::new(HttpInterpret::new(self.clone()))
fn create_interpret(self) -> Self::InterpretType {
HttpInterpret::new(self)
} }
} }

View File

@ -1,7 +1,7 @@
use k8s_openapi::api::apps::v1::Deployment; use k8s_openapi::api::apps::v1::Deployment;
use serde_json::json; use serde_json::json;
use crate::score::Score; use crate::{interpret::Interpret, score::Score};
use super::resource::{K8sResourceInterpret, K8sResourceScore}; use super::resource::{K8sResourceInterpret, K8sResourceScore};
@ -12,9 +12,7 @@ pub struct K8sDeploymentScore {
} }
impl Score for K8sDeploymentScore { impl Score for K8sDeploymentScore {
type InterpretType = K8sResourceInterpret<Deployment>; fn create_interpret(&self) -> Box<dyn Interpret> {
fn create_interpret(self) -> Self::InterpretType {
let deployment: Deployment = serde_json::from_value(json!( let deployment: Deployment = serde_json::from_value(json!(
{ {
"metadata": { "metadata": {
@ -45,8 +43,8 @@ impl Score for K8sDeploymentScore {
} }
)) ))
.unwrap(); .unwrap();
K8sResourceInterpret { Box::new(K8sResourceInterpret {
score: K8sResourceScore::single(deployment), score: K8sResourceScore::single(deployment.clone()),
} })
} }
} }

View File

@ -36,9 +36,7 @@ impl<
where where
<K as kube::Resource>::DynamicType: Default, <K as kube::Resource>::DynamicType: Default,
{ {
type InterpretType = K8sResourceInterpret<K>; fn create_interpret(&self) -> Box<dyn Interpret> {
fn create_interpret(self) -> Self::InterpretType {
todo!() todo!()
} }
} }

View File

@ -9,7 +9,7 @@ use crate::{
topology::{HAClusterTopology, LoadBalancerService}, topology::{HAClusterTopology, LoadBalancerService},
}; };
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct LoadBalancerScore { pub struct LoadBalancerScore {
pub public_services: Vec<LoadBalancerService>, pub public_services: Vec<LoadBalancerService>,
pub private_services: Vec<LoadBalancerService>, pub private_services: Vec<LoadBalancerService>,
@ -20,10 +20,8 @@ pub struct LoadBalancerScore {
} }
impl Score for LoadBalancerScore { impl Score for LoadBalancerScore {
type InterpretType = LoadBalancerInterpret; fn create_interpret(&self) -> Box<dyn Interpret> {
Box::new(LoadBalancerInterpret::new(self.clone()))
fn create_interpret(self) -> Self::InterpretType {
LoadBalancerInterpret::new(self)
} }
} }

View File

@ -1,4 +1,5 @@
use crate::{ use crate::{
interpret::Interpret,
inventory::Inventory, inventory::Inventory,
modules::dhcp::DhcpScore, modules::dhcp::DhcpScore,
score::Score, score::Score,
@ -46,9 +47,7 @@ impl OKDBootstrapDhcpScore {
} }
impl Score for OKDBootstrapDhcpScore { impl Score for OKDBootstrapDhcpScore {
type InterpretType = <DhcpScore as Score>::InterpretType; fn create_interpret(&self) -> Box<dyn Interpret> {
fn create_interpret(self) -> Self::InterpretType {
self.dhcp_score.create_interpret() self.dhcp_score.create_interpret()
} }
} }

View File

@ -1,6 +1,7 @@
use std::net::SocketAddr; use std::net::SocketAddr;
use crate::{ use crate::{
interpret::Interpret,
modules::load_balancer::LoadBalancerScore, modules::load_balancer::LoadBalancerScore,
score::Score, score::Score,
topology::{ topology::{
@ -69,9 +70,7 @@ impl OKDBootstrapLoadBalancerScore {
} }
impl Score for OKDBootstrapLoadBalancerScore { impl Score for OKDBootstrapLoadBalancerScore {
type InterpretType = <LoadBalancerScore as Score>::InterpretType; fn create_interpret(&self) -> Box<dyn Interpret> {
fn create_interpret(self) -> Self::InterpretType {
self.load_balancer_score.create_interpret() self.load_balancer_score.create_interpret()
} }
} }

View File

@ -1,4 +1,5 @@
use crate::{ use crate::{
interpret::Interpret,
inventory::Inventory, inventory::Inventory,
modules::dhcp::DhcpScore, modules::dhcp::DhcpScore,
score::Score, score::Score,
@ -38,9 +39,7 @@ impl OKDDhcpScore {
} }
impl Score for OKDDhcpScore { impl Score for OKDDhcpScore {
type InterpretType = <DhcpScore as Score>::InterpretType; fn create_interpret(&self) -> Box<dyn Interpret> {
fn create_interpret(self) -> Self::InterpretType {
self.dhcp_score.create_interpret() self.dhcp_score.create_interpret()
} }
} }

View File

@ -1,4 +1,5 @@
use crate::{ use crate::{
interpret::Interpret,
modules::dns::DnsScore, modules::dns::DnsScore,
score::Score, score::Score,
topology::{DnsRecord, DnsRecordType, HAClusterTopology}, topology::{DnsRecord, DnsRecordType, HAClusterTopology},
@ -40,9 +41,7 @@ impl OKDDnsScore {
} }
impl Score for OKDDnsScore { impl Score for OKDDnsScore {
type InterpretType = <DnsScore as Score>::InterpretType; fn create_interpret(&self) -> Box<dyn Interpret> {
fn create_interpret(self) -> Self::InterpretType {
self.dns_score.create_interpret() self.dns_score.create_interpret()
} }
} }

View File

@ -1,6 +1,7 @@
use std::net::SocketAddr; use std::net::SocketAddr;
use crate::{ use crate::{
interpret::Interpret,
modules::load_balancer::LoadBalancerScore, modules::load_balancer::LoadBalancerScore,
score::Score, score::Score,
topology::{ topology::{
@ -80,9 +81,7 @@ impl OKDLoadBalancerScore {
} }
impl Score for OKDLoadBalancerScore { impl Score for OKDLoadBalancerScore {
type InterpretType = <LoadBalancerScore as Score>::InterpretType; fn create_interpret(&self) -> Box<dyn Interpret> {
fn create_interpret(self) -> Self::InterpretType {
self.load_balancer_score.create_interpret() self.load_balancer_score.create_interpret()
} }
} }

View File

@ -16,9 +16,7 @@ impl OKDUpgradeScore {
} }
// impl Score for OKDUpgradeScore { // impl Score for OKDUpgradeScore {
// type InterpretType; // fn create_interpret(self) -> Box<dyn Interpret> {
//
// fn create_interpret(self) -> Self::InterpretType {
// // Should this be a specialized interpret for OKD upgrades or rather a set of interprets // // Should this be a specialized interpret for OKD upgrades or rather a set of interprets
// // such as : // // such as :
// // // //

View File

@ -15,10 +15,8 @@ pub struct TftpScore {
} }
impl Score for TftpScore { impl Score for TftpScore {
type InterpretType = TftpInterpret; fn create_interpret(&self) -> Box<dyn Interpret> {
Box::new(TftpInterpret::new(self.clone()))
fn create_interpret(self) -> Self::InterpretType {
TftpInterpret::new(self)
} }
} }

View File

@ -1,7 +1,7 @@
use std::io;
use crossterm::event::{self, Event}; use crossterm::event::{self, Event};
use harmony::maestro::Maestro; use harmony::maestro::Maestro;
use ratatui::{self, layout::Position, prelude::CrosstermBackend, Frame, Terminal}; use ratatui::{self, layout::Position, prelude::CrosstermBackend, Frame, Terminal};
use std::io;
pub mod tui { pub mod tui {
// Export any necessary modules or types from the internal tui module // Export any necessary modules or types from the internal tui module
@ -43,8 +43,7 @@ impl HarmonyTUI {
pub async fn init(self) -> Result<(), Box<dyn std::error::Error>> { pub async fn init(self) -> Result<(), Box<dyn std::error::Error>> {
color_eyre::install()?; color_eyre::install()?;
let backend = CrosstermBackend::new(io::stdout()); let mut terminal = ratatui::init();
let mut terminal = Terminal::new(backend)?;
loop { loop {
terminal.draw(|f| self.render(f))?; terminal.draw(|f| self.render(f))?;
@ -53,6 +52,8 @@ impl HarmonyTUI {
} }
} }
ratatui::restore();
Ok(()) Ok(())
} }