feat(topology): generalize Score and Interpret implementations with topology traits

Refactor various `Score` and `Interpret` implementations to utilize generic `Topology` traits, removing hardcoded dependencies on `HAClusterTopology`. This enhancement allows for more flexible and extensible code, accommodating different types of network topologies.
This commit is contained in:
Jean-Gabriel Gill-Couture 2025-03-26 23:10:51 -04:00
parent d7897f29c4
commit fda007f014
22 changed files with 148 additions and 217 deletions

View File

@ -7,7 +7,7 @@ use super::{
data::{Id, Version},
executors::ExecutorError,
inventory::Inventory,
topology::HAClusterTopology,
topology::Topology,
};
pub enum InterpretName {
@ -37,12 +37,9 @@ impl std::fmt::Display for InterpretName {
}
#[async_trait]
pub trait Interpret: std::fmt::Debug + Send {
async fn execute(
&self,
inventory: &Inventory,
topology: &HAClusterTopology,
) -> Result<Outcome, InterpretError>;
pub trait Interpret<T: Topology>: std::fmt::Debug + Send {
async fn execute(&self, inventory: &Inventory, topology: &T)
-> Result<Outcome, InterpretError>;
fn get_name(&self) -> InterpretName;
fn get_version(&self) -> Version;
fn get_status(&self) -> InterpretStatus;

View File

@ -6,19 +6,19 @@ use super::{
interpret::{InterpretError, Outcome},
inventory::Inventory,
score::Score,
topology::HAClusterTopology,
topology::Topology,
};
type ScoreVec = Vec<Box<dyn Score>>;
type ScoreVec<T: Topology> = Vec<Box<dyn Score<T>>>;
pub struct Maestro {
pub struct Maestro<T: Topology> {
inventory: Inventory,
topology: HAClusterTopology,
scores: Arc<RwLock<ScoreVec>>,
topology: T,
scores: Arc<RwLock<ScoreVec<T>>>,
}
impl Maestro {
pub fn new(inventory: Inventory, topology: HAClusterTopology) -> Self {
impl<T: Topology> Maestro<T> {
pub fn new(inventory: Inventory, topology: T) -> Self {
Self {
inventory,
topology,
@ -51,12 +51,15 @@ impl Maestro {
info!("Starting Maestro");
}
pub fn register_all(&mut self, mut scores: ScoreVec) {
pub fn register_all(&mut self, mut scores: ScoreVec<T>) {
let mut score_mut = self.scores.write().expect("Should acquire lock");
score_mut.append(&mut scores);
}
pub async fn interpret(&self, score: Box<dyn Score>) -> Result<Outcome, InterpretError> {
pub async fn interpret<S>(&self, score: S) -> Result<Outcome, InterpretError>
where
S: Score<T>,
{
info!("Running score {score:?}");
let interpret = score.create_interpret();
info!("Launching interpret {interpret:?}");
@ -65,7 +68,7 @@ impl Maestro {
result
}
pub fn scores(&self) -> Arc<RwLock<ScoreVec>> {
pub fn scores(&self) -> Arc<RwLock<ScoreVec<T>>> {
self.scores.clone()
}
}

View File

@ -1,7 +1,6 @@
use super::interpret::Interpret;
use super::{interpret::Interpret, topology::Topology};
pub trait Score: std::fmt::Debug + Send + Sync {
fn create_interpret(&self) -> Box<dyn Interpret>;
pub trait Score<T: Topology>: std::fmt::Debug + Send + Sync {
fn create_interpret(&self) -> Box<dyn Interpret<T>>;
fn name(&self) -> String;
fn clone_box(&self) -> Box<dyn Score>;
}

View File

@ -15,9 +15,11 @@ use super::IpAddress;
use super::LoadBalancer;
use super::LoadBalancerService;
use super::LogicalHost;
use super::OcK8sclient;
use super::Router;
use super::TftpServer;
use super::Topology;
use super::Url;
use super::openshift::OpenshiftClient;
use std::sync::Arc;
@ -38,11 +40,20 @@ pub struct HAClusterTopology {
pub switch: Vec<LogicalHost>,
}
impl HAClusterTopology {
pub async fn oc_client(&self) -> Result<Arc<OpenshiftClient>, kube::Error> {
impl Topology for HAClusterTopology {
fn name(&self) -> &str {
todo!()
}
}
#[async_trait]
impl OcK8sclient for HAClusterTopology {
async fn oc_client(&self) -> Result<Arc<OpenshiftClient>, kube::Error> {
Ok(Arc::new(OpenshiftClient::try_default().await?))
}
}
impl HAClusterTopology {
pub fn autoload() -> Self {
let dummy_infra = Arc::new(DummyInfra {});
let dummy_host = LogicalHost {
@ -67,6 +78,7 @@ impl HAClusterTopology {
}
}
#[derive(Debug)]
struct DummyInfra;
const UNIMPLEMENTED_DUMMY_INFRA: &str = "This is a dummy infrastructure, no operation is supported";

View File

@ -16,6 +16,12 @@ pub use tftp::*;
use std::net::IpAddr;
pub trait Topology {
fn name(&self) -> &str;
}
pub trait Capability {}
pub type IpAddress = IpAddr;
#[derive(Debug, Clone)]

View File

@ -1,11 +1,11 @@
use std::{net::Ipv4Addr, str::FromStr};
use std::{net::Ipv4Addr, str::FromStr, sync::Arc};
use async_trait::async_trait;
use harmony_types::net::MacAddress;
use crate::executors::ExecutorError;
use super::{IpAddress, LogicalHost};
use super::{openshift::OpenshiftClient, IpAddress, LogicalHost};
#[derive(Debug)]
pub struct DHCPStaticEntry {
@ -40,9 +40,14 @@ impl std::fmt::Debug for dyn Firewall {
pub struct NetworkDomain {
pub name: String,
}
#[async_trait]
pub trait OcK8sclient: Send + Sync + std::fmt::Debug {
async fn oc_client(&self) -> Result<Arc<OpenshiftClient>, kube::Error>;
}
#[async_trait]
pub trait DhcpServer: Send + Sync {
pub trait DhcpServer: Send + Sync + std::fmt::Debug {
async fn add_static_mapping(&self, entry: &DHCPStaticEntry) -> Result<(), ExecutorError>;
async fn remove_static_mapping(&self, mac: &MacAddress) -> Result<(), ExecutorError>;
async fn list_static_mappings(&self) -> Vec<(MacAddress, IpAddress)>;
@ -53,12 +58,6 @@ pub trait DhcpServer: Send + Sync {
async fn commit_config(&self) -> Result<(), ExecutorError>;
}
impl std::fmt::Debug for dyn DhcpServer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("DhcpServer {}", self.get_ip()))
}
}
#[async_trait]
pub trait DnsServer: Send + Sync {
async fn register_dhcp_leases(&self, register: bool) -> Result<(), ExecutorError>;

View File

@ -8,7 +8,7 @@ use crate::{
domain::{data::Version, interpret::InterpretStatus},
interpret::{Interpret, InterpretError, InterpretName, Outcome},
inventory::Inventory,
topology::{DHCPStaticEntry, HAClusterTopology, HostBinding, IpAddress},
topology::{DHCPStaticEntry, DhcpServer, HAClusterTopology, HostBinding, IpAddress, Topology},
};
use crate::domain::score::Score;
@ -20,18 +20,14 @@ pub struct DhcpScore {
pub boot_filename: Option<String>,
}
impl Score for DhcpScore {
fn create_interpret(&self) -> Box<dyn Interpret> {
impl<T: Topology + DhcpServer> Score<T> for DhcpScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
Box::new(DhcpInterpret::new(self.clone()))
}
fn name(&self) -> String {
"DhcpScore".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}
// https://docs.opnsense.org/manual/dhcp.html#advanced-settings
@ -52,10 +48,10 @@ impl DhcpInterpret {
status: InterpretStatus::QUEUED,
}
}
async fn add_static_entries(
async fn add_static_entries<D: DhcpServer>(
&self,
_inventory: &Inventory,
topology: &HAClusterTopology,
dhcp_server: &D,
) -> Result<Outcome, InterpretError> {
let dhcp_entries: Vec<DHCPStaticEntry> = self
.score
@ -78,7 +74,6 @@ impl DhcpInterpret {
.collect();
info!("DHCPStaticEntry : {:?}", dhcp_entries);
let dhcp_server = Arc::new(topology.dhcp_server.clone());
info!("DHCP server : {:?}", dhcp_server);
let number_new_entries = dhcp_entries.len();
@ -96,14 +91,13 @@ impl DhcpInterpret {
))
}
async fn set_pxe_options(
async fn set_pxe_options<D: DhcpServer>(
&self,
_inventory: &Inventory,
topology: &HAClusterTopology,
dhcp_server: &D,
) -> Result<Outcome, InterpretError> {
let next_server_outcome = match self.score.next_server {
Some(next_server) => {
let dhcp_server = Arc::new(topology.dhcp_server.clone());
dhcp_server.set_next_server(next_server).await?;
Outcome::new(
InterpretStatus::SUCCESS,
@ -115,7 +109,6 @@ impl DhcpInterpret {
let boot_filename_outcome = match &self.score.boot_filename {
Some(boot_filename) => {
let dhcp_server = Arc::new(topology.dhcp_server.clone());
dhcp_server.set_boot_filename(&boot_filename).await?;
Outcome::new(
InterpretStatus::SUCCESS,
@ -142,7 +135,7 @@ impl DhcpInterpret {
}
#[async_trait]
impl Interpret for DhcpInterpret {
impl<T: Topology + DhcpServer> Interpret<T> for DhcpInterpret {
fn get_name(&self) -> InterpretName {
InterpretName::OPNSenseDHCP
}
@ -162,15 +155,15 @@ impl Interpret for DhcpInterpret {
async fn execute(
&self,
inventory: &Inventory,
topology: &HAClusterTopology,
topology: &T,
) -> Result<Outcome, InterpretError> {
info!("Executing {} on inventory {inventory:?}", self.get_name());
info!("Executing DhcpInterpret on inventory {inventory:?}");
self.set_pxe_options(inventory, topology).await?;
self.add_static_entries(inventory, topology).await?;
topology.dhcp_server.commit_config().await?;
topology.commit_config().await?;
Ok(Outcome::new(
InterpretStatus::SUCCESS,

View File

@ -7,7 +7,7 @@ use crate::{
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
inventory::Inventory,
score::Score,
topology::{DnsRecord, HAClusterTopology},
topology::{DnsRecord, DnsServer, HAClusterTopology, Topology},
};
#[derive(Debug, new, Clone)]
@ -16,18 +16,14 @@ pub struct DnsScore {
register_dhcp_leases: Option<bool>,
}
impl Score for DnsScore {
fn create_interpret(&self) -> Box<dyn Interpret> {
impl<T: Topology + DnsServer> Score<T> for DnsScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
Box::new(DnsInterpret::new(self.clone()))
}
fn name(&self) -> String {
"DnsScore".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}
// https://docs.opnsense.org/manual/dhcp.html#advanced-settings
@ -48,12 +44,11 @@ impl DnsInterpret {
status: InterpretStatus::QUEUED,
}
}
async fn serve_dhcp_entries(
async fn serve_dhcp_entries<T: DnsServer>(
&self,
_inventory: &Inventory,
topology: &HAClusterTopology,
dns: &T,
) -> Result<Outcome, InterpretError> {
let dns = topology.dns_server.clone();
if let Some(register) = self.score.register_dhcp_leases {
dns.register_dhcp_leases(register).await?;
}
@ -64,15 +59,12 @@ impl DnsInterpret {
))
}
async fn ensure_hosts_registered(
async fn ensure_hosts_registered<D: DnsServer>(
&self,
topology: &HAClusterTopology,
dns_server: &D,
) -> Result<Outcome, InterpretError> {
let entries = &self.score.dns_entries;
topology
.dns_server
.ensure_hosts_registered(entries.clone())
.await?;
dns_server.ensure_hosts_registered(entries.clone()).await?;
Ok(Outcome::new(
InterpretStatus::SUCCESS,
@ -85,7 +77,7 @@ impl DnsInterpret {
}
#[async_trait]
impl Interpret for DnsInterpret {
impl<T: Topology + DnsServer> Interpret<T> for DnsInterpret {
fn get_name(&self) -> InterpretName {
InterpretName::OPNSenseDns
}
@ -105,14 +97,14 @@ impl Interpret for DnsInterpret {
async fn execute(
&self,
inventory: &Inventory,
topology: &HAClusterTopology,
topology: &T,
) -> Result<Outcome, InterpretError> {
info!("Executing {} on inventory {inventory:?}", self.get_name());
info!("Executing {} on inventory {inventory:?}", <DnsInterpret as Interpret<T>>::get_name(self));
self.serve_dhcp_entries(inventory, topology).await?;
self.ensure_hosts_registered(&topology).await?;
self.ensure_hosts_registered(topology).await?;
topology.dns_server.commit_config().await?;
topology.commit_config().await?;
Ok(Outcome::new(
InterpretStatus::SUCCESS,

View File

@ -5,7 +5,7 @@ use crate::{
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
inventory::Inventory,
score::Score,
topology::HAClusterTopology,
topology::{HAClusterTopology, Topology},
};
/// Score that always errors. This is only useful for development/testing purposes. It does nothing
@ -13,8 +13,8 @@ use crate::{
#[derive(Debug, Clone)]
pub struct ErrorScore;
impl Score for ErrorScore {
fn create_interpret(&self) -> Box<dyn crate::interpret::Interpret> {
impl<T: Topology> Score<T> for ErrorScore {
fn create_interpret(&self) -> Box<dyn crate::interpret::Interpret<T>> {
Box::new(DummyInterpret {
result: Err(InterpretError::new("Error Score default error".to_string())),
status: InterpretStatus::QUEUED,
@ -24,10 +24,6 @@ impl Score for ErrorScore {
fn name(&self) -> String {
"ErrorScore".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}
/// Score that always succeeds. This is only useful for development/testing purposes. It does nothing
@ -35,8 +31,8 @@ impl Score for ErrorScore {
#[derive(Debug, Clone)]
pub struct SuccessScore;
impl Score for SuccessScore {
fn create_interpret(&self) -> Box<dyn crate::interpret::Interpret> {
impl<T: Topology> Score<T> for SuccessScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
Box::new(DummyInterpret {
result: Ok(Outcome::success("SuccessScore default success".to_string())),
status: InterpretStatus::QUEUED,
@ -46,10 +42,6 @@ impl Score for SuccessScore {
fn name(&self) -> String {
"SuccessScore".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}
/// An interpret that only returns the result it is given when built. It does nothing else. Only
@ -61,7 +53,7 @@ struct DummyInterpret {
}
#[async_trait]
impl Interpret for DummyInterpret {
impl<T: Topology> Interpret<T> for DummyInterpret {
fn get_name(&self) -> InterpretName {
InterpretName::Dummy
}
@ -81,7 +73,7 @@ impl Interpret for DummyInterpret {
async fn execute(
&self,
_inventory: &Inventory,
_topology: &HAClusterTopology,
_topology: &T,
) -> Result<Outcome, InterpretError> {
self.result.clone()
}
@ -92,18 +84,14 @@ impl Interpret for DummyInterpret {
#[derive(Debug, Clone)]
pub struct PanicScore;
impl Score for PanicScore {
fn create_interpret(&self) -> Box<dyn crate::interpret::Interpret> {
impl<T: Topology> Score<T> for PanicScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
Box::new(PanicInterpret {})
}
fn name(&self) -> String {
"PanicScore".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}
/// An interpret that always panics when executed. Useful for development/testing purposes.
@ -111,7 +99,7 @@ impl Score for PanicScore {
struct PanicInterpret;
#[async_trait]
impl Interpret for PanicInterpret {
impl<T: Topology> Interpret<T> for PanicInterpret {
fn get_name(&self) -> InterpretName {
InterpretName::Panic
}
@ -131,7 +119,7 @@ impl Interpret for PanicInterpret {
async fn execute(
&self,
_inventory: &Inventory,
_topology: &HAClusterTopology,
_topology: &T,
) -> Result<Outcome, InterpretError> {
panic!("Panic interpret always panics when executed")
}

View File

@ -6,7 +6,7 @@ use crate::{
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
inventory::Inventory,
score::Score,
topology::{HAClusterTopology, Url},
topology::{HAClusterTopology, HttpServer, Topology, Url},
};
#[derive(Debug, new, Clone)]
@ -14,18 +14,14 @@ pub struct HttpScore {
files_to_serve: Url,
}
impl Score for HttpScore {
fn create_interpret(&self) -> Box<dyn Interpret> {
impl<T: Topology + HttpServer> Score<T> for HttpScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
Box::new(HttpInterpret::new(self.clone()))
}
fn name(&self) -> String {
"HttpScore".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}
#[derive(Debug, new, Clone)]
@ -34,13 +30,12 @@ pub struct HttpInterpret {
}
#[async_trait]
impl Interpret for HttpInterpret {
impl<T: Topology + HttpServer> Interpret<T> for HttpInterpret {
async fn execute(
&self,
_inventory: &Inventory,
topology: &HAClusterTopology,
http_server: &T,
) -> Result<Outcome, InterpretError> {
let http_server = &topology.http_server;
http_server.ensure_initialized().await?;
// http_server.set_ip(topology.router.get_gateway()).await?;
http_server.serve_files(&self.score.files_to_serve).await?;

View File

@ -1,7 +1,7 @@
use k8s_openapi::api::apps::v1::Deployment;
use serde_json::json;
use crate::{interpret::Interpret, score::Score};
use crate::{interpret::Interpret, score::Score, topology::{OcK8sclient, Topology}};
use super::resource::{K8sResourceInterpret, K8sResourceScore};
@ -11,8 +11,8 @@ pub struct K8sDeploymentScore {
pub image: String,
}
impl Score for K8sDeploymentScore {
fn create_interpret(&self) -> Box<dyn Interpret> {
impl <T:Topology + OcK8sclient> Score<T> for K8sDeploymentScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
let deployment: Deployment = serde_json::from_value(json!(
{
"metadata": {
@ -51,8 +51,4 @@ impl Score for K8sDeploymentScore {
fn name(&self) -> String {
"K8sDeploymentScore".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}

View File

@ -8,7 +8,7 @@ use crate::{
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
inventory::Inventory,
score::Score,
topology::HAClusterTopology,
topology::{HAClusterTopology, OcK8sclient, Topology},
};
#[derive(Debug, Clone)]
@ -34,21 +34,18 @@ impl<
+ 'static
+ Send
+ Clone,
> Score for K8sResourceScore<K>
T: Topology,
> Score<T> for K8sResourceScore<K>
where
<K as kube::Resource>::DynamicType: Default,
{
fn create_interpret(&self) -> Box<dyn Interpret> {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
todo!()
}
fn name(&self) -> String {
"K8sResourceScore".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}
#[derive(Debug)]
@ -66,14 +63,15 @@ impl<
+ Default
+ Send
+ Sync,
> Interpret for K8sResourceInterpret<K>
T: Topology + OcK8sclient,
> Interpret<T> for K8sResourceInterpret<K>
where
<K as kube::Resource>::DynamicType: Default,
{
async fn execute(
&self,
_inventory: &Inventory,
topology: &HAClusterTopology,
topology: &T,
) -> Result<Outcome, InterpretError> {
topology
.oc_client()

View File

@ -8,7 +8,7 @@ use crate::{
inventory::Inventory,
modules::k8s::deployment::K8sDeploymentScore,
score::Score,
topology::{HAClusterTopology, Url},
topology::{HAClusterTopology, OcK8sclient, Topology, Url},
};
#[derive(Debug, Clone)]
@ -34,18 +34,14 @@ impl Default for LAMPConfig {
}
}
impl Score for LAMPScore {
fn create_interpret(&self) -> Box<dyn Interpret> {
impl <T:Topology> Score<T> for LAMPScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
todo!()
}
fn name(&self) -> String {
"LampScore".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}
#[derive(Debug)]
@ -54,14 +50,14 @@ pub struct LAMPInterpret {
}
#[async_trait]
impl Interpret for LAMPInterpret {
impl <T:Topology + OcK8sclient> Interpret<T> for LAMPInterpret {
async fn execute(
&self,
inventory: &Inventory,
topology: &HAClusterTopology,
topology: &T,
) -> Result<Outcome, InterpretError> {
let deployment_score = K8sDeploymentScore {
name: self.score.name(),
name: <LAMPScore as Score<T>>::name(&self.score),
image: "local_image".to_string(),
};

View File

@ -6,7 +6,7 @@ use crate::{
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
inventory::Inventory,
score::Score,
topology::{HAClusterTopology, LoadBalancerService},
topology::{HAClusterTopology, LoadBalancer, LoadBalancerService, Topology},
};
#[derive(Debug, Clone)]
@ -19,18 +19,14 @@ pub struct LoadBalancerScore {
// uuid?
}
impl Score for LoadBalancerScore {
fn create_interpret(&self) -> Box<dyn Interpret> {
impl<T: Topology + LoadBalancer> Score<T> for LoadBalancerScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
Box::new(LoadBalancerInterpret::new(self.clone()))
}
fn name(&self) -> String {
"LoadBalancerScore".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}
#[derive(Debug)]
@ -51,37 +47,32 @@ impl LoadBalancerInterpret {
}
#[async_trait]
impl Interpret for LoadBalancerInterpret {
impl<T: Topology + LoadBalancer> Interpret<T> for LoadBalancerInterpret {
async fn execute(
&self,
_inventory: &Inventory,
topology: &HAClusterTopology,
load_balancer: &T,
) -> Result<Outcome, InterpretError> {
info!(
"Making sure Load Balancer is initialized: {:?}",
topology.load_balancer.ensure_initialized().await?
load_balancer.ensure_initialized().await?
);
for service in self.score.public_services.iter() {
info!("Ensuring service exists {service:?}");
topology
.load_balancer
.ensure_service_exists(service)
.await?;
load_balancer.ensure_service_exists(service).await?;
}
for service in self.score.private_services.iter() {
info!("Ensuring private service exists {service:?}");
topology
.load_balancer
.ensure_service_exists(service)
.await?;
load_balancer.ensure_service_exists(service).await?;
}
info!("Applying load balancer configuration");
topology.load_balancer.commit_config().await?;
load_balancer.commit_config().await?;
info!("Making a full reload and restart of haproxy");
topology.load_balancer.reload_restart().await?;
load_balancer.reload_restart().await?;
Ok(Outcome::success(format!(
"Load balancer successfully configured {} services",
self.score.public_services.len() + self.score.private_services.len()

View File

@ -3,7 +3,7 @@ use crate::{
inventory::Inventory,
modules::dhcp::DhcpScore,
score::Score,
topology::{HAClusterTopology, HostBinding},
topology::{DhcpServer, HAClusterTopology, HostBinding, Topology},
};
#[derive(Debug, Clone)]
@ -46,16 +46,12 @@ impl OKDBootstrapDhcpScore {
}
}
impl Score for OKDBootstrapDhcpScore {
fn create_interpret(&self) -> Box<dyn Interpret> {
impl<T: Topology + DhcpServer> Score<T> for OKDBootstrapDhcpScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
self.dhcp_score.create_interpret()
}
fn name(&self) -> String {
"OKDBootstrapDhcpScore".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}

View File

@ -5,8 +5,7 @@ use crate::{
modules::load_balancer::LoadBalancerScore,
score::Score,
topology::{
BackendServer, HAClusterTopology, HealthCheck, HttpMethod, HttpStatusCode,
LoadBalancerService,
BackendServer, HAClusterTopology, HealthCheck, HttpMethod, HttpStatusCode, LoadBalancer, LoadBalancerService, Topology
},
};
@ -69,16 +68,12 @@ impl OKDBootstrapLoadBalancerScore {
}
}
impl Score for OKDBootstrapLoadBalancerScore {
fn create_interpret(&self) -> Box<dyn Interpret> {
impl<T: Topology + LoadBalancer> Score<T> for OKDBootstrapLoadBalancerScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
self.load_balancer_score.create_interpret()
}
fn name(&self) -> String {
"OKDBootstrapLoadBalancerScore".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}

View File

@ -3,7 +3,7 @@ use crate::{
inventory::Inventory,
modules::dhcp::DhcpScore,
score::Score,
topology::{HAClusterTopology, HostBinding},
topology::{DhcpServer, HAClusterTopology, HostBinding, Topology},
};
#[derive(Debug, Clone)]
@ -38,16 +38,12 @@ impl OKDDhcpScore {
}
}
impl Score for OKDDhcpScore {
fn create_interpret(&self) -> Box<dyn Interpret> {
impl<T: Topology + DhcpServer> Score<T> for OKDDhcpScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
self.dhcp_score.create_interpret()
}
fn name(&self) -> String {
"OKDDhcpScore".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}

View File

@ -2,7 +2,7 @@ use crate::{
interpret::Interpret,
modules::dns::DnsScore,
score::Score,
topology::{DnsRecord, DnsRecordType, HAClusterTopology},
topology::{DnsRecord, DnsRecordType, DnsServer, HAClusterTopology, Topology},
};
#[derive(Debug, Clone)]
@ -40,16 +40,12 @@ impl OKDDnsScore {
}
}
impl Score for OKDDnsScore {
fn create_interpret(&self) -> Box<dyn Interpret> {
impl<T: Topology + DnsServer> Score<T> for OKDDnsScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
self.dns_score.create_interpret()
}
fn name(&self) -> String {
"OKDDnsScore".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}

View File

@ -5,8 +5,7 @@ use crate::{
modules::load_balancer::LoadBalancerScore,
score::Score,
topology::{
BackendServer, HAClusterTopology, HealthCheck, HttpMethod, HttpStatusCode,
LoadBalancerService,
BackendServer, HAClusterTopology, HealthCheck, HttpMethod, HttpStatusCode, LoadBalancer, LoadBalancerService, Topology
},
};
@ -80,16 +79,12 @@ impl OKDLoadBalancerScore {
}
}
impl Score for OKDLoadBalancerScore {
fn create_interpret(&self) -> Box<dyn Interpret> {
impl<T: Topology + LoadBalancer> Score<T> for OKDLoadBalancerScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
self.load_balancer_score.create_interpret()
}
fn name(&self) -> String {
"OKDLoadBalancerScore".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}

View File

@ -8,7 +8,7 @@ use crate::{
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
inventory::Inventory,
score::Score,
topology::HAClusterTopology,
topology::{HAClusterTopology, Topology},
};
#[derive(Debug, Clone)]
@ -17,8 +17,8 @@ pub struct OPNsenseShellCommandScore {
pub command: String,
}
impl Score for OPNsenseShellCommandScore {
fn create_interpret(&self) -> Box<dyn Interpret> {
impl<T: Topology> Score<T> for OPNsenseShellCommandScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
Box::new(OPNsenseShellInterpret {
status: InterpretStatus::QUEUED,
score: self.clone(),
@ -28,10 +28,6 @@ impl Score for OPNsenseShellCommandScore {
fn name(&self) -> String {
"OPNSenseShellCommandScore".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}
#[derive(Debug)]
@ -41,11 +37,11 @@ pub struct OPNsenseShellInterpret {
}
#[async_trait]
impl Interpret for OPNsenseShellInterpret {
impl <T:Topology> Interpret<T> for OPNsenseShellInterpret {
async fn execute(
&self,
_inventory: &Inventory,
_topology: &HAClusterTopology,
_topology: &T,
) -> Result<Outcome, InterpretError> {
let output = self
.score

View File

@ -5,6 +5,7 @@ use tokio::sync::RwLock;
use crate::{
interpret::{Interpret, InterpretStatus},
score::Score,
topology::Topology,
};
use super::{OPNsenseShellCommandScore, OPNsenseShellInterpret};
@ -14,8 +15,8 @@ pub struct OPNSenseLaunchUpgrade {
pub opnsense: Arc<RwLock<opnsense_config::Config>>,
}
impl Score for OPNSenseLaunchUpgrade {
fn create_interpret(&self) -> Box<dyn Interpret> {
impl<T: Topology> Score<T> for OPNSenseLaunchUpgrade {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
let score = OPNsenseShellCommandScore {
opnsense: self.opnsense.clone(),
command: "/usr/local/opnsense/scripts/firmware/update.sh".to_string(),
@ -30,8 +31,4 @@ impl Score for OPNSenseLaunchUpgrade {
fn name(&self) -> String {
"OPNSenseLaunchUpgrade".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}

View File

@ -6,7 +6,7 @@ use crate::{
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
inventory::Inventory,
score::Score,
topology::{HAClusterTopology, Url},
topology::{HAClusterTopology, Router, TftpServer, Topology, Url},
};
#[derive(Debug, new, Clone)]
@ -14,18 +14,14 @@ pub struct TftpScore {
files_to_serve: Url,
}
impl Score for TftpScore {
fn create_interpret(&self) -> Box<dyn Interpret> {
impl <T:Topology + TftpServer + Router> Score<T> for TftpScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
Box::new(TftpInterpret::new(self.clone()))
}
fn name(&self) -> String {
"TftpScore".to_string()
}
fn clone_box(&self) -> Box<dyn Score> {
Box::new(self.clone())
}
}
#[derive(Debug, new, Clone)]
@ -34,18 +30,17 @@ pub struct TftpInterpret {
}
#[async_trait]
impl Interpret for TftpInterpret {
impl <T:Topology + TftpServer + Router> Interpret<T> for TftpInterpret {
async fn execute(
&self,
_inventory: &Inventory,
topology: &HAClusterTopology,
topology: &T,
) -> Result<Outcome, InterpretError> {
let tftp_server = &topology.tftp_server;
tftp_server.ensure_initialized().await?;
tftp_server.set_ip(topology.router.get_gateway()).await?;
tftp_server.serve_files(&self.score.files_to_serve).await?;
tftp_server.commit_config().await?;
tftp_server.reload_restart().await?;
topology.ensure_initialized().await?;
topology.set_ip(topology.get_gateway()).await?;
topology.serve_files(&self.score.files_to_serve).await?;
topology.commit_config().await?;
topology.reload_restart().await?;
Ok(Outcome::success(format!(
"TFTP Server running and serving files from {}",
self.score.files_to_serve