use serde::{Deserialize, Serialize};
use crate::discovery::{InstanceEndpoint, ServiceInstance};
use crate::discovery_kube::{KubeDiscoveryConfig, KubeDiscoveryError, KubeDiscoveryResult};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct KubeEndpoint {
pub service: String,
pub id: String,
pub address: String,
pub port: u16,
pub port_name: Option<String>,
pub ready: bool,
}
pub fn map_endpoints(
config: &KubeDiscoveryConfig,
payload: &str,
) -> KubeDiscoveryResult<Vec<ServiceInstance>> {
let endpoints: Vec<KubeEndpoint> = serde_json::from_str(payload)?;
endpoints
.into_iter()
.filter(|endpoint| endpoint.ready)
.filter(|endpoint| {
config
.port_name
.as_ref()
.is_none_or(|port_name| endpoint.port_name.as_ref() == Some(port_name))
})
.map(|endpoint| {
let mut instance = ServiceInstance::new(
endpoint.service,
endpoint.id,
InstanceEndpoint::new(endpoint.address, endpoint.port)
.map_err(|error| KubeDiscoveryError::Backend(error.to_string()))?,
);
for (key, value) in &config.metadata {
instance = instance.with_metadata(key, value);
}
Ok(instance)
})
.collect()
}
#[cfg(test)]
mod tests {
use crate::discovery_kube::{KubeDiscoveryConfig, map_endpoints};
#[test]
fn mapper_filters_ready_named_ports() {
let mut config = KubeDiscoveryConfig {
port_name: Some("http".to_string()),
..Default::default()
};
config
.metadata
.insert("namespace".to_string(), "default".to_string());
let instances = map_endpoints(
&config,
r#"[{"service":"api","id":"pod-a","address":"10.0.0.1","port":8080,"port_name":"http","ready":true},
{"service":"api","id":"pod-b","address":"10.0.0.2","port":9090,"port_name":"admin","ready":true}]"#,
)
.expect("instances");
assert_eq!(instances.len(), 1);
assert_eq!(instances[0].metadata["namespace"], "default");
}
}