sk_store/
config.rs

1use std::collections::HashMap;
2use std::fs::File;
3use std::ops::Not;
4
5use serde::{
6    Deserialize,
7    Serialize,
8};
9use sk_core::k8s::GVK;
10use tracing::*;
11
12#[derive(Deserialize)]
13#[serde(rename_all = "camelCase")]
14struct TrackedObjectConfigWithDeprecatedFields {
15    #[deprecated]
16    pub pod_spec_template_path: Option<String>,
17    pub pod_spec_template_paths: Option<Vec<String>>,
18
19    #[serde(default)]
20    pub track_lifecycle: bool,
21}
22
23#[derive(Clone, Debug, Default, Deserialize, Serialize)]
24#[serde(rename_all = "camelCase", from = "TrackedObjectConfigWithDeprecatedFields")]
25pub struct TrackedObjectConfig {
26    pub pod_spec_template_paths: Option<Vec<String>>,
27
28    #[serde(skip_serializing_if = "<&bool>::not")]
29    pub track_lifecycle: bool,
30}
31
32impl From<TrackedObjectConfigWithDeprecatedFields> for TrackedObjectConfig {
33    fn from(input: TrackedObjectConfigWithDeprecatedFields) -> Self {
34        let mut output = TrackedObjectConfig {
35            pod_spec_template_paths: input.pod_spec_template_paths.clone(),
36            track_lifecycle: input.track_lifecycle,
37        };
38
39        #[allow(deprecated)]
40        if let Some(pstp) = input.pod_spec_template_path {
41            warn!(
42                "tracked object config field podSpecTemplatePath is deprecated \
43                    and will be removed in a future version of SimKube.  Please use \
44                    podSpecTemplatePaths instead."
45            );
46
47            if input.pod_spec_template_paths.as_ref().is_some_and(|p| !p.is_empty()) {
48                warn!(
49                    "both podSpecTemplatePath and podSpecTemplatePaths are set; \
50                        ignoring the deprecated field."
51                );
52            } else {
53                output.pod_spec_template_paths = Some(vec![pstp]);
54            }
55        }
56
57        output
58    }
59}
60
61#[derive(Clone, Debug, Default, Deserialize, Serialize)]
62#[serde(rename_all = "camelCase")]
63pub struct TracerConfig {
64    pub tracked_objects: HashMap<GVK, TrackedObjectConfig>,
65}
66
67impl TracerConfig {
68    pub fn load(filename: &str) -> anyhow::Result<TracerConfig> {
69        Ok(serde_yaml::from_reader(File::open(filename)?)?)
70    }
71
72    pub fn pod_spec_template_paths(&self, gvk: &GVK) -> Option<&[String]> {
73        self.tracked_objects.get(gvk)?.pod_spec_template_paths.as_deref()
74    }
75
76    pub fn track_lifecycle_for(&self, gvk: &GVK) -> bool {
77        self.tracked_objects.get(gvk).is_some_and(|obj| obj.track_lifecycle)
78    }
79}
80
81#[cfg(test)]
82mod tests {
83    use sk_testutils::*;
84
85    use super::*;
86
87    #[rstest]
88    #[case::none(None, vec!["/foo/bar".into()])]
89    #[case::empty(Some(vec![]), vec!["/foo/bar".into()])]
90    #[case::full(Some(vec!["/asdf".into()]), vec!["/asdf".into()])]
91    fn test_deprecated_config(#[case] pod_spec_template_paths: Option<Vec<String>>, #[case] expected: Vec<String>) {
92        let gvk = GVK::new("fake", "v1", "Resource");
93        let mut config_yml = "
94---
95trackedObjects:
96  fake/v1.Resource:
97    podSpecTemplatePath: /foo/bar
98"
99        .to_string();
100
101        if let Some(pstps) = pod_spec_template_paths {
102            if pstps.len() > 0 {
103                let pstp = pstps[0].clone();
104                config_yml.push_str(&format!("    podSpecTemplatePaths:\n      - {pstp}"));
105            }
106        }
107
108        let config: TracerConfig = serde_yaml::from_str(&config_yml).unwrap();
109
110        assert_eq!(config.tracked_objects[&gvk].pod_spec_template_paths, Some(expected));
111    }
112
113    #[rstest]
114    fn test_correct_config() {
115        let gvk = GVK::new("fake", "v1", "Resource");
116        let config_yml = "
117---
118trackedObjects:
119  fake/v1.Resource:
120    podSpecTemplatePaths:
121      - /foo/bar
122"
123        .to_string();
124
125        let config: TracerConfig = serde_yaml::from_str(&config_yml).unwrap();
126        assert_eq!(config.tracked_objects[&gvk].pod_spec_template_paths, Some(vec!["/foo/bar".into()]));
127    }
128}