vault_mgmt_lib/
version.rs1use std::str::FromStr;
2
3use k8s_openapi::api::{apps::v1::StatefulSet, core::v1::Pod};
4
5#[derive(Clone, Debug, Hash, PartialEq, Eq)]
6pub struct VaultVersion {
7 pub version: String,
8}
9
10impl FromStr for VaultVersion {
11 type Err = anyhow::Error;
12
13 fn from_str(s: &str) -> Result<Self, Self::Err> {
14 Ok(Self {
15 version: s.to_string(),
16 })
17 }
18}
19
20impl TryFrom<&StatefulSet> for VaultVersion {
22 type Error = anyhow::Error;
23
24 fn try_from(statefulset: &StatefulSet) -> Result<Self, Self::Error> {
25 let container = statefulset
26 .spec
27 .clone()
28 .ok_or(anyhow::anyhow!("statefulset does not have a spec"))?
29 .template
30 .spec
31 .ok_or(anyhow::anyhow!("statefulset does not have a pod spec"))?
32 .containers;
33 let container = container
34 .first()
35 .ok_or(anyhow::anyhow!("statefulset does not have a container"))?;
36
37 let image = container
38 .image
39 .clone()
40 .ok_or(anyhow::anyhow!("container does not have an image"))?;
41
42 let version = image
43 .split(':')
44 .nth(1)
45 .ok_or(anyhow::anyhow!("image does not have a tag"))?
46 .to_string();
47
48 Ok(Self { version })
49 }
50}
51
52impl TryFrom<&Pod> for VaultVersion {
54 type Error = anyhow::Error;
55
56 fn try_from(pod: &Pod) -> Result<Self, Self::Error> {
57 let container = pod
58 .spec
59 .clone()
60 .ok_or(anyhow::anyhow!("pod does not have a spec"))?
61 .containers;
62 let container = container
63 .first()
64 .ok_or(anyhow::anyhow!("pod does not have a container"))?;
65
66 let image = container
67 .image
68 .clone()
69 .ok_or(anyhow::anyhow!("container does not have an image"))?;
70
71 let version = image
72 .split(':')
73 .nth(1)
74 .ok_or(anyhow::anyhow!("image does not have a tag"))?
75 .to_string();
76
77 Ok(Self { version })
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use k8s_openapi::api::{apps::v1::StatefulSet, core::v1::Pod};
84
85 use crate::VaultVersion;
86
87 #[tokio::test]
88 async fn constructing_vault_version_from_statefulset_works() {
89 let file = tokio::fs::read_to_string(format!(
90 "tests/resources/installed/{}.yaml",
91 "apis/apps/v1/namespaces/vault-mgmt-e2e/statefulsets/vault-mgmt-e2e-2274"
92 ))
93 .await
94 .unwrap();
95
96 let statefulset: &StatefulSet = &serde_yaml::from_str(&file).unwrap();
97
98 let version: VaultVersion = statefulset.try_into().unwrap();
99
100 assert_eq!(version.version, "1.13.0");
101 }
102
103 #[tokio::test]
104 async fn constructing_vault_version_from_pod_works() {
105 let file = tokio::fs::read_to_string(format!(
106 "tests/resources/installed/{}.yaml",
107 "api/v1/namespaces/vault-mgmt-e2e/pods/vault-mgmt-e2e-2274-0"
108 ))
109 .await
110 .unwrap();
111
112 let pod: &k8s_openapi::api::core::v1::Pod = &serde_yaml::from_str(&file).unwrap();
113
114 let version: VaultVersion = pod.try_into().unwrap();
115
116 assert_eq!(version.version, "1.13.0");
117 }
118
119 #[tokio::test]
120 async fn constructing_vault_version_from_pod_with_invalid_image_fails() {
121 let file = tokio::fs::read_to_string(format!(
122 "tests/resources/installed/{}.yaml",
123 "api/v1/namespaces/vault-mgmt-e2e/pods/vault-mgmt-e2e-2274-0"
124 ))
125 .await
126 .unwrap();
127
128 let mut pod: Pod = serde_yaml::from_str(&file).unwrap();
129
130 pod.spec
131 .as_mut()
132 .unwrap()
133 .containers
134 .first_mut()
135 .unwrap()
136 .image = Some("vault".to_string());
137
138 let version: Result<VaultVersion, _> = (&pod).try_into();
139
140 assert!(version.is_err());
141 }
142
143 #[test]
144 fn comparing_vault_versions_works() {
145 let current = VaultVersion {
146 version: "1.13.0".to_string(),
147 };
148
149 let outdated = VaultVersion {
150 version: "1.12.0".to_string(),
151 };
152
153 let newer = VaultVersion {
154 version: "1.14.0".to_string(),
155 };
156
157 assert!(current == current);
158 assert!(current != outdated);
159 assert!(current != newer);
160 assert!(outdated != newer);
161 }
162}