use std::collections::BTreeMap; use k8s_openapi::api::core::v1::{Service, ServicePort, ServiceSpec}; use kube::api::ObjectMeta; use kube::Resource; use crate::types::SojuBouncer; pub fn build_service(bouncer: &SojuBouncer) -> Service { let name = bouncer.metadata.name.clone().unwrap(); let ns = bouncer.metadata.namespace.clone().unwrap(); let oref = bouncer.controller_owner_ref(&()).unwrap(); let selector: BTreeMap = [("app.kubernetes.io/name".to_string(), name.clone())].into(); let mut ports: Vec = bouncer .spec .listeners .iter() .enumerate() .filter_map(|(i, l)| { l.address .rsplit(':') .next() .and_then(|p| p.parse::().ok()) .map(|port| ServicePort { name: Some(format!("listener-{i}")), port, ..Default::default() }) }) .collect(); if name != "soju-shared" { ports.push(ServicePort { name: Some("http".to_string()), port: 8081, ..Default::default() }); } Service { metadata: ObjectMeta { name: Some(name), namespace: Some(ns), owner_references: Some(vec![oref]), ..Default::default() }, spec: Some(ServiceSpec { selector: Some(selector), ports: if ports.is_empty() { None } else { Some(ports) }, ..Default::default() }), ..Default::default() } } #[cfg(test)] mod tests { use super::*; use crate::testutil::test_bouncer; #[test] fn service_named_correctly() { let svc = build_service(&test_bouncer()); assert_eq!(svc.metadata.name.unwrap(), "test-bouncer"); } #[test] fn service_has_correct_selector() { let svc = build_service(&test_bouncer()); let selector = svc.spec.unwrap().selector.unwrap(); assert_eq!(selector["app.kubernetes.io/name"], "test-bouncer"); } #[test] fn service_has_ports_for_each_listener() { let svc = build_service(&test_bouncer()); let ports = svc.spec.unwrap().ports.unwrap(); assert_eq!(ports.len(), 3); assert_eq!(ports[0].port, 6697); assert_eq!(ports[1].port, 6667); assert_eq!(ports[2].port, 8081); assert_eq!(ports[2].name.as_deref(), Some("http")); } #[test] fn shared_bouncer_has_no_http_port() { let mut b = test_bouncer(); b.metadata.name = Some("soju-shared".to_string()); let svc = build_service(&b); let ports = svc.spec.unwrap().ports.unwrap(); assert_eq!(ports.len(), 2); assert!(ports.iter().all(|p| p.name.as_deref() != Some("http"))); } #[test] fn service_with_no_listeners_shared_has_no_ports() { let mut b = test_bouncer(); b.metadata.name = Some("soju-shared".to_string()); b.spec.listeners.clear(); let svc = build_service(&b); assert!(svc.spec.unwrap().ports.is_none()); } #[test] fn service_has_owner_reference() { let svc = build_service(&test_bouncer()); let orefs = svc.metadata.owner_references.unwrap(); assert_eq!(orefs.len(), 1); assert_eq!(orefs[0].name, "test-bouncer"); } }