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(load_balancer_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]
pub trait Interpret {
pub trait Interpret: std::fmt::Debug {
async fn execute(
&self,
inventory: &Inventory,

View File

@ -1,4 +1,5 @@
use derive_new::new;
use std::sync::{Arc, RwLock};
use log::info;
use super::{
@ -8,20 +9,35 @@ use super::{
topology::HAClusterTopology,
};
#[derive(new)]
type ScoreVec = Vec<Box<dyn Score>>;
pub struct Maestro {
inventory: Inventory,
topology: HAClusterTopology,
scores: Arc<RwLock<ScoreVec>>,
}
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) {
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:?}");
let interpret: S::InterpretType = score.create_interpret();
let interpret = score.create_interpret();
info!("Launching interpret {interpret:?}");
let result = interpret.execute(&self.inventory, &self.topology).await;
info!("Got result {result:?}");

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
use std::io;
use crossterm::event::{self, Event};
use harmony::maestro::Maestro;
use ratatui::{self, layout::Position, prelude::CrosstermBackend, Frame, Terminal};
use std::io;
pub mod tui {
// 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>> {
color_eyre::install()?;
let backend = CrosstermBackend::new(io::stdout());
let mut terminal = Terminal::new(backend)?;
let mut terminal = ratatui::init();
loop {
terminal.draw(|f| self.render(f))?;
@ -53,6 +52,8 @@ impl HarmonyTUI {
}
}
ratatui::restore();
Ok(())
}