feat: Impl TlsRoute for K8sAnywhereTopology

This commit is contained in:
2025-12-14 22:22:09 -05:00
parent d06bd4dac6
commit e9cab92585
4 changed files with 41 additions and 36 deletions

View File

@@ -152,6 +152,12 @@ pub struct InterpretError {
msg: String, msg: String,
} }
impl From<InterpretError> for String {
fn from(e: InterpretError) -> String {
format!("InterpretError : {}", e.msg)
}
}
impl std::fmt::Display for InterpretError { impl std::fmt::Display for InterpretError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.msg) f.write_str(&self.msg)

View File

@@ -34,13 +34,14 @@ use crate::{
service_monitor::ServiceMonitor, service_monitor::ServiceMonitor,
}, },
}, },
network::TlsPassthroughScore,
prometheus::{ prometheus::{
k8s_prometheus_alerting_score::K8sPrometheusCRDAlertingScore, k8s_prometheus_alerting_score::K8sPrometheusCRDAlertingScore,
prometheus::PrometheusMonitoring, rhob_alerting_score::RHOBAlertingScore, prometheus::PrometheusMonitoring, rhob_alerting_score::RHOBAlertingScore,
}, },
}, },
score::Score, score::Score,
topology::ingress::Ingress, topology::{TlsRoute, TlsRouter, ingress::Ingress},
}; };
use super::{ use super::{
@@ -102,6 +103,29 @@ impl K8sclient for K8sAnywhereTopology {
} }
} }
#[async_trait]
impl TlsRouter for K8sAnywhereTopology {
async fn install_route(&self, route: TlsRoute) -> Result<(), String> {
if let Some(distro) = self.k8s_distribution.get() {
match distro {
KubernetesDistribution::OpenshiftFamily => {
TlsPassthroughScore { route }
.interpret(&Inventory::empty(), self)
.await?;
Ok(())
}
KubernetesDistribution::K3sFamily | KubernetesDistribution::Default => Err(
format!("Distribution not supported yet for Tlsrouter {distro:?}"),
),
}
} else {
Err(format!(
"Could not find a k8s distribution, TlsRouter in K8sAnywhereTopology requires it"
))
}
}
}
#[async_trait] #[async_trait]
impl Grafana for K8sAnywhereTopology { impl Grafana for K8sAnywhereTopology {
async fn ensure_grafana_operator( async fn ensure_grafana_operator(

View File

@@ -1,6 +1,7 @@
use async_trait::async_trait; use async_trait::async_trait;
use cidr::Ipv4Cidr; use cidr::Ipv4Cidr;
use derive_new::new; use derive_new::new;
use serde::Serialize;
use super::{IpAddress, LogicalHost}; use super::{IpAddress, LogicalHost};
@@ -47,8 +48,6 @@ impl Router for UnmanagedRouter {
} }
} }
#[derive(Clone, Debug)]
/// Desired state config for a TLS passthrough route. /// Desired state config for a TLS passthrough route.
/// Forwards external TLS (port 443) → backend service:target_port (no termination at router). /// Forwards external TLS (port 443) → backend service:target_port (no termination at router).
/// Inspired by CNPG multisite: exposes `-rw`/`-ro` services publicly via OKD Route/HAProxy/K8s /// Inspired by CNPG multisite: exposes `-rw`/`-ro` services publicly via OKD Route/HAProxy/K8s
@@ -63,6 +62,7 @@ impl Router for UnmanagedRouter {
/// target_port: 5432, /// target_port: 5432,
/// }; /// };
/// ``` /// ```
#[derive(Clone, Debug, Serialize)]
pub struct TlsRoute { pub struct TlsRoute {
/// Public hostname clients connect to (TLS SNI, port 443 implicit). /// Public hostname clients connect to (TLS SNI, port 443 implicit).
/// Router matches this for passthrough forwarding. /// Router matches this for passthrough forwarding.
@@ -95,24 +95,4 @@ pub trait TlsRouter: Send + Sync {
/// Example: OKD Route{ host, to: backend:target_port, tls: {passthrough} }; /// Example: OKD Route{ host, to: backend:target_port, tls: {passthrough} };
/// HAProxy frontend→backend \"postgres-upstream\". /// HAProxy frontend→backend \"postgres-upstream\".
async fn install_route(&self, config: TlsRoute) -> Result<(), String>; async fn install_route(&self, config: TlsRoute) -> Result<(), String>;
/// Installed route's public hostname.
fn hostname(&self) -> String;
/// Installed route's backend identifier.
fn backend(&self) -> String;
/// Installed route's backend port.
fn target_port(&self) -> u16;
}
impl std::fmt::Debug for dyn TlsRouter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!(
"TlsRouter[hostname={}, backend={}:{}]",
self.hostname(),
self.backend(),
self.target_port()
))
}
} }

View File

@@ -19,10 +19,13 @@ use crate::topology::{K8sclient, Topology};
/// # Usage /// # Usage
/// ``` /// ```
/// use harmony::modules::network::TlsPassthroughScore; /// use harmony::modules::network::TlsPassthroughScore;
/// use harmony::topology::router::TlsRoute;
/// let score = TlsPassthroughScore { /// let score = TlsPassthroughScore {
/// route: TlsRoute {
/// backend: "postgres-cluster-rw".to_string(), /// backend: "postgres-cluster-rw".to_string(),
/// hostname: "postgres-rw.example.com".to_string(), /// hostname: "postgres-rw.example.com".to_string(),
/// target_port: 5432, /// target_port: 5432,
/// },
/// }; /// };
/// ``` /// ```
/// ///
@@ -37,28 +40,20 @@ use crate::topology::{K8sclient, Topology};
/// to use through this high level TlsPassthroughScore. /// to use through this high level TlsPassthroughScore.
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct TlsPassthroughScore { pub struct TlsPassthroughScore {
/// Backend identifier (k8s Service, HAProxy upstream, IP/FQDN, etc.). pub route: TlsRoute,
pub backend: String,
/// Public hostname clients connect to (TLS SNI, port 443 implicit).
pub hostname: String,
/// Backend TCP port.
pub target_port: u16,
} }
impl<T: Topology + K8sclient + TlsRouter + Send + Sync> Score<T> for TlsPassthroughScore { impl<T: Topology + K8sclient + TlsRouter + Send + Sync> Score<T> for TlsPassthroughScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> { fn create_interpret(&self) -> Box<dyn Interpret<T>> {
let tls_route = TlsRoute { Box::new(TlsPassthroughInterpret {
hostname: self.hostname.clone(), tls_route: self.route.clone(),
backend: self.backend.clone(), })
target_port: self.target_port,
};
Box::new(TlsPassthroughInterpret { tls_route })
} }
fn name(&self) -> String { fn name(&self) -> String {
format!( format!(
"TlsRouterScore({}:{}{})", "TlsRouterScore({}:{}{})",
self.backend, self.target_port, self.hostname self.route.backend, self.route.target_port, self.route.hostname
) )
} }
} }