refactor: Interpret score with a provided method on Score #100

Merged
letian merged 3 commits from interpret-score into master 2025-08-09 22:56:26 +00:00
15 changed files with 83 additions and 37 deletions
Showing only changes of commit 9db475849c - Show all commits

View File

@ -13,11 +13,13 @@ pub enum HarmonyEvent {
InterpretExecutionStarted { InterpretExecutionStarted {
topology: String, topology: String,
interpret: String, interpret: String,
score: String,
message: String, message: String,
}, },
InterpretExecutionFinished { InterpretExecutionFinished {
topology: String, topology: String,
interpret: String, interpret: String,
score: String,
outcome: Result<Outcome, InterpretError>, outcome: Result<Outcome, InterpretError>,
}, },
TopologyStateChanged { TopologyStateChanged {

View File

@ -24,6 +24,14 @@ pub enum InterpretName {
TenantInterpret, TenantInterpret,
Application, Application,
ArgoCD, ArgoCD,
Alerting,
Ntfy,
HelmChart,
HelmCommand,
K8sResource,
Lamp,
ApplicationMonitoring,
K8sPrometheusCrdAlerting,
} }
impl std::fmt::Display for InterpretName { impl std::fmt::Display for InterpretName {
@ -42,6 +50,14 @@ impl std::fmt::Display for InterpretName {
InterpretName::TenantInterpret => f.write_str("Tenant"), InterpretName::TenantInterpret => f.write_str("Tenant"),
InterpretName::Application => f.write_str("Application"), InterpretName::Application => f.write_str("Application"),
InterpretName::ArgoCD => f.write_str("ArgoCD"), InterpretName::ArgoCD => f.write_str("ArgoCD"),
InterpretName::Alerting => f.write_str("Alerting"),
InterpretName::Ntfy => f.write_str("Ntfy"),
InterpretName::HelmChart => f.write_str("HelmChart"),
InterpretName::HelmCommand => f.write_str("HelmCommand"),
InterpretName::K8sResource => f.write_str("K8sResource"),
InterpretName::Lamp => f.write_str("LAMP"),
InterpretName::ApplicationMonitoring => f.write_str("ApplicationMonitoring"),
InterpretName::K8sPrometheusCrdAlerting => f.write_str("K8sPrometheusCrdAlerting"),
} }
} }
} }

View File

@ -5,6 +5,7 @@ use serde::Serialize;
use serde_value::Value; use serde_value::Value;
use super::{ use super::{
instrumentation::{self, HarmonyEvent},
interpret::{Interpret, InterpretError, Outcome}, interpret::{Interpret, InterpretError, Outcome},
inventory::Inventory, inventory::Inventory,
topology::Topology, topology::Topology,
@ -20,7 +21,25 @@ pub trait Score<T: Topology>:
topology: &T, topology: &T,
) -> Result<Outcome, InterpretError> { ) -> Result<Outcome, InterpretError> {
let interpret = self.create_interpret(); let interpret = self.create_interpret();
interpret.execute(inventory, topology).await
instrumentation::instrument(HarmonyEvent::InterpretExecutionStarted {
topology: topology.name().into(),
interpret: interpret.get_name().to_string(),
score: self.name(),
message: format!("{} running...", interpret.get_name()),
})
.unwrap();
let result = interpret.execute(inventory, topology).await;
instrumentation::instrument(HarmonyEvent::InterpretExecutionFinished {
topology: topology.name().into(),
interpret: interpret.get_name().to_string(),
score: self.name(),
outcome: result.clone(),
})
.unwrap();
result
} }
fn name(&self) -> String; fn name(&self) -> String;

View File

@ -45,7 +45,7 @@ impl<S: AlertSender + Installable<T>, T: Topology> Interpret<T> for AlertingInte
} }
fn get_name(&self) -> InterpretName { fn get_name(&self) -> InterpretName {
todo!() InterpretName::Alerting
} }
fn get_version(&self) -> Version { fn get_version(&self) -> Version {

View File

@ -240,9 +240,11 @@ impl<T: Topology + HelmCommand> Interpret<T> for HelmChartInterpret {
)), )),
} }
} }
fn get_name(&self) -> InterpretName { fn get_name(&self) -> InterpretName {
todo!() InterpretName::HelmChart
} }
fn get_version(&self) -> Version { fn get_version(&self) -> Version {
todo!() todo!()
} }

View File

