syncable_cli/analyzer/kubelint/templates/
updateconfig.rs1use crate::analyzer::kubelint::context::Object;
4use crate::analyzer::kubelint::context::object::K8sObject;
5use crate::analyzer::kubelint::templates::{CheckFunc, ParameterDesc, Template, TemplateError};
6use crate::analyzer::kubelint::types::{Diagnostic, ObjectKindsDesc};
7
8pub struct RollingUpdateStrategyTemplate;
10
11impl Template for RollingUpdateStrategyTemplate {
12 fn key(&self) -> &str {
13 "rolling-update-strategy"
14 }
15
16 fn human_name(&self) -> &str {
17 "Rolling Update Strategy"
18 }
19
20 fn description(&self) -> &str {
21 "Detects deployments without a rolling update strategy configured"
22 }
23
24 fn supported_object_kinds(&self) -> ObjectKindsDesc {
25 ObjectKindsDesc::new(&["Deployment", "DaemonSet"])
26 }
27
28 fn parameters(&self) -> Vec<ParameterDesc> {
29 Vec::new()
30 }
31
32 fn instantiate(
33 &self,
34 _params: &serde_yaml::Value,
35 ) -> Result<Box<dyn CheckFunc>, TemplateError> {
36 Ok(Box::new(RollingUpdateStrategyCheck))
37 }
38}
39
40struct RollingUpdateStrategyCheck;
41
42impl CheckFunc for RollingUpdateStrategyCheck {
43 fn check(&self, object: &Object) -> Vec<Diagnostic> {
44 let mut diagnostics = Vec::new();
45
46 match &object.k8s_object {
47 K8sObject::Deployment(dep) => {
48 let strategy = dep.strategy.as_ref();
49 let strategy_type = strategy.and_then(|s| s.type_.as_deref());
50
51 if strategy_type == Some("Recreate") {
53 diagnostics.push(Diagnostic {
54 message: format!(
55 "Deployment '{}' uses Recreate strategy instead of RollingUpdate",
56 object.name()
57 ),
58 remediation: Some(
59 "Consider using RollingUpdate strategy for zero-downtime deployments."
60 .to_string(),
61 ),
62 });
63 }
64
65 if strategy_type.is_none() || strategy_type == Some("RollingUpdate") {
67 let rolling_update = strategy.and_then(|s| s.rolling_update.as_ref());
68 if rolling_update.is_none() {
69 diagnostics.push(Diagnostic {
70 message: format!(
71 "Deployment '{}' has no explicit rolling update configuration",
72 object.name()
73 ),
74 remediation: Some(
75 "Configure strategy.rollingUpdate.maxSurge and maxUnavailable \
76 for controlled rollouts."
77 .to_string(),
78 ),
79 });
80 }
81 }
82 }
83 K8sObject::DaemonSet(ds) => {
84 let strategy_type = ds.update_strategy.as_ref().and_then(|s| s.type_.as_deref());
85
86 if strategy_type == Some("OnDelete") {
87 diagnostics.push(Diagnostic {
88 message: format!(
89 "DaemonSet '{}' uses OnDelete strategy instead of RollingUpdate",
90 object.name()
91 ),
92 remediation: Some(
93 "Consider using RollingUpdate strategy for automatic updates."
94 .to_string(),
95 ),
96 });
97 }
98 }
99 _ => {}
100 }
101
102 diagnostics
103 }
104}