Skip to content

Commit 8cc03df

Browse files
chore: Move controller utility functions to separate module (#104)
1 parent d292f1e commit 8cc03df

3 files changed

Lines changed: 229 additions & 60 deletions

File tree

rust/operator-binary/src/controller/validate.rs

Lines changed: 17 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
//! The validate step in the OpenSearchCluster controller
22
3-
use std::{collections::BTreeMap, num::TryFromIntError, str::FromStr};
3+
use std::{collections::BTreeMap, str::FromStr};
44

55
use snafu::{OptionExt, ResultExt, Snafu};
66
use stackable_operator::{
7-
kube::{Resource, ResourceExt},
8-
product_logging::spec::Logging,
9-
role_utils::RoleGroup,
10-
shared::time::Duration,
7+
product_logging::spec::Logging, role_utils::RoleGroup, shared::time::Duration,
118
};
129
use strum::{EnumDiscriminants, IntoStaticStr};
1310

@@ -19,49 +16,38 @@ use crate::{
1916
crd::v1alpha1::{self},
2017
framework::{
2118
builder::pod::container::{EnvVarName, EnvVarSet},
19+
controller_utils::{get_cluster_name, get_namespace, get_uid},
2220
product_logging::framework::{
2321
VectorContainerLogConfig, validate_logging_configuration_for_container,
2422
},
2523
role_utils::{GenericProductSpecificCommonConfig, RoleGroupConfig, with_validated_config},
26-
types::{
27-
kubernetes::{ConfigMapName, NamespaceName, Uid},
28-
operator::ClusterName,
29-
},
24+
types::{kubernetes::ConfigMapName, operator::ClusterName},
3025
},
3126
};
3227

3328
#[derive(Snafu, Debug, EnumDiscriminants)]
3429
#[strum_discriminants(derive(IntoStaticStr))]
3530
pub enum Error {
3631
#[snafu(display("failed to get the cluster name"))]
37-
GetClusterName {},
32+
GetClusterName {
33+
source: crate::framework::controller_utils::Error,
34+
},
3835

3936
#[snafu(display("failed to get the cluster namespace"))]
40-
GetClusterNamespace {},
37+
GetClusterNamespace {
38+
source: crate::framework::controller_utils::Error,
39+
},
4140

4241
#[snafu(display("failed to get the cluster UID"))]
43-
GetClusterUid {},
42+
GetClusterUid {
43+
source: crate::framework::controller_utils::Error,
44+
},
4445

4546
#[snafu(display(
4647
"failed to get vectorAggregatorConfigMapName; It must be set if enableVectorAgent is true."
4748
))]
4849
GetVectorAggregatorConfigMapName {},
4950

