syncable_cli/analyzer/kubelint/context/
object.rs

1//! Kubernetes object wrappers for linting.
2
3use crate::analyzer::kubelint::types::ObjectKind;
4use serde::{Deserialize, Serialize};
5use std::path::PathBuf;
6
7/// Metadata about a parsed Kubernetes object.
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct ObjectMetadata {
10    /// The file path where this object was defined.
11    pub file_path: PathBuf,
12    /// The raw YAML content (for error reporting).
13    pub raw: Option<Vec<u8>>,
14    /// Line number in the source file (1-indexed).
15    pub line_number: Option<u32>,
16}
17
18impl ObjectMetadata {
19    /// Create new metadata for an object from a file.
20    pub fn from_file(path: impl Into<PathBuf>) -> Self {
21        Self {
22            file_path: path.into(),
23            raw: None,
24            line_number: None,
25        }
26    }
27
28    /// Set the raw content.
29    pub fn with_raw(mut self, raw: Vec<u8>) -> Self {
30        self.raw = Some(raw);
31        self
32    }
33
34    /// Set the line number.
35    pub fn with_line(mut self, line: u32) -> Self {
36        self.line_number = Some(line);
37        self
38    }
39}
40
41/// A parsed Kubernetes object ready for linting.
42#[derive(Debug, Clone)]
43pub struct Object {
44    /// Metadata about where this object came from.
45    pub metadata: ObjectMetadata,
46    /// The Kubernetes object data.
47    pub k8s_object: K8sObject,
48}
49
50impl Object {
51    /// Create a new object.
52    pub fn new(metadata: ObjectMetadata, k8s_object: K8sObject) -> Self {
53        Self {
54            metadata,
55            k8s_object,
56        }
57    }
58
59    /// Get the object's kind.
60    pub fn kind(&self) -> ObjectKind {
61        self.k8s_object.kind()
62    }
63
64    /// Get the object's name.
65    pub fn name(&self) -> &str {
66        self.k8s_object.name()
67    }
68
69    /// Get the object's namespace.
70    pub fn namespace(&self) -> Option<&str> {
71        self.k8s_object.namespace()
72    }
73
74    /// Get annotations from the object.
75    pub fn annotations(&self) -> Option<&std::collections::BTreeMap<String, String>> {
76        self.k8s_object.annotations()
77    }
78}
79
80/// An object that failed to parse.
81#[derive(Debug, Clone)]
82pub struct InvalidObject {
83    /// Metadata about where this object came from.
84    pub metadata: ObjectMetadata,
85    /// The error that occurred during parsing.
86    pub load_err: String,
87}
88
89impl InvalidObject {
90    /// Create a new invalid object record.
91    pub fn new(metadata: ObjectMetadata, error: impl Into<String>) -> Self {
92        Self {
93            metadata,
94            load_err: error.into(),
95        }
96    }
97}
98
99/// Enum representing all supported Kubernetes object types.
100///
101/// This enum provides type-safe access to K8s objects while also
102/// supporting unknown/custom types via the Unknown variant.
103#[derive(Debug, Clone)]
104pub enum K8sObject {
105    // Workloads
106    Deployment(Box<DeploymentData>),
107    StatefulSet(Box<StatefulSetData>),
108    DaemonSet(Box<DaemonSetData>),
109    ReplicaSet(Box<ReplicaSetData>),
110    Pod(Box<PodData>),
111    Job(Box<JobData>),
112    CronJob(Box<CronJobData>),
113
114    // Services & Networking
115    Service(Box<ServiceData>),
116    Ingress(Box<IngressData>),
117    NetworkPolicy(Box<NetworkPolicyData>),
118
119    // RBAC
120    Role(Box<RoleData>),
121    ClusterRole(Box<ClusterRoleData>),
122    RoleBinding(Box<RoleBindingData>),
123    ClusterRoleBinding(Box<ClusterRoleBindingData>),
124    ServiceAccount(Box<ServiceAccountData>),
125
126    // Scaling
127    HorizontalPodAutoscaler(Box<HpaData>),
128    PodDisruptionBudget(Box<PdbData>),
129
130    // Storage
131    PersistentVolumeClaim(Box<PvcData>),
132
133    // Unknown/CRD
134    Unknown(Box<UnknownObject>),
135}
136
137impl K8sObject {
138    /// Get the object kind.
139    pub fn kind(&self) -> ObjectKind {
140        match self {
141            Self::Deployment(_) => ObjectKind::Deployment,
142            Self::StatefulSet(_) => ObjectKind::StatefulSet,
143            Self::DaemonSet(_) => ObjectKind::DaemonSet,
144            Self::ReplicaSet(_) => ObjectKind::ReplicaSet,
145            Self::Pod(_) => ObjectKind::Pod,
146            Self::Job(_) => ObjectKind::Job,
147            Self::CronJob(_) => ObjectKind::CronJob,
148            Self::Service(_) => ObjectKind::Service,
149            Self::Ingress(_) => ObjectKind::Ingress,
150            Self::NetworkPolicy(_) => ObjectKind::NetworkPolicy,
151            Self::Role(_) => ObjectKind::Role,
152            Self::ClusterRole(_) => ObjectKind::ClusterRole,
153            Self::RoleBinding(_) => ObjectKind::RoleBinding,
154            Self::ClusterRoleBinding(_) => ObjectKind::ClusterRoleBinding,
155            Self::ServiceAccount(_) => ObjectKind::ServiceAccount,
156            Self::HorizontalPodAutoscaler(_) => ObjectKind::HorizontalPodAutoscaler,
157            Self::PodDisruptionBudget(_) => ObjectKind::PodDisruptionBudget,
158            Self::PersistentVolumeClaim(_) => ObjectKind::PersistentVolumeClaim,
159            Self::Unknown(_) => ObjectKind::Any,
160        }
161    }
162
163    /// Get the object name.
164    pub fn name(&self) -> &str {
165        match self {
166            Self::Deployment(d) => &d.name,
167            Self::StatefulSet(d) => &d.name,
168            Self::DaemonSet(d) => &d.name,
169            Self::ReplicaSet(d) => &d.name,
170            Self::Pod(d) => &d.name,
171            Self::Job(d) => &d.name,
172            Self::CronJob(d) => &d.name,
173            Self::Service(d) => &d.name,
174            Self::Ingress(d) => &d.name,
175            Self::NetworkPolicy(d) => &d.name,
176            Self::Role(d) => &d.name,
177            Self::ClusterRole(d) => &d.name,
178            Self::RoleBinding(d) => &d.name,
179            Self::ClusterRoleBinding(d) => &d.name,
180            Self::ServiceAccount(d) => &d.name,
181            Self::HorizontalPodAutoscaler(d) => &d.name,
182            Self::PodDisruptionBudget(d) => &d.name,
183            Self::PersistentVolumeClaim(d) => &d.name,
184            Self::Unknown(d) => &d.name,
185        }
186    }
187
188    /// Get the object namespace.
189    pub fn namespace(&self) -> Option<&str> {
190        match self {
191            Self::Deployment(d) => d.namespace.as_deref(),
192            Self::StatefulSet(d) => d.namespace.as_deref(),
193            Self::DaemonSet(d) => d.namespace.as_deref(),
194            Self::ReplicaSet(d) => d.namespace.as_deref(),
195            Self::Pod(d) => d.namespace.as_deref(),
196            Self::Job(d) => d.namespace.as_deref(),
197            Self::CronJob(d) => d.namespace.as_deref(),
198            Self::Service(d) => d.namespace.as_deref(),
199            Self::Ingress(d) => d.namespace.as_deref(),
200            Self::NetworkPolicy(d) => d.namespace.as_deref(),
201            Self::Role(d) => d.namespace.as_deref(),
202            Self::ClusterRole(_) => None, // Cluster-scoped
203            Self::RoleBinding(d) => d.namespace.as_deref(),
204            Self::ClusterRoleBinding(_) => None, // Cluster-scoped
205            Self::ServiceAccount(d) => d.namespace.as_deref(),
206            Self::HorizontalPodAutoscaler(d) => d.namespace.as_deref(),
207            Self::PodDisruptionBudget(d) => d.namespace.as_deref(),
208            Self::PersistentVolumeClaim(d) => d.namespace.as_deref(),
209            Self::Unknown(d) => d.namespace.as_deref(),
210        }
211    }
212
213    /// Get annotations from the object.
214    pub fn annotations(&self) -> Option<&std::collections::BTreeMap<String, String>> {
215        match self {
216            Self::Deployment(d) => d.annotations.as_ref(),
217            Self::StatefulSet(d) => d.annotations.as_ref(),
218            Self::DaemonSet(d) => d.annotations.as_ref(),
219            Self::ReplicaSet(d) => d.annotations.as_ref(),
220            Self::Pod(d) => d.annotations.as_ref(),
221            Self::Job(d) => d.annotations.as_ref(),
222            Self::CronJob(d) => d.annotations.as_ref(),
223            Self::Service(d) => d.annotations.as_ref(),
224            Self::Ingress(d) => d.annotations.as_ref(),
225            Self::NetworkPolicy(d) => d.annotations.as_ref(),
226            Self::Role(d) => d.annotations.as_ref(),
227            Self::ClusterRole(d) => d.annotations.as_ref(),
228            Self::RoleBinding(d) => d.annotations.as_ref(),
229            Self::ClusterRoleBinding(d) => d.annotations.as_ref(),
230            Self::ServiceAccount(d) => d.annotations.as_ref(),
231            Self::HorizontalPodAutoscaler(d) => d.annotations.as_ref(),
232            Self::PodDisruptionBudget(d) => d.annotations.as_ref(),
233            Self::PersistentVolumeClaim(d) => d.annotations.as_ref(),
234            Self::Unknown(d) => d.annotations.as_ref(),
235        }
236    }
237}
238
239// ============================================================================
240// Data structures for each K8s object type
241// These are simplified representations; full k8s-openapi types will be used
242// in the actual implementation
243// ============================================================================
244
245/// Common metadata fields.
246#[derive(Debug, Clone, Default)]
247pub struct CommonMeta {
248    pub name: String,
249    pub namespace: Option<String>,
250    pub labels: Option<std::collections::BTreeMap<String, String>>,
251    pub annotations: Option<std::collections::BTreeMap<String, String>>,
252}
253
254/// Simplified container spec.
255#[derive(Debug, Clone, Default)]
256pub struct ContainerSpec {
257    pub name: String,
258    pub image: Option<String>,
259    pub security_context: Option<SecurityContext>,
260    pub resources: Option<ResourceRequirements>,
261    pub liveness_probe: Option<Probe>,
262    pub readiness_probe: Option<Probe>,
263    pub startup_probe: Option<Probe>,
264    pub env: Vec<EnvVar>,
265    pub volume_mounts: Vec<VolumeMount>,
266    pub ports: Vec<ContainerPort>,
267}
268
269/// Security context for containers/pods.
270#[derive(Debug, Clone, Default)]
271pub struct SecurityContext {
272    pub privileged: Option<bool>,
273    pub allow_privilege_escalation: Option<bool>,
274    pub run_as_non_root: Option<bool>,
275    pub run_as_user: Option<i64>,
276    pub read_only_root_filesystem: Option<bool>,
277    pub capabilities: Option<Capabilities>,
278    pub proc_mount: Option<String>,
279}
280
281/// Linux capabilities.
282#[derive(Debug, Clone, Default)]
283pub struct Capabilities {
284    pub add: Vec<String>,
285    pub drop: Vec<String>,
286}
287
288/// Resource requirements.
289#[derive(Debug, Clone, Default)]
290pub struct ResourceRequirements {
291    pub limits: Option<std::collections::BTreeMap<String, String>>,
292    pub requests: Option<std::collections::BTreeMap<String, String>>,
293}
294
295/// Probe configuration.
296#[derive(Debug, Clone, Default)]
297pub struct Probe {
298    pub http_get: Option<HttpGetAction>,
299    pub tcp_socket: Option<TcpSocketAction>,
300    pub exec: Option<ExecAction>,
301}
302
303#[derive(Debug, Clone, Default)]
304pub struct HttpGetAction {
305    pub port: i32,
306    pub path: Option<String>,
307}
308
309#[derive(Debug, Clone, Default)]
310pub struct TcpSocketAction {
311    pub port: i32,
312}
313
314#[derive(Debug, Clone, Default)]
315pub struct ExecAction {
316    pub command: Vec<String>,
317}
318
319/// Environment variable.
320#[derive(Debug, Clone, Default)]
321pub struct EnvVar {
322    pub name: String,
323    pub value: Option<String>,
324    pub value_from: Option<EnvVarSource>,
325}
326
327#[derive(Debug, Clone)]
328pub enum EnvVarSource {
329    SecretKeyRef { name: String, key: String },
330    ConfigMapKeyRef { name: String, key: String },
331    FieldRef { field_path: String },
332}
333
334/// Volume mount.
335#[derive(Debug, Clone, Default)]
336pub struct VolumeMount {
337    pub name: String,
338    pub mount_path: String,
339    pub read_only: Option<bool>,
340}
341
342/// Container port.
343#[derive(Debug, Clone, Default)]
344pub struct ContainerPort {
345    pub container_port: i32,
346    pub protocol: Option<String>,
347    pub host_port: Option<i32>,
348}
349
350/// Pod spec (simplified).
351#[derive(Debug, Clone, Default)]
352pub struct PodSpec {
353    pub containers: Vec<ContainerSpec>,
354    pub init_containers: Vec<ContainerSpec>,
355    pub volumes: Vec<Volume>,
356    pub service_account_name: Option<String>,
357    pub host_network: Option<bool>,
358    pub host_pid: Option<bool>,
359    pub host_ipc: Option<bool>,
360    pub security_context: Option<PodSecurityContext>,
361    pub affinity: Option<Affinity>,
362    pub dns_config: Option<DnsConfig>,
363    pub restart_policy: Option<String>,
364    pub priority_class_name: Option<String>,
365}
366
367#[derive(Debug, Clone, Default)]
368pub struct PodSecurityContext {
369    pub run_as_non_root: Option<bool>,
370    pub run_as_user: Option<i64>,
371    pub sysctls: Vec<Sysctl>,
372}
373
374#[derive(Debug, Clone, Default)]
375pub struct Sysctl {
376    pub name: String,
377    pub value: String,
378}
379
380#[derive(Debug, Clone, Default)]
381pub struct Volume {
382    pub name: String,
383    pub host_path: Option<HostPathVolumeSource>,
384    pub secret: Option<SecretVolumeSource>,
385}
386
387#[derive(Debug, Clone, Default)]
388pub struct HostPathVolumeSource {
389    pub path: String,
390    pub type_: Option<String>,
391}
392
393#[derive(Debug, Clone, Default)]
394pub struct SecretVolumeSource {
395    pub secret_name: Option<String>,
396}
397
398#[derive(Debug, Clone, Default)]
399pub struct Affinity {
400    pub pod_anti_affinity: Option<PodAntiAffinity>,
401    pub node_affinity: Option<NodeAffinity>,
402}
403
404#[derive(Debug, Clone, Default)]
405pub struct PodAntiAffinity {
406    pub required_during_scheduling_ignored_during_execution: Vec<PodAffinityTerm>,
407    pub preferred_during_scheduling_ignored_during_execution: Vec<WeightedPodAffinityTerm>,
408}
409
410#[derive(Debug, Clone, Default)]
411pub struct PodAffinityTerm {
412    pub topology_key: String,
413}
414
415#[derive(Debug, Clone, Default)]
416pub struct WeightedPodAffinityTerm {
417    pub weight: i32,
418    pub pod_affinity_term: PodAffinityTerm,
419}
420
421#[derive(Debug, Clone, Default)]
422pub struct NodeAffinity {
423    pub required_during_scheduling_ignored_during_execution: Option<NodeSelector>,
424}
425
426#[derive(Debug, Clone, Default)]
427pub struct NodeSelector {
428    pub node_selector_terms: Vec<NodeSelectorTerm>,
429}
430
431#[derive(Debug, Clone, Default)]
432pub struct NodeSelectorTerm {
433    pub match_expressions: Vec<NodeSelectorRequirement>,
434}
435
436#[derive(Debug, Clone, Default)]
437pub struct NodeSelectorRequirement {
438    pub key: String,
439    pub operator: String,
440    pub values: Vec<String>,
441}
442
443#[derive(Debug, Clone, Default)]
444pub struct DnsConfig {
445    pub options: Vec<PodDnsConfigOption>,
446}
447
448#[derive(Debug, Clone, Default)]
449pub struct PodDnsConfigOption {
450    pub name: Option<String>,
451    pub value: Option<String>,
452}
453
454// ============================================================================
455// Object data types
456// ============================================================================
457
458#[derive(Debug, Clone, Default)]
459pub struct DeploymentData {
460    pub name: String,
461    pub namespace: Option<String>,
462    pub annotations: Option<std::collections::BTreeMap<String, String>>,
463    pub labels: Option<std::collections::BTreeMap<String, String>>,
464    pub replicas: Option<i32>,
465    pub selector: Option<LabelSelector>,
466    pub pod_spec: Option<PodSpec>,
467    pub strategy: Option<DeploymentStrategy>,
468}
469
470#[derive(Debug, Clone, Default)]
471pub struct LabelSelector {
472    pub match_labels: Option<std::collections::BTreeMap<String, String>>,
473}
474
475#[derive(Debug, Clone, Default)]
476pub struct DeploymentStrategy {
477    pub type_: Option<String>,
478    pub rolling_update: Option<RollingUpdateDeployment>,
479}
480
481#[derive(Debug, Clone, Default)]
482pub struct RollingUpdateDeployment {
483    pub max_unavailable: Option<String>,
484    pub max_surge: Option<String>,
485}
486
487#[derive(Debug, Clone, Default)]
488pub struct StatefulSetData {
489    pub name: String,
490    pub namespace: Option<String>,
491    pub annotations: Option<std::collections::BTreeMap<String, String>>,
492    pub labels: Option<std::collections::BTreeMap<String, String>>,
493    pub replicas: Option<i32>,
494    pub selector: Option<LabelSelector>,
495    pub pod_spec: Option<PodSpec>,
496}
497
498#[derive(Debug, Clone, Default)]
499pub struct DaemonSetData {
500    pub name: String,
501    pub namespace: Option<String>,
502    pub annotations: Option<std::collections::BTreeMap<String, String>>,
503    pub labels: Option<std::collections::BTreeMap<String, String>>,
504    pub selector: Option<LabelSelector>,
505    pub pod_spec: Option<PodSpec>,
506    pub update_strategy: Option<DaemonSetUpdateStrategy>,
507}
508
509#[derive(Debug, Clone, Default)]
510pub struct DaemonSetUpdateStrategy {
511    pub type_: Option<String>,
512}
513
514#[derive(Debug, Clone, Default)]
515pub struct ReplicaSetData {
516    pub name: String,
517    pub namespace: Option<String>,
518    pub annotations: Option<std::collections::BTreeMap<String, String>>,
519    pub labels: Option<std::collections::BTreeMap<String, String>>,
520    pub replicas: Option<i32>,
521    pub selector: Option<LabelSelector>,
522    pub pod_spec: Option<PodSpec>,
523}
524
525#[derive(Debug, Clone, Default)]
526pub struct PodData {
527    pub name: String,
528    pub namespace: Option<String>,
529    pub annotations: Option<std::collections::BTreeMap<String, String>>,
530    pub labels: Option<std::collections::BTreeMap<String, String>>,
531    pub spec: Option<PodSpec>,
532}
533
534#[derive(Debug, Clone, Default)]
535pub struct JobData {
536    pub name: String,
537    pub namespace: Option<String>,
538    pub annotations: Option<std::collections::BTreeMap<String, String>>,
539    pub labels: Option<std::collections::BTreeMap<String, String>>,
540    pub pod_spec: Option<PodSpec>,
541    pub ttl_seconds_after_finished: Option<i32>,
542}
543
544#[derive(Debug, Clone, Default)]
545pub struct CronJobData {
546    pub name: String,
547    pub namespace: Option<String>,
548    pub annotations: Option<std::collections::BTreeMap<String, String>>,
549    pub labels: Option<std::collections::BTreeMap<String, String>>,
550    pub job_spec: Option<JobData>,
551}
552
553#[derive(Debug, Clone, Default)]
554pub struct ServiceData {
555    pub name: String,
556    pub namespace: Option<String>,
557    pub annotations: Option<std::collections::BTreeMap<String, String>>,
558    pub labels: Option<std::collections::BTreeMap<String, String>>,
559    pub selector: Option<std::collections::BTreeMap<String, String>>,
560    pub ports: Vec<ServicePort>,
561    pub type_: Option<String>,
562}
563
564#[derive(Debug, Clone, Default)]
565pub struct ServicePort {
566    pub port: i32,
567    pub target_port: Option<String>,
568    pub protocol: Option<String>,
569    pub name: Option<String>,
570}
571
572#[derive(Debug, Clone, Default)]
573pub struct IngressData {
574    pub name: String,
575    pub namespace: Option<String>,
576    pub annotations: Option<std::collections::BTreeMap<String, String>>,
577    pub labels: Option<std::collections::BTreeMap<String, String>>,
578    pub rules: Vec<IngressRule>,
579}
580
581#[derive(Debug, Clone, Default)]
582pub struct IngressRule {
583    pub host: Option<String>,
584    pub http: Option<HttpIngressRuleValue>,
585}
586
587#[derive(Debug, Clone, Default)]
588pub struct HttpIngressRuleValue {
589    pub paths: Vec<HttpIngressPath>,
590}
591
592#[derive(Debug, Clone, Default)]
593pub struct HttpIngressPath {
594    pub path: Option<String>,
595    pub backend: IngressBackend,
596}
597
598#[derive(Debug, Clone, Default)]
599pub struct IngressBackend {
600    pub service: Option<IngressServiceBackend>,
601}
602
603#[derive(Debug, Clone, Default)]
604pub struct IngressServiceBackend {
605    pub name: String,
606    pub port: Option<ServiceBackendPort>,
607}
608
609#[derive(Debug, Clone, Default)]
610pub struct ServiceBackendPort {
611    pub number: Option<i32>,
612    pub name: Option<String>,
613}
614
615#[derive(Debug, Clone, Default)]
616pub struct NetworkPolicyData {
617    pub name: String,
618    pub namespace: Option<String>,
619    pub annotations: Option<std::collections::BTreeMap<String, String>>,
620    pub labels: Option<std::collections::BTreeMap<String, String>>,
621    pub pod_selector: Option<LabelSelector>,
622}
623
624#[derive(Debug, Clone, Default)]
625pub struct RoleData {
626    pub name: String,
627    pub namespace: Option<String>,
628    pub annotations: Option<std::collections::BTreeMap<String, String>>,
629    pub labels: Option<std::collections::BTreeMap<String, String>>,
630    pub rules: Vec<PolicyRule>,
631}
632
633#[derive(Debug, Clone, Default)]
634pub struct ClusterRoleData {
635    pub name: String,
636    pub annotations: Option<std::collections::BTreeMap<String, String>>,
637    pub labels: Option<std::collections::BTreeMap<String, String>>,
638    pub rules: Vec<PolicyRule>,
639}
640
641#[derive(Debug, Clone, Default)]
642pub struct PolicyRule {
643    pub api_groups: Vec<String>,
644    pub resources: Vec<String>,
645    pub verbs: Vec<String>,
646}
647
648#[derive(Debug, Clone, Default)]
649pub struct RoleBindingData {
650    pub name: String,
651    pub namespace: Option<String>,
652    pub annotations: Option<std::collections::BTreeMap<String, String>>,
653    pub labels: Option<std::collections::BTreeMap<String, String>>,
654    pub role_ref: RoleRef,
655    pub subjects: Vec<Subject>,
656}
657
658#[derive(Debug, Clone, Default)]
659pub struct ClusterRoleBindingData {
660    pub name: String,
661    pub annotations: Option<std::collections::BTreeMap<String, String>>,
662    pub labels: Option<std::collections::BTreeMap<String, String>>,
663    pub role_ref: RoleRef,
664    pub subjects: Vec<Subject>,
665}
666
667#[derive(Debug, Clone, Default)]
668pub struct RoleRef {
669    pub api_group: String,
670    pub kind: String,
671    pub name: String,
672}
673
674#[derive(Debug, Clone, Default)]
675pub struct Subject {
676    pub kind: String,
677    pub name: String,
678    pub namespace: Option<String>,
679}
680
681#[derive(Debug, Clone, Default)]
682pub struct ServiceAccountData {
683    pub name: String,
684    pub namespace: Option<String>,
685    pub annotations: Option<std::collections::BTreeMap<String, String>>,
686    pub labels: Option<std::collections::BTreeMap<String, String>>,
687}
688
689#[derive(Debug, Clone, Default)]
690pub struct HpaData {
691    pub name: String,
692    pub namespace: Option<String>,
693    pub annotations: Option<std::collections::BTreeMap<String, String>>,
694    pub labels: Option<std::collections::BTreeMap<String, String>>,
695    pub min_replicas: Option<i32>,
696    pub max_replicas: i32,
697    pub scale_target_ref: CrossVersionObjectReference,
698}
699
700#[derive(Debug, Clone, Default)]
701pub struct CrossVersionObjectReference {
702    pub api_version: Option<String>,
703    pub kind: String,
704    pub name: String,
705}
706
707#[derive(Debug, Clone, Default)]
708pub struct PdbData {
709    pub name: String,
710    pub namespace: Option<String>,
711    pub annotations: Option<std::collections::BTreeMap<String, String>>,
712    pub labels: Option<std::collections::BTreeMap<String, String>>,
713    pub min_available: Option<String>,
714    pub max_unavailable: Option<String>,
715    pub selector: Option<LabelSelector>,
716    pub unhealthy_pod_eviction_policy: Option<String>,
717}
718
719#[derive(Debug, Clone, Default)]
720pub struct PvcData {
721    pub name: String,
722    pub namespace: Option<String>,
723    pub annotations: Option<std::collections::BTreeMap<String, String>>,
724    pub labels: Option<std::collections::BTreeMap<String, String>>,
725}
726
727#[derive(Debug, Clone, Default)]
728pub struct UnknownObject {
729    pub api_version: String,
730    pub kind: String,
731    pub name: String,
732    pub namespace: Option<String>,
733    pub annotations: Option<std::collections::BTreeMap<String, String>>,
734    pub labels: Option<std::collections::BTreeMap<String, String>>,
735    pub raw: serde_yaml::Value,
736}