use super::super::crd::CustomMetric;
use kube::api::ListParams;
use tracing::{debug, warn};
pub struct MetricsClient {
#[allow(dead_code)]
client: kube::Client,
#[allow(dead_code)]
namespace: String,
}
impl MetricsClient {
pub fn new(client: kube::Client, namespace: &str) -> Self {
Self {
client,
namespace: namespace.to_string(),
}
}
pub async fn collect_pod_metrics(
&self,
label_selector: &str,
) -> Result<PodMetricsSummary, Error> {
let _params: _ = ListParams::default().labels(label_selector);
debug!("Collecting pod metrics with selector: {}", label_selector);
Ok(PodMetricsSummary {
total_pods: 0,
total_cpu_millicores: 0.0,
total_memory_bytes: 0.0,
total_cpu_request: 0.0,
total_memory_request: 0.0,
})
}
pub async fn collect_custom_metrics(
&self,
metrics: &[CustomMetric],
) -> Result<HashMap<String, f64>, Error> {
let mut result = HashMap::new();
for metric in metrics {
debug!("Collecting custom metric: {}", metric.name);
let value: _ = match metric.metric_type.as_str() {
"Pod" => self.collect_pod_metric(metric).await?,
"Resource" => self.collect_resource_metric(metric).await?,
_ => {
warn!("Unsupported metric type: {}", metric.metric_type);
continue;
}
};
result.insert(metric.name.clone(), value);
}
Ok(result)
}
async fn collect_pod_metric(&self, _metric: &CustomMetric) -> Result<f64, Error> {
Ok(0.0)
}
async fn collect_resource_metric(&self, _metric: &CustomMetric) -> Result<f64, Error> {
Ok(0.0)
}
}
#[derive(Debug, Clone)]
pub struct PodMetricsSummary {
pub total_pods: u32,
pub total_cpu_millicores: f64,
pub total_memory_bytes: f64,
pub total_cpu_request: f64,
pub total_memory_request: f64,
}
impl PodMetricsSummary {
pub fn cpu_usage_percent(&self) -> f64 {
if self.total_cpu_request > 0.0 {
(self.total_cpu_millicores / self.total_cpu_request) * 100.0
} else {
0.0
}
}
pub fn memory_usage_percent(&self) -> f64 {
if self.total_memory_request > 0.0 {
(self.total_memory_bytes / self.total_memory_request) * 100.0
} else {
0.0
}
}
pub fn cpu_cores(&self) -> f64 {
self.total_cpu_millicores / 1000.0
}
pub fn memory_gb(&self) -> f64 {
self.total_memory_bytes / (1024.0 * 1024.0 * 1024.0)
}
}
#[allow(dead_code)]
fn parse_cpu_usage(usage: &str) -> Option<f64> {
if usage.ends_with('m') {
let value: _ = usage.trim_end_matches('m');
value.parse::<f64>().ok()
} else {
let value: _ = usage.parse::<f64>().ok()?;
Some(value * 1000.0) }
}
#[allow(dead_code)]
fn parse_memory_usage(usage: &str) -> Option<f64> {
if usage.ends_with("Ki") {
let value: _ = usage.trim_end_matches("Ki").parse::<f64>().ok()?;
Some(value * 1024.0)
} else if usage.ends_with("Mi") {
let value: _ = usage.trim_end_matches("Mi").parse::<f64>().ok()?;
Some(value * 1024.0 * 1024.0)
} else if usage.ends_with("Gi") {
let value: _ = usage.trim_end_matches("Gi").parse::<f64>().ok()?;
Some(value * 1024.0 * 1024.0 * 1024.0)
} else if usage.ends_with("Ti") {
let value: _ = usage.trim_end_matches("Ti").parse::<f64>().ok()?;
Some(value * 1024.0 * 1024.0 * 1024.0 * 1024.0)
} else {
usage.parse::<f64>().ok()
}
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Kubernetes error: {0}")]
Kube(#[from] kube::Error),
#[error("Parse error: {0}")]
Parse(String),
#[error("Other error: {0}")]
Other(String),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_cpu_usage() {
assert_eq!(parse_cpu_usage("100m"), Some(100.0));
assert_eq!(parse_cpu_usage("1"), Some(1000.0));
assert_eq!(parse_cpu_usage("0.5"), Some(500.0));
}
#[test]
fn test_parse_memory_usage() {
assert_eq!(parse_memory_usage("1024Ki"), Some(1024.0 * 1024.0));
assert_eq!(parse_memory_usage("100Mi"), Some(100.0 * 1024.0 * 1024.0));
assert_eq!(parse_memory_usage("1Gi"), Some(1024.0 * 1024.0 * 1024.0));
}
#[test]
fn test_pod_metrics_summary() {
let summary: _ = PodMetricsSummary {
total_pods: 5,
total_cpu_millicores: 500.0,
total_memory_bytes: 1024.0 * 1024.0 * 1024.0, total_cpu_request: 1000.0,
total_memory_request: 2.0 * 1024.0 * 1024.0 * 1024.0, };
assert_eq!(summary.total_pods, 5);
assert_eq!(summary.cpu_usage_percent(), 50.0); assert_eq!(summary.memory_usage_percent(), 50.0); assert_eq!(summary.cpu_cores(), 0.5); assert_eq!(summary.memory_gb(), 1.0);
}
}
use std::collections::{BTreeMap, HashMap};