syncable_cli/analyzer/k8s_optimize/rules/
k8s_opt_010.rs1use super::{OptimizationRule, RuleContext, codes};
4use crate::analyzer::k8s_optimize::config::K8sOptimizeConfig;
5use crate::analyzer::k8s_optimize::parser::{parse_cpu_to_millicores, parse_memory_to_bytes};
6use crate::analyzer::k8s_optimize::types::{
7 OptimizationIssue, ResourceRecommendation, ResourceSpec, RuleCode, Severity, WorkloadType,
8};
9
10pub struct UnbalancedResourcesRule;
12
13impl OptimizationRule for UnbalancedResourcesRule {
14 fn code(&self) -> &'static str {
15 codes::UNBALANCED_RESOURCES
16 }
17
18 fn description(&self) -> &'static str {
19 "Resource allocation is unbalanced for workload type"
20 }
21
22 fn default_severity(&self) -> Severity {
23 Severity::Low
24 }
25
26 fn check(
27 &self,
28 ctx: &RuleContext,
29 config: &K8sOptimizeConfig,
30 ) -> Option<ResourceRecommendation> {
31 if !config.include_info {
33 return None;
34 }
35
36 let cpu_request = ctx.current.cpu_request.as_ref()?;
38 let memory_request = ctx.current.memory_request.as_ref()?;
39
40 let cpu_millicores = parse_cpu_to_millicores(cpu_request)?;
41 let memory_bytes = parse_memory_to_bytes(memory_request)?;
42
43 let memory_gb = memory_bytes as f64 / (1024.0 * 1024.0 * 1024.0);
45 if memory_gb < 0.1 {
46 return None; }
48
49 let ratio = cpu_millicores as f64 / memory_gb;
50
51 let (expected_min, expected_max) = match ctx.workload_type {
53 WorkloadType::Web => (200.0, 2000.0), WorkloadType::Worker => (500.0, 3000.0), WorkloadType::Database => (100.0, 1000.0), WorkloadType::Cache => (100.0, 500.0), WorkloadType::MessageBroker => (200.0, 1000.0),
58 WorkloadType::MachineLearning => (500.0, 4000.0), WorkloadType::Batch => (500.0, 4000.0), WorkloadType::General => (100.0, 2000.0), };
62
63 if ratio >= expected_min && ratio <= expected_max {
65 return None;
66 }
67
68 let defaults = ctx.workload_type.default_resources();
69 let recommended = ResourceSpec {
70 cpu_request: Some(defaults.cpu_request.to_string()),
71 cpu_limit: Some(defaults.cpu_limit.to_string()),
72 memory_request: Some(defaults.memory_request.to_string()),
73 memory_limit: Some(defaults.memory_limit.to_string()),
74 };
75
76 let direction = if ratio < expected_min {
77 "CPU-heavy for memory"
78 } else {
79 "Memory-heavy for CPU"
80 };
81
82 Some(ResourceRecommendation {
83 resource_kind: ctx.resource_kind.clone(),
84 resource_name: ctx.resource_name.clone(),
85 namespace: ctx.namespace.clone(),
86 container: ctx.container_name.clone(),
87 file_path: ctx.file_path.clone(),
88 line: ctx.line,
89 issue: OptimizationIssue::UnbalancedResources,
90 severity: self.default_severity(),
91 message: format!(
92 "Resource allocation is unbalanced for {} workload: {} (ratio: {:.0} millicores/GB, expected: {:.0}-{:.0}).",
93 ctx.workload_type, direction, ratio, expected_min, expected_max
94 ),
95 workload_type: ctx.workload_type,
96 current: ctx.current.clone(),
97 actual_usage: None,
98 recommended: recommended.clone(),
99 savings: None,
100 fix_yaml: recommended.to_yaml(),
101 rule_code: RuleCode::new(self.code()),
102 })
103 }
104}