50-
#[snafu(display("failed to set cluster name"))]
51-
ParseClusterName {
52-
source: crate::framework::macros::attributed_string_type::Error,
53-
},
54-
55-
#[snafu(display("failed to set cluster namespace"))]
56-
ParseClusterNamespace {
57-
source: crate::framework::macros::attributed_string_type::Error,
58-
},
59-
60-
#[snafu(display("failed to set UID"))]
61-
ParseClusterUid {
62-
source: crate::framework::macros::attributed_string_type::Error,
63-
},
64-
6551
#[snafu(display("failed to parse environment variable"))]
6652
ParseEnvironmentVariable {
6753
source: crate::framework::builder::pod::container::Error,
@@ -94,7 +80,7 @@ pub enum Error {
9480

9581
#[snafu(display("termination grace period is too long (got {duration}, maximum allowed is {max})", max = Duration::from_secs(i64::MAX as u64)))]
9682
TerminationGracePeriodTooLong {
97-
source: TryFromIntError,
83+
source: std::num::TryFromIntError,
9884
duration: Duration,
9985
},
10086
}
@@ -114,14 +100,9 @@ pub fn validate(
114100
context_names: &ContextNames,
115101
cluster: &v1alpha1::OpenSearchCluster,
116102
) -> Result<ValidatedCluster> {
117-
let raw_cluster_name = cluster.meta().name.clone().context(GetClusterNameSnafu)?;
118-
let cluster_name = ClusterName::from_str(&raw_cluster_name).context(ParseClusterNameSnafu)?;
119-
120-
let raw_namespace = cluster.namespace().context(GetClusterNamespaceSnafu)?;
121-
let namespace = NamespaceName::from_str(&raw_namespace).context(ParseClusterNamespaceSnafu)?;
122-
123-
let raw_uid = cluster.uid().context(GetClusterUidSnafu)?;
124-
let uid = Uid::from_str(&raw_uid).context(ParseClusterUidSnafu)?;
103+
let cluster_name = get_cluster_name(cluster).context(GetClusterNameSnafu)?;
104+
let namespace = get_namespace(cluster).context(GetClusterNamespaceSnafu)?;
105+
let uid = get_uid(cluster).context(GetClusterUidSnafu)?;
125106

126107
let product_image = cluster
127108
.spec
@@ -541,14 +522,6 @@ mod tests {
541522
);
542523
}
543524

544-
#[test]
545-
fn test_validate_err_parse_cluster_name() {
546-
test_validate_err(
547-
|cluster| cluster.metadata.name = Some("invalid cluster name".to_owned()),
548-
ErrorDiscriminants::ParseClusterName,
549-
);
550-
}
551-
552525
#[test]
553526
fn test_validate_err_get_cluster_namespace() {
554527
test_validate_err(
@@ -557,14 +530,6 @@ mod tests {
557530
);
558531
}
559532

560-
#[test]
561-
fn test_validate_err_parse_cluster_namespace() {
562-
test_validate_err(
563-
|cluster| cluster.metadata.namespace = Some("invalid cluster namespace".to_owned()),
564-
ErrorDiscriminants::ParseClusterNamespace,
565-
);
566-
}
567-
568533
#[test]
569534
fn test_validate_err_get_cluster_uid() {
570535
test_validate_err(
@@ -573,14 +538,6 @@ mod tests {
573538
);
574539
}
575540

576-
#[test]
577-
fn test_validate_err_parse_cluster_uid() {
578-
test_validate_err(
579-
|cluster| cluster.metadata.uid = Some("invalid cluster UID".to_owned()),
580-
ErrorDiscriminants::ParseClusterUid,
581-
);
582-
}
583-
584541
#[test]
585542
fn test_validate_err_resolve_product_image() {
586543
test_validate_err(

rust/operator-binary/src/framework.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use types::kubernetes::Uid;
2424

2525
pub mod builder;
2626
pub mod cluster_resources;
27+
pub mod controller_utils;
2728
pub mod kvp;
2829
pub mod macros;
2930
pub mod product_logging;
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
//! Helper functions which are not tied to a specific controller step
2+
3+
use std::str::FromStr;
4+
5+
use snafu::{OptionExt, ResultExt, Snafu};
6+
use stackable_operator::kube::runtime::reflector::Lookup;
7+
use strum::{EnumDiscriminants, IntoStaticStr};
8+
9+
use crate::framework::types::{
10+
kubernetes::{NamespaceName, Uid},
11+
operator::ClusterName,
12+
};
13+
14+
#[derive(Snafu, Debug, EnumDiscriminants)]
15+
#[strum_discriminants(derive(IntoStaticStr))]
16+
pub enum Error {
17+
#[snafu(display("failed to get the cluster name"))]
18+
GetClusterName {},
19+
20+
#[snafu(display("failed to get the namespace"))]
21+
GetNamespace {},
22+
23+
#[snafu(display("failed to get the UID"))]
24+
GetUid {},
25+
26+
#[snafu(display("failed to set the cluster name"))]
27+
ParseClusterName {
28+
source: crate::framework::macros::attributed_string_type::Error,
29+
},
30+
31+
#[snafu(display("failed to set the namespace"))]
32+
ParseNamespace {
33+
source: crate::framework::macros::attributed_string_type::Error,
34+
},
35+
36+
#[snafu(display("failed to set the UID"))]
37+
ParseUid {
38+
source: crate::framework::macros::attributed_string_type::Error,
39+
},
40+
}
41+
42+
type Result<T, E = Error> = std::result::Result<T, E>;
43+
44+
/// Get the cluster name from the given resource
45+
pub fn get_cluster_name(cluster: &impl Lookup) -> Result<ClusterName> {
46+
let raw_cluster_name = cluster.name().context(GetClusterNameSnafu)?;
47+
let cluster_name = ClusterName::from_str(&raw_cluster_name).context(ParseClusterNameSnafu)?;
48+
49+
Ok(cluster_name)
50+
}
51+
52+
/// Get the namespace from the given resource
53+
pub fn get_namespace(resource: &impl Lookup) -> Result<NamespaceName> {
54+
let raw_namespace = resource.namespace().context(GetNamespaceSnafu)?;
55+
let namespace = NamespaceName::from_str(&raw_namespace).context(ParseNamespaceSnafu)?;
56+
57+
Ok(namespace)
58+
}
59+
60+
/// Get the UID from the given resource
61+
pub fn get_uid(resource: &impl Lookup) -> Result<Uid> {
62+
let raw_uid = resource.uid().context(GetUidSnafu)?;
63+
let uid = Uid::from_str(&raw_uid).context(ParseUidSnafu)?;
64+
65+
Ok(uid)
66+
}
67+
68+
#[cfg(test)]
69+
mod tests {
70+
use stackable_operator::kube::runtime::reflector::Lookup;
71+
use uuid::uuid;
72+
73+
use super::{ErrorDiscriminants, get_cluster_name, get_namespace, get_uid};
74+
use crate::framework::types::{
75+
kubernetes::{NamespaceName, Uid},
76+
operator::ClusterName,
77+
};
78+
79+
#[derive(Debug, Default)]
80+
struct TestResource {
81+
name: Option<&'static str>,
82+
namespace: Option<&'static str>,
83+
uid: Option<&'static str>,
84+
}
85+
86+
impl Lookup for TestResource {
87+
type DynamicType = ();
88+
89+
fn kind(_dyntype: &Self::DynamicType) -> std::borrow::Cow<'_, str> {
90+
"TestResource".into()
91+
}
92+
93+
fn group(_dyntype: &Self::DynamicType) -> std::borrow::Cow<'_, str> {
94+
"stackable.tech".into()
95+
}
96+
97+
fn version(_dyntype: &Self::DynamicType) -> std::borrow::Cow<'_, str> {
98+
"v1".into()
99+
}
100+
101+
fn plural(_dyntype: &Self::DynamicType) -> std::borrow::Cow<'_, str> {
102+
"testresources".into()
103+
}
104+
105+
fn name(&self) -> Option<std::borrow::Cow<'_, str>> {
106+
self.name.map(std::borrow::Cow::Borrowed)
107+
}
108+
109+
fn namespace(&self) -> Option<std::borrow::Cow<'_, str>> {
110+
self.namespace.map(std::borrow::Cow::Borrowed)
111+
}
112+
113+
fn resource_version(&self) -> Option<std::borrow::Cow<'_, str>> {
114+
Some("1".into())
115+
}
116+
117+
fn uid(&self) -> Option<std::borrow::Cow<'_, str>> {
118+
self.uid.map(std::borrow::Cow::Borrowed)
119+
}
120+
}
121+
122+
#[test]
123+
fn test_get_cluster_name() {
124+
assert_eq!(
125+
ClusterName::from_str_unsafe("test-cluster"),
126+
get_cluster_name(&TestResource {
127+
name: Some("test-cluster"),
128+
..TestResource::default()
129+
})
130+
.expect("should contain a valid cluster name")
131+
);
132+
133+
assert_eq!(
134+
Err(ErrorDiscriminants::GetClusterName),
135+
get_cluster_name(&TestResource {
136+
name: None,
137+
..TestResource::default()
138+
})
139+
.map_err(ErrorDiscriminants::from)
140+
);
141+
142+
assert_eq!(
143+
Err(ErrorDiscriminants::ParseClusterName),
144+
get_cluster_name(&TestResource {
145+
name: Some("invalid cluster name"),
146+
..TestResource::default()
147+
})
148+
.map_err(ErrorDiscriminants::from)
149+
);
150+
}
151+
152+
#[test]
153+
fn test_get_namespace() {
154+
assert_eq!(
155+
NamespaceName::from_str_unsafe("test-namespace"),
156+
get_namespace(&TestResource {
157+
namespace: Some("test-namespace"),
158+
..TestResource::default()
159+
})
160+
.expect("should contain a valid namespace")
161+
);
162+
163+
assert_eq!(
164+
Err(ErrorDiscriminants::GetNamespace),
165+
get_namespace(&TestResource {
166+
namespace: None,
167+
..TestResource::default()
168+
})
169+
.map_err(ErrorDiscriminants::from)
170+
);
171+
172+
assert_eq!(
173+
Err(ErrorDiscriminants::ParseNamespace),
174+
get_namespace(&TestResource {
175+
namespace: Some("invalid namespace"),
176+
..TestResource::default()
177+
})
178+
.map_err(ErrorDiscriminants::from)
179+
);
180+
}
181+
182+
#[test]
183+
fn test_get_uid() {
184+
assert_eq!(
185+
Uid::from(uuid!("e6ac237d-a6d4-43a1-8135-f36506110912")),
186+
get_uid(&TestResource {
187+
uid: Some("e6ac237d-a6d4-43a1-8135-f36506110912"),
188+
..TestResource::default()
189+
})
190+
.expect("should contain a valid UID")
191+
);
192+
193+
assert_eq!(
194+
Err(ErrorDiscriminants::GetUid),
195+
get_uid(&TestResource {
196+
uid: None,
197+
..TestResource::default()
198+
})
199+
.map_err(ErrorDiscriminants::from)
200+
);
201+
202+
assert_eq!(
203+
Err(ErrorDiscriminants::ParseUid),
204+
get_uid(&TestResource {
205+
uid: Some("invalid UID"),
206+
..TestResource::default()
207+
})
208+
.map_err(ErrorDiscriminants::from)
209+
);
210+
}
211+
}

0 commit comments

Comments
 (0)