use std::time::Duration; use awc::Client; use crate::target::ScrapeTarget; pub async fn k8s_pod_discovery() -> Option> { let pod_namespace = std::env::var("POD_NAMESPACE").ok()?; let token_path = "/var/run/secrets/kubernetes.io/serviceaccount/token"; let token = tokio::fs::read_to_string(token_path).await.ok()?; let client = Client::builder() .timeout(Duration::from_secs(5)) .add_default_header(( awc::http::header::AUTHORIZATION.as_str(), format!("Bearer {}", token), )) .finish(); let api_url = format!( "https://kubernetes.default.svc/api/v1/namespaces/{}/pods", pod_namespace ); let mut response = client.get(api_url).send().await.ok()?; let body_bytes = response.body().await.ok()?; let pod_list: serde_json::Value = serde_json::from_slice(&body_bytes).ok()?; let targets: Vec = pod_list["items"] .as_array()? .iter() .filter_map(|pod| { let name = pod["metadata"]["name"].as_str()?.to_string(); let phase = pod["status"]["phase"].as_str()?; if phase != "Running" { return None; } let pod_ip = pod["status"]["podIP"].as_str()?; let annotations = pod["metadata"]["annotations"].as_object()?; let port: u16 = annotations .get("metrics.port") .and_then(|v| v.as_str()) .and_then(|s| s.parse().ok()) .unwrap_or(8080); let path = annotations .get("metrics.path") .and_then(|v| v.as_str()) .unwrap_or("/metrics"); let labels = pod["metadata"]["labels"] .as_object() .map(|m| { m.iter() .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string()))) .collect() }) .unwrap_or_default(); Some(ScrapeTarget { name, addr: format!("{}:{}", pod_ip, port), metrics_path: path.to_string(), labels, }) }) .collect(); Some(targets) }