@ -349,7 +349,7 @@ impl<T: Topology + K8sclient + HelmCommand> Interpret<T> for HelmChartInterpretV
} }
fn get_name(&self) -> InterpretName { fn get_name(&self) -> InterpretName {
todo!() InterpretName::HelmCommand
} }
fn get_version(&self) -> Version { fn get_version(&self) -> Version {
todo!() todo!()

View File

@ -37,7 +37,7 @@ impl<T: Topology> Score<T> for K3DInstallationScore {
} }
fn name(&self) -> String { fn name(&self) -> String {
todo!() "K3dInstallationScore".into()
} }
} }
@ -51,20 +51,14 @@ impl<T: Topology> Interpret<T> for K3dInstallationInterpret {
async fn execute( async fn execute(
&self, &self,
_inventory: &Inventory, _inventory: &Inventory,
topology: &T, _topology: &T,
) -> Result<Outcome, InterpretError> { ) -> Result<Outcome, InterpretError> {
instrumentation::instrument(HarmonyEvent::InterpretExecutionStarted {
topology: topology.name().into(),
interpret: "k3d-installation".into(),
message: "installing k3d...".into(),
})
.unwrap();
let k3d = k3d_rs::K3d::new( let k3d = k3d_rs::K3d::new(
self.score.installation_path.clone(), self.score.installation_path.clone(),
Some(self.score.cluster_name.clone()), Some(self.score.cluster_name.clone()),
); );
let outcome = match k3d.ensure_installed().await {
match k3d.ensure_installed().await {
Ok(_client) => { Ok(_client) => {
let msg = format!("k3d cluster '{}' installed ", self.score.cluster_name); let msg = format!("k3d cluster '{}' installed ", self.score.cluster_name);
debug!("{msg}"); debug!("{msg}");
@ -73,16 +67,7 @@ impl<T: Topology> Interpret<T> for K3dInstallationInterpret {
Err(msg) => Err(InterpretError::new(format!( Err(msg) => Err(InterpretError::new(format!(
"failed to ensure k3d is installed : {msg}" "failed to ensure k3d is installed : {msg}"
))), ))),
}; }
instrumentation::instrument(HarmonyEvent::InterpretExecutionFinished {
topology: topology.name().into(),
interpret: "k3d-installation".into(),
outcome: outcome.clone(),
})
.unwrap();
outcome
} }
fn get_name(&self) -> InterpretName { fn get_name(&self) -> InterpretName {
InterpretName::K3dInstallation InterpretName::K3dInstallation

View File

@ -89,7 +89,7 @@ where
)) ))
} }
fn get_name(&self) -> InterpretName { fn get_name(&self) -> InterpretName {
todo!() InterpretName::K8sResource
} }
fn get_version(&self) -> Version { fn get_version(&self) -> Version {
todo!() todo!()

View File

@ -160,7 +160,7 @@ impl<T: Topology + K8sclient + HelmCommand> Interpret<T> for LAMPInterpret {
} }
fn get_name(&self) -> InterpretName { fn get_name(&self) -> InterpretName {
todo!() InterpretName::Lamp
} }
fn get_version(&self) -> Version { fn get_version(&self) -> Version {

View File

@ -69,7 +69,7 @@ impl<T: Topology + PrometheusApplicationMonitoring<CRDPrometheus>> Interpret<T>
} }
fn get_name(&self) -> InterpretName { fn get_name(&self) -> InterpretName {
todo!() InterpretName::ApplicationMonitoring
} }
fn get_version(&self) -> Version { fn get_version(&self) -> Version {

View File

@ -28,7 +28,7 @@ impl<T: Topology + HelmCommand + K8sclient> Score<T> for NtfyScore {
} }
fn name(&self) -> String { fn name(&self) -> String {
"Ntfy".to_string() "NtfyScore".to_string()
} }
} }
@ -123,8 +123,9 @@ impl<T: Topology + HelmCommand + K8sclient> Interpret<T> for NtfyInterpret {
} }
fn get_name(&self) -> InterpretName { fn get_name(&self) -> InterpretName {
todo!() InterpretName::Ntfy
} }
fn get_version(&self) -> Version { fn get_version(&self) -> Version {
todo!() todo!()
} }

View File

