71 lines
2.2 KiB
Rust
71 lines
2.2 KiB
Rust
use std::time::Duration;
|
|
|
|
use awc::Client;
|
|
|
|
use crate::target::ScrapeTarget;
|
|
|
|
pub async fn k8s_pod_discovery() -> Option<Vec<ScrapeTarget>> {
|
|
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<ScrapeTarget> = 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)
|
|
}
|