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,
}
impl From<InterpretError> for String {
fn from(e: InterpretError) -> String {
format!("InterpretError : {}", e.msg)
}
}
impl std::fmt::Display for InterpretError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.msg)

View File

@@ -34,13 +34,14 @@ use crate::{
service_monitor::ServiceMonitor,
},
},
network::TlsPassthroughScore,
prometheus::{
k8s_prometheus_alerting_score::K8sPrometheusCRDAlertingScore,
prometheus::PrometheusMonitoring, rhob_alerting_score::RHOBAlertingScore,
},
},
score::Score,
topology::ingress::Ingress,
topology::{TlsRoute, TlsRouter, ingress::Ingress},
};
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]
impl Grafana for K8sAnywhereTopology {
async fn ensure_grafana_operator(

View File

@@ -1,6 +1,7 @@
use async_trait::async_trait;
use cidr::Ipv4Cidr;
use derive_new::new;
use serde::Serialize;
use super::{IpAddress, LogicalHost};
@@ -47,8 +48,6 @@ impl Router for UnmanagedRouter {
}
}
#[derive(Clone, Debug)]
/// Desired state config for a TLS passthrough route.
/// 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
@@ -63,6 +62,7 @@ impl Router for UnmanagedRouter {
/// target_port: 5432,
/// };
/// ```
#[derive(Clone, Debug, Serialize)]
pub struct TlsRoute {
/// Public hostname clients connect to (TLS SNI, port 443 implicit).
/// 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} };
/// HAProxy frontend→backend \"postgres-upstream\".
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
/// ```
/// use harmony::modules::network::TlsPassthroughScore;
/// use harmony::topology::router::TlsRoute;
/// let score = TlsPassthroughScore {
/// route: TlsRoute {
/// backend: "postgres-cluster-rw".to_string(),
/// hostname: "postgres-rw.example.com".to_string(),
/// target_port: 5432,
/// },
/// };
/// ```
///
@@ -37,28 +40,20 @@ use crate::topology::{K8sclient, Topology};
/// to use through this high level TlsPassthroughScore.
#[derive(Debug, Clone, Serialize)]
pub struct TlsPassthroughScore {
/// Backend identifier (k8s Service, HAProxy upstream, IP/FQDN, etc.).
pub backend: String,
/// Public hostname clients connect to (TLS SNI, port 443 implicit).
pub hostname: String,
/// Backend TCP port.
pub target_port: u16,
pub route: TlsRoute,
}
impl<T: Topology + K8sclient + TlsRouter + Send + Sync> Score<T> for TlsPassthroughScore {
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
let tls_route = TlsRoute {
hostname: self.hostname.clone(),
backend: self.backend.clone(),
target_port: self.target_port,
};
Box::new(TlsPassthroughInterpret { tls_route })
Box::new(TlsPassthroughInterpret {
tls_route: self.route.clone(),
})
}
fn name(&self) -> String {
format!(
"TlsRouterScore({}:{}{})",
self.backend, self.target_port, self.hostname
self.route.backend, self.route.target_port, self.route.hostname
)
}
}