use std::collections::BTreeMap; use kube::api::ObjectMeta; use kube::Resource; use serde::{Deserialize, Serialize}; use crate::types::chatservice::ChatService; use crate::types::webservice::WebService; #[derive(Clone, Debug, Deserialize, Serialize)] pub struct OcpRoute { pub metadata: ObjectMeta, pub spec: OcpRouteSpec, } #[derive(Clone, Debug, Deserialize, Serialize)] pub struct OcpRouteSpec { #[serde(skip_serializing_if = "Option::is_none")] pub host: Option, pub to: RouteTargetReference, #[serde(skip_serializing_if = "Option::is_none")] pub port: Option, #[serde(skip_serializing_if = "Option::is_none")] pub tls: Option, #[serde(skip_serializing_if = "Option::is_none", rename = "wildcardPolicy")] pub wildcard_policy: Option, } #[derive(Clone, Debug, Deserialize, Serialize)] pub struct RouteTargetReference { pub kind: String, pub name: String, #[serde(skip_serializing_if = "Option::is_none")] pub weight: Option, } #[derive(Clone, Debug, Deserialize, Serialize)] pub struct RoutePort { #[serde(rename = "targetPort")] pub target_port: String, } #[derive(Clone, Debug, Deserialize, Serialize)] pub struct RouteTlsConfig { pub termination: String, #[serde( skip_serializing_if = "Option::is_none", rename = "insecureEdgeTerminationPolicy" )] pub insecure_edge_termination_policy: Option, #[serde(skip_serializing_if = "Option::is_none", rename = "externalCertificate")] pub external_certificate: Option, } #[derive(Clone, Debug, Deserialize, Serialize)] pub struct ExternalCertificate { pub name: String, } fn slug_host(host: &str) -> String { host.replace('.', "-") } pub fn build_web_route(ws: &WebService) -> OcpRoute { let name = ws.metadata.name.clone().unwrap(); let ns = ws.metadata.namespace.clone().unwrap(); let oref = ws.controller_owner_ref(&()).unwrap(); let slug = slug_host(&ws.spec.host); let tls_secret = format!("{slug}-tls"); build_edge_route(&name, &ns, &ws.spec.host, &tls_secret, None, oref) } pub fn build_chat_route(cs: &ChatService) -> OcpRoute { let name = cs.metadata.name.clone().unwrap(); let ns = cs.metadata.namespace.clone().unwrap(); let oref = cs.controller_owner_ref(&()).unwrap(); let slug = slug_host(&cs.spec.host); let tls_secret = format!("{slug}-tls"); let mut annotations = BTreeMap::new(); annotations.insert( "haproxy.router.openshift.io/timeout".to_string(), format!("{}s", cs.spec.websocket_timeout), ); build_edge_route( &name, &ns, &cs.spec.host, &tls_secret, Some(annotations), oref, ) } fn build_edge_route( name: &str, ns: &str, host: &str, tls_secret: &str, annotations: Option>, oref: k8s_openapi::apimachinery::pkg::apis::meta::v1::OwnerReference, ) -> OcpRoute { OcpRoute { metadata: ObjectMeta { name: Some(name.to_string()), namespace: Some(ns.to_string()), owner_references: Some(vec![oref]), annotations: annotations.map(|a| if a.is_empty() { return a } else { a }), ..Default::default() }, spec: OcpRouteSpec { host: Some(host.to_string()), to: RouteTargetReference { kind: "Service".to_string(), name: name.to_string(), weight: Some(100), }, port: Some(RoutePort { target_port: "http".to_string(), }), tls: Some(RouteTlsConfig { termination: "edge".to_string(), insecure_edge_termination_policy: Some("Redirect".to_string()), external_certificate: Some(ExternalCertificate { name: tls_secret.to_string(), }), }), wildcard_policy: Some("None".to_string()), }, } } #[cfg(test)] mod tests { use super::*; use crate::testutil::{test_chatservice, test_webservice}; #[test] fn web_route_uses_edge_tls() { let route = build_web_route(&test_webservice()); let tls = route.spec.tls.unwrap(); assert_eq!(tls.termination, "edge"); } #[test] fn web_route_references_tls_secret() { let route = build_web_route(&test_webservice()); let tls = route.spec.tls.unwrap(); assert_eq!(tls.external_certificate.unwrap().name, "txt-irc-now-tls"); } #[test] fn web_route_has_correct_host() { let route = build_web_route(&test_webservice()); assert_eq!(route.spec.host.unwrap(), "txt.irc.now"); } #[test] fn web_route_points_at_service() { let route = build_web_route(&test_webservice()); assert_eq!(route.spec.to.kind, "Service"); assert_eq!(route.spec.to.name, "txt"); } #[test] fn web_route_targets_http_port() { let route = build_web_route(&test_webservice()); assert_eq!(route.spec.port.unwrap().target_port, "http"); } #[test] fn web_route_has_owner_reference() { let route = build_web_route(&test_webservice()); let orefs = route.metadata.owner_references.unwrap(); assert_eq!(orefs[0].name, "txt"); } #[test] fn chat_route_has_timeout_annotation() { let route = build_chat_route(&test_chatservice()); let annotations = route.metadata.annotations.unwrap(); assert_eq!( annotations["haproxy.router.openshift.io/timeout"], "600s" ); } #[test] fn chat_route_uses_edge_tls() { let route = build_chat_route(&test_chatservice()); let tls = route.spec.tls.unwrap(); assert_eq!(tls.termination, "edge"); } }