@ -99,7 +99,7 @@ impl<T: Topology + K8sclient + PrometheusApplicationMonitoring<CRDPrometheus>> I
} }
fn get_name(&self) -> InterpretName { fn get_name(&self) -> InterpretName {
todo!() InterpretName::K8sPrometheusCrdAlerting
} }
fn get_version(&self) -> Version { fn get_version(&self) -> Version {
@ -118,7 +118,7 @@ impl<T: Topology + K8sclient + PrometheusApplicationMonitoring<CRDPrometheus>> I
impl K8sPrometheusCRDAlertingInterpret { impl K8sPrometheusCRDAlertingInterpret {
async fn crd_exists(&self, crd: &str) -> bool { async fn crd_exists(&self, crd: &str) -> bool {
let status = Command::new("sh") let status = Command::new("sh")
.args(["-c", "kubectl get crd -A | grep -i", crd]) .args(["-c", &format!("kubectl get crd -A | grep -i {crd}")])
.status() .status()
.map_err(|e| InterpretError::new(format!("could not connect to cluster: {}", e))) .map_err(|e| InterpretError::new(format!("could not connect to cluster: {}", e)))
.unwrap(); .unwrap();

View File

@ -17,7 +17,7 @@ impl<T: Topology + TenantCredentialManager> Score<T> for TenantCredentialScore {
} }
fn name(&self) -> String { fn name(&self) -> String {
todo!() "TenantCredentialScore".into()
} }
} }

View File

@ -107,12 +107,21 @@ async fn handle_events() {
HarmonyEvent::InterpretExecutionStarted { HarmonyEvent::InterpretExecutionStarted {
topology, topology,
interpret, interpret,
score,
message, message,
} => { } => {
let section_key = if (*sections).contains_key(&topology_key(&topology)) { let section_key = if (*sections).contains_key(&topology_key(&topology)) {
topology_key(&topology) topology_key(&topology)
} else if (*sections).contains_key(&score_key(&score)) {
score_key(&interpret)
} else { } else {
interpret_key(&interpret) let key = score_key(&score);
let section = progress::new_section(format!(
"\n{} Interpreting score: {score}...",
crate::theme::EMOJI_SCORE,
));
(*sections).insert(key.clone(), section);
key
}; };
let section = (*sections).get(&section_key).unwrap(); let section = (*sections).get(&section_key).unwrap();
let progress_bar = progress::add_spinner(section, message); let progress_bar = progress::add_spinner(section, message);
@ -122,13 +131,14 @@ async fn handle_events() {
HarmonyEvent::InterpretExecutionFinished { HarmonyEvent::InterpretExecutionFinished {
topology, topology,
interpret, interpret,
score,
outcome, outcome,
} => { } => {
let has_topology = (*sections).contains_key(&topology_key(&topology)); let has_topology = (*sections).contains_key(&topology_key(&topology));
let section_key = if has_topology { let section_key = if has_topology {
topology_key(&topology) topology_key(&topology)
} else { } else {
interpret_key(&interpret) score_key(&score)
}; };
let section = (*sections).get(&section_key).unwrap(); let section = (*sections).get(&section_key).unwrap();
@ -138,9 +148,15 @@ async fn handle_events() {
let _ = section.clear(); let _ = section.clear();
match outcome { match outcome {
Ok(outcome) => { Ok(outcome) => match outcome.status {
progress::success(section, progress_bar, outcome.message); harmony::interpret::InterpretStatus::SUCCESS => {
} progress::success(section, progress_bar, outcome.message)
}
harmony::interpret::InterpretStatus::NOOP => {
progress::skip(section, progress_bar, outcome.message)
}
_ => progress::error(section, progress_bar, outcome.message),
},
Err(err) => { Err(err) => {
progress::error(section, progress_bar, err.to_string()); progress::error(section, progress_bar, err.to_string());
} }
@ -162,6 +178,10 @@ fn topology_key(topology: &str) -> String {
format!("topology-{topology}") format!("topology-{topology}")
} }
fn score_key(score: &str) -> String {
format!("score-{score}")
}
fn interpret_key(interpret: &str) -> String { fn interpret_key(interpret: &str) -> String {
format!("interpret-{interpret}") format!("interpret-{interpret}")
} }

View File

@ -8,6 +8,7 @@ pub static EMOJI_SKIP: Emoji<'_, '_> = Emoji("⏭️", "");
pub static EMOJI_ERROR: Emoji<'_, '_> = Emoji("⚠️", ""); pub static EMOJI_ERROR: Emoji<'_, '_> = Emoji("⚠️", "");
pub static EMOJI_DEPLOY: Emoji<'_, '_> = Emoji("🚀", ""); pub static EMOJI_DEPLOY: Emoji<'_, '_> = Emoji("🚀", "");
pub static EMOJI_TOPOLOGY: Emoji<'_, '_> = Emoji("📦", ""); pub static EMOJI_TOPOLOGY: Emoji<'_, '_> = Emoji("📦", "");
pub static EMOJI_SCORE: Emoji<'_, '_> = Emoji("🎶", "");
lazy_static! { lazy_static! {
pub static ref SPINNER_STYLE: ProgressStyle = ProgressStyle::default_spinner() pub static ref SPINNER_STYLE: ProgressStyle = ProgressStyle::default_spinner()