Skip to content
This repository was archived by the owner on Dec 21, 2021. It is now read-only.

Commit 1c3c34f

Browse files
author
Siegfried Weber
authored
Crash fixed when no tag is provided for the container image (#40)
1 parent 327191c commit 1c3c34f

File tree

5 files changed

+180
-22
lines changed

5 files changed

+180
-22
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
target/

Cargo.lock

Lines changed: 31 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,8 @@ thiserror = "1.0"
3030
url = "2.2"
3131
pnet = "0.26.0"
3232
stackable_config = { git = "https://github.com/stackabletech/common.git", branch = "main" }
33+
34+
[dev-dependencies]
35+
indoc = "1.0"
36+
rstest = "0.6"
37+
serde_yaml = "0.8"

src/provider/mod.rs

Lines changed: 103 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::fs;
33
use std::path::PathBuf;
44
use std::process::Child;
55

6+
use anyhow::anyhow;
67
use k8s_openapi::apiextensions_apiserver::pkg::apis::apiextensions::v1::CustomResourceDefinition;
78
use kube::{Api, Client};
89
use kubelet::backoff::ExponentialBackoffStrategy;
@@ -87,23 +88,23 @@ impl StackableProvider {
8788
}
8889

8990
fn get_package(pod: &Pod) -> Result<Package, StackableError> {
90-
let containers = pod.containers();
91-
return if containers.len().ne(&1) {
92-
let e = PodValidationError {
93-
msg: String::from("Size of containers list in PodSpec has to be exactly 1"),
94-
};
95-
Err(e)
91+
if let Some((container, [])) = pod.containers().split_first() {
92+
container
93+
.image()
94+
.and_then(|maybe_ref| maybe_ref.ok_or_else(|| anyhow!("Image is required.")))
95+
.and_then(Package::try_from)
96+
.map_err(|err| PodValidationError {
97+
msg: format!(
98+
"Unable to get package reference from pod [{}]: {}",
99+
&pod.name(),
100+
&err
101+
),
102+
})
96103
} else {
97-
// List has exactly one value, try to parse this
98-
if let Ok(Some(reference)) = containers[0].image() {
99-
Package::try_from(reference)
100-
} else {
101-
let e = PodValidationError {
102-
msg: format!("Unable to get package reference from pod: {}", &pod.name()),
103-
};
104-
Err(e)
105-
}
106-
};
104+
Err(PodValidationError {
105+
msg: String::from("Only one container is supported in the PodSpec."),
106+
})
107+
}
107108
}
108109

109110
async fn check_crds(&self) -> Result<Vec<String>, StackableError> {
@@ -206,3 +207,89 @@ impl Provider for StackableProvider {
206207
Ok(())
207208
}
208209
}
210+
211+
#[cfg(test)]
212+
mod test {
213+
use super::*;
214+
use indoc::indoc;
215+
use rstest::rstest;
216+
217+
#[test]
218+
fn try_to_get_package_from_complete_configuration() {
219+
let pod = parse_pod_from_yaml(indoc! {"
220+
apiVersion: v1
221+
kind: Pod
222+
metadata:
223+
name: test
224+
spec:
225+
containers:
226+
- name: kafka
227+
image: kafka:2.7
228+
"});
229+
230+
let maybe_package = StackableProvider::get_package(&pod);
231+
232+
if let Ok(package) = maybe_package {
233+
assert_eq!("kafka", package.product);
234+
assert_eq!("2.7", package.version);
235+
} else {
236+
panic!("Package expected but got {:?}", maybe_package);
237+
}
238+
}
239+
240+
#[rstest(pod_config, expected_err,
241+
case(indoc! {"
242+
apiVersion: v1
243+
kind: Pod
244+
metadata:
245+
name: test
246+
spec:
247+
containers:
248+
- name: kafka
249+
image: kafka:2.7
250+
- name: zookeeper
251+
image: zookeeper:3.6.2
252+
"},
253+
"Only one container is supported in the PodSpec."
254+
),
255+
case(indoc! {"
256+
apiVersion: v1
257+
kind: Pod
258+
metadata:
259+
name: test
260+
spec:
261+
containers:
262+
- name: kafka
263+
"},
264+
"Unable to get package reference from pod [test]: Image is required."
265+
),
266+
case(indoc! {"
267+
apiVersion: v1
268+
kind: Pod
269+
metadata:
270+
name: test
271+
spec:
272+
containers:
273+
- name: kafka
274+
image: kafka
275+
"},
276+
"Unable to get package reference from pod [test]: Tag is required."
277+
),
278+
)]
279+
fn try_to_get_package_from_insufficient_configuration(pod_config: &str, expected_err: &str) {
280+
let pod = parse_pod_from_yaml(pod_config);
281+
282+
let maybe_package = StackableProvider::get_package(&pod);
283+
284+
if let Err(PodValidationError { msg }) = maybe_package {
285+
assert_eq!(expected_err, msg);
286+
} else {
287+
panic!("PodValidationError expected but got {:?}", maybe_package);
288+
}
289+
}
290+
291+
fn parse_pod_from_yaml(pod_config: &str) -> Pod {
292+
let kube_pod: k8s_openapi::api::core::v1::Pod = serde_yaml::from_str(pod_config).unwrap();
293+
Pod::from(kube_pod)
294+
}
295+
}

src/provider/repository/package.rs

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
use std::convert::TryFrom;
22
use std::fmt;
33

4+
use anyhow::{anyhow, Result};
45
use oci_distribution::Reference;
56
use serde::{Deserialize, Serialize};
67

7-
use crate::provider::error::StackableError;
8-
98
#[derive(Serialize, Deserialize, Debug, Clone)]
109
pub struct Package {
1110
pub product: String,
@@ -31,15 +30,18 @@ impl Package {
3130
}
3231

3332
impl TryFrom<Reference> for Package {
34-
type Error = StackableError;
33+
type Error = anyhow::Error;
3534

3635
// Converts from an oci reference to a package representation
3736
// The oci tag (anything after the \":\" in the string) is used as
3837
// version by this code and needs to be present
39-
fn try_from(value: Reference) -> Result<Self, Self::Error> {
38+
fn try_from(value: Reference) -> Result<Self> {
39+
let repository = value.repository();
40+
let tag = value.tag().ok_or_else(|| anyhow!("Tag is required."))?;
41+
4042
Ok(Package {
41-
product: String::from(value.repository()),
42-
version: String::from(value.tag().unwrap()),
43+
product: String::from(repository),
44+
version: String::from(tag),
4345
})
4446
}
4547
}
@@ -49,3 +51,35 @@ impl fmt::Display for Package {
4951
write!(f, "{}:{}", self.product, self.version)
5052
}
5153
}
54+
55+
#[cfg(test)]
56+
mod test {
57+
use super::*;
58+
59+
#[test]
60+
fn try_from_complete_reference() {
61+
let reference = Reference::try_from("kafka:2.7").expect("Reference cannot be parsed.");
62+
63+
let maybe_package = Package::try_from(reference);
64+
65+
if let Ok(package) = maybe_package {
66+
assert_eq!("kafka", package.product);
67+
assert_eq!("2.7", package.version);
68+
} else {
69+
panic!("Package expected but got {:?}", maybe_package);
70+
}
71+
}
72+
73+
#[test]
74+
fn try_from_reference_without_tag() {
75+
let reference = Reference::try_from("kafka").expect("Reference cannot be parsed.");
76+
77+
let maybe_package = Package::try_from(reference);
78+
79+
if let Err(error) = maybe_package {
80+
assert_eq!("Tag is required.", error.to_string());
81+
} else {
82+
panic!("Error expected but got {:?}", maybe_package);
83+
}
84+
}
85+
}

0 commit comments

Comments
 (0)