Skip to content

Commit b02d255

Browse files
authored
fix: split fetch and validate auth class steps (#1036)
* fix: split fetch and validate auth class steps * fix: rename resolved_authentication_classes to authentication_classes in dereference step. * fix: rename ResolvedAuth... to DereferencedAuthenticationClass. * fix: rename missing resolved leftovers.
1 parent 9a98434 commit b02d255

7 files changed

Lines changed: 93 additions & 76 deletions

File tree

rust/operator-binary/src/crd/authentication.rs

Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -51,32 +51,64 @@ pub mod versioned {
5151
}
5252

5353
#[derive(Clone, Debug)]
54-
/// Helper struct that contains resolved AuthenticationClasses to reduce network API calls.
55-
pub struct ResolvedAuthenticationClasses {
56-
resolved_authentication_classes: Vec<core::v1alpha1::AuthenticationClass>,
54+
/// Helper struct that contains dereferenced AuthenticationClasses to reduce network API calls.
55+
pub struct DereferencedAuthenticationClasses {
56+
dereferenced_authentication_classes: Vec<core::v1alpha1::AuthenticationClass>,
5757
}
5858

59-
impl ResolvedAuthenticationClasses {
59+
impl DereferencedAuthenticationClasses {
60+
/// Fetch the referenced AuthenticationClasses from the Kubernetes API without validating them.
61+
///
62+
/// Call [`Self::validate`] on the result to enforce the constraints documented there.
63+
pub async fn fetch_references(
64+
client: &Client,
65+
auth_classes: &Vec<v1alpha1::ZookeeperAuthentication>,
66+
) -> Result<DereferencedAuthenticationClasses, Error> {
67+
let mut dereferenced_authentication_classes: Vec<core::v1alpha1::AuthenticationClass> =
68+
vec![];
69+
70+
for auth_class in auth_classes {
71+
dereferenced_authentication_classes.push(
72+
core::v1alpha1::AuthenticationClass::resolve(
73+
client,
74+
&auth_class.authentication_class,
75+
)
76+
.await
77+
.context(AuthenticationClassRetrievalSnafu {
78+
authentication_class: ObjectRef::<core::v1alpha1::AuthenticationClass>::new(
79+
&auth_class.authentication_class,
80+
),
81+
})?,
82+
);
83+
}
84+
85+
Ok(DereferencedAuthenticationClasses {
86+
dereferenced_authentication_classes,
87+
})
88+
}
89+
6090
/// Return the (first) TLS `AuthenticationClass` if available
6191
pub fn get_tls_authentication_class(&self) -> Option<&core::v1alpha1::AuthenticationClass> {
62-
self.resolved_authentication_classes.iter().find(|auth| {
63-
matches!(
64-
auth.spec.provider,
65-
core::v1alpha1::AuthenticationClassProvider::Tls(_)
66-
)
67-
})
92+
self.dereferenced_authentication_classes
93+
.iter()
94+
.find(|auth| {
95+
matches!(
96+
auth.spec.provider,
97+
core::v1alpha1::AuthenticationClassProvider::Tls(_)
98+
)
99+
})
68100
}
69101

70-
/// Validates the resolved AuthenticationClasses.
102+
/// Validates the dereferenced AuthenticationClasses.
71103
/// Currently errors out if:
72104
/// - More than one AuthenticationClass was provided
73105
/// - AuthenticationClass mechanism was not supported
74106
pub fn validate(&self) -> Result<Self, Error> {
75-
if self.resolved_authentication_classes.len() > 1 {
107+
if self.dereferenced_authentication_classes.len() > 1 {
76108
return Err(Error::MultipleAuthenticationClassesProvided);
77109
}
78110

79-
for auth_class in &self.resolved_authentication_classes {
111+
for auth_class in &self.dereferenced_authentication_classes {
80112
match &auth_class.spec.provider {
81113
core::v1alpha1::AuthenticationClassProvider::Tls(_) => {}
82114
core::v1alpha1::AuthenticationClassProvider::Ldap(_)
@@ -96,36 +128,8 @@ impl ResolvedAuthenticationClasses {
96128

97129
/// USE ONLY IN TESTS! We can not put it behind `#[cfg(test)]` because of <https://github.com/rust-lang/cargo/issues/8379>
98130
pub fn new_for_tests() -> Self {
99-
ResolvedAuthenticationClasses {
100-
resolved_authentication_classes: vec![],
131+
DereferencedAuthenticationClasses {
132+
dereferenced_authentication_classes: vec![],
101133
}
102134
}
103135
}
104-
105-
/// Resolve provided AuthenticationClasses via API calls and validate the contents.
106-
/// Currently errors out if:
107-
/// - AuthenticationClass could not be resolved
108-
/// - Validation failed
109-
pub async fn resolve_authentication_classes(
110-
client: &Client,
111-
auth_classes: &Vec<v1alpha1::ZookeeperAuthentication>,
112-
) -> Result<ResolvedAuthenticationClasses, Error> {
113-
let mut resolved_authentication_classes: Vec<core::v1alpha1::AuthenticationClass> = vec![];
114-
115-
for auth_class in auth_classes {
116-
resolved_authentication_classes.push(
117-
core::v1alpha1::AuthenticationClass::resolve(client, &auth_class.authentication_class)
118-
.await
119-
.context(AuthenticationClassRetrievalSnafu {
120-
authentication_class: ObjectRef::<core::v1alpha1::AuthenticationClass>::new(
121-
&auth_class.authentication_class,
122-
),
123-
})?,
124-
);
125-
}
126-
127-
ResolvedAuthenticationClasses {
128-
resolved_authentication_classes,
129-
}
130-
.validate()
131-
}

rust/operator-binary/src/crd/security.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use stackable_operator::{
2626
};
2727

2828
use crate::{
29-
crd::{authentication::ResolvedAuthenticationClasses, tls, v1alpha1},
29+
crd::{authentication::DereferencedAuthenticationClasses, tls, v1alpha1},
3030
zk_controller::LISTENER_VOLUME_NAME,
3131
};
3232

@@ -51,7 +51,7 @@ pub enum Error {
5151

5252
/// Helper struct combining TLS settings for server and quorum with the resolved AuthenticationClasses
5353
pub struct ZookeeperSecurity {
54-
resolved_authentication_classes: ResolvedAuthenticationClasses,
54+
resolved_authentication_classes: DereferencedAuthenticationClasses,
5555
server_secret_class: Option<String>,
5656
quorum_secret_class: String,
5757
}
@@ -90,11 +90,11 @@ impl ZookeeperSecurity {
9090
pub const SYSTEM_TRUST_STORE_DIR: &'static str = "/etc/pki/java/cacerts";
9191

9292
/// Build a `ZookeeperSecurity` from a [`v1alpha1::ZookeeperCluster`] and already-resolved
93-
/// [`ResolvedAuthenticationClasses`]. Synchronous; intended to be called from the validate
93+
/// [`DereferencedAuthenticationClasses`]. Synchronous; intended to be called from the validate
9494
/// step of the controllers.
9595
pub fn new(
9696
zk: &v1alpha1::ZookeeperCluster,
97-
resolved_authentication_classes: ResolvedAuthenticationClasses,
97+
resolved_authentication_classes: DereferencedAuthenticationClasses,
9898
) -> Self {
9999
ZookeeperSecurity {
100100
resolved_authentication_classes,
@@ -351,7 +351,7 @@ impl ZookeeperSecurity {
351351
/// USE ONLY IN TESTS! We can not put it behind `#[cfg(test)]` because of <https://github.com/rust-lang/cargo/issues/8379>
352352
pub fn new_for_tests() -> Self {
353353
ZookeeperSecurity {
354-
resolved_authentication_classes: ResolvedAuthenticationClasses::new_for_tests(),
354+
resolved_authentication_classes: DereferencedAuthenticationClasses::new_for_tests(),
355355
server_secret_class: Some("tls".to_owned()),
356356
quorum_secret_class: "tls".to_string(),
357357
}

rust/operator-binary/src/zk_controller/dereference.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,36 +9,37 @@ use snafu::{ResultExt, Snafu};
99
use stackable_operator::client::Client;
1010

1111
use crate::crd::{
12-
authentication::{self, ResolvedAuthenticationClasses},
12+
authentication::{self, DereferencedAuthenticationClasses},
1313
v1alpha1,
1414
};
1515

1616
#[derive(Snafu, Debug)]
1717
pub enum Error {
18-
#[snafu(display("failed to resolve authentication classes"))]
19-
ResolveAuthenticationClasses { source: authentication::Error },
18+
#[snafu(display("failed to fetch authentication classes"))]
19+
FetchAuthenticationClasses { source: authentication::Error },
2020
}
2121

2222
type Result<T, E = Error> = std::result::Result<T, E>;
2323

24-
/// Kubernetes objects referenced from the [`v1alpha1::ZookeeperCluster`] spec, already fetched.
24+
/// Kubernetes objects referenced from the [`v1alpha1::ZookeeperCluster`] spec, already fetched but
25+
/// not yet validated.
2526
pub struct DereferencedObjects {
26-
pub resolved_authentication_classes: ResolvedAuthenticationClasses,
27+
pub authentication_classes: DereferencedAuthenticationClasses,
2728
}
2829

2930
/// Fetches all Kubernetes objects referenced from the [`v1alpha1::ZookeeperCluster`] spec.
3031
pub async fn dereference(
3132
client: &Client,
3233
zk: &v1alpha1::ZookeeperCluster,
3334
) -> Result<DereferencedObjects> {
34-
let resolved_authentication_classes = authentication::resolve_authentication_classes(
35+
let authentication_classes = DereferencedAuthenticationClasses::fetch_references(
3536
client,
3637
&zk.spec.cluster_config.authentication,
3738
)
3839
.await
39-
.context(ResolveAuthenticationClassesSnafu)?;
40+
.context(FetchAuthenticationClassesSnafu)?;
4041

4142
Ok(DereferencedObjects {
42-
resolved_authentication_classes,
43+
authentication_classes,
4344
})
4445
}

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use stackable_operator::{
1717
use crate::{
1818
crd::{
1919
CONTAINER_IMAGE_BASE_NAME, JVM_SECURITY_PROPERTIES_FILE, ZOOKEEPER_PROPERTIES_FILE,
20-
ZookeeperRole, security::ZookeeperSecurity, v1alpha1,
20+
ZookeeperRole, authentication, security::ZookeeperSecurity, v1alpha1,
2121
},
2222
zk_controller::dereference::DereferencedObjects,
2323
};
@@ -29,6 +29,9 @@ pub enum Error {
2929
source: product_image_selection::Error,
3030
},
3131

32+
#[snafu(display("failed to validate authentication classes"))]
33+
InvalidAuthenticationClassConfiguration { source: authentication::Error },
34+
3235
#[snafu(display("object defines no server role"))]
3336
NoServerRole,
3437

@@ -69,10 +72,12 @@ pub fn validate(
6972
)
7073
.context(ResolveProductImageSnafu)?;
7174

72-
let zookeeper_security = ZookeeperSecurity::new(
73-
zk,
74-
dereferenced_objects.resolved_authentication_classes.clone(),
75-
);
75+
let resolved_authentication_classes = dereferenced_objects
76+
.authentication_classes
77+
.validate()
78+
.context(InvalidAuthenticationClassConfigurationSnafu)?;
79+
80+
let zookeeper_security = ZookeeperSecurity::new(zk, resolved_authentication_classes);
7681

7782
let validated_role_config =
7883
validated_product_config(zk, &resolved_product_image.product_version, product_config)?;

rust/operator-binary/src/znode_controller.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ pub async fn reconcile_znode(
267267
// block finalizer removal.
268268
let zookeeper_security = ZookeeperSecurity::new(
269269
&dereferenced.zk,
270-
dereferenced.resolved_authentication_classes.clone(),
270+
dereferenced.authentication_classes.clone(),
271271
);
272272
reconcile_cleanup(client, dereferenced.zk, &zookeeper_security, &znode_path)
273273
.await

rust/operator-binary/src/znode_controller/dereference.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//! The dereference step in the ZookeeperZnode controller.
22
//!
33
//! Fetches the parent [`v1alpha1::ZookeeperCluster`] referenced by the znode's
4-
//! `spec.clusterRef`, plus the [`ResolvedAuthenticationClasses`] of that cluster. Both Apply
5-
//! and Cleanup paths in `reconcile_znode` share this output.
4+
//! `spec.clusterRef`, plus the [`DereferencedAuthenticationClasses`] of that cluster. Both Apply
5+
//! and Cleanup paths in `reconcile_znode` share this output. Synchronous validation of the
6+
//! fetched objects happens in the validate step.
67
78
use snafu::{ResultExt, Snafu};
89
use stackable_operator::{
@@ -11,7 +12,7 @@ use stackable_operator::{
1112
};
1213

1314
use crate::crd::{
14-
authentication::{self, ResolvedAuthenticationClasses},
15+
authentication::{self, DereferencedAuthenticationClasses},
1516
v1alpha1,
1617
};
1718

@@ -32,16 +33,16 @@ pub enum Error {
3233
zk: ObjectRef<v1alpha1::ZookeeperCluster>,
3334
},
3435

35-
#[snafu(display("failed to resolve authentication classes"))]
36-
ResolveAuthenticationClasses { source: authentication::Error },
36+
#[snafu(display("failed to fetch authentication classes"))]
37+
FetchAuthenticationClasses { source: authentication::Error },
3738
}
3839

3940
type Result<T, E = Error> = std::result::Result<T, E>;
4041

4142
/// Kubernetes objects referenced from the [`v1alpha1::ZookeeperZnode`] spec, already fetched.
4243
pub struct DereferencedObjects {
4344
pub zk: v1alpha1::ZookeeperCluster,
44-
pub resolved_authentication_classes: ResolvedAuthenticationClasses,
45+
pub authentication_classes: DereferencedAuthenticationClasses,
4546
}
4647

4748
/// Fetches all Kubernetes objects referenced from the [`v1alpha1::ZookeeperZnode`] spec.
@@ -51,16 +52,16 @@ pub async fn dereference(
5152
) -> Result<DereferencedObjects> {
5253
let zk = find_zk_of_znode(client, znode).await?;
5354

54-
let resolved_authentication_classes = authentication::resolve_authentication_classes(
55+
let authentication_classes = DereferencedAuthenticationClasses::fetch_references(
5556
client,
5657
&zk.spec.cluster_config.authentication,
5758
)
5859
.await
59-
.context(ResolveAuthenticationClassesSnafu)?;
60+
.context(FetchAuthenticationClassesSnafu)?;
6061

6162
Ok(DereferencedObjects {
6263
zk,
63-
resolved_authentication_classes,
64+
authentication_classes,
6465
})
6566
}
6667

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use stackable_operator::{
1010
};
1111

1212
use crate::{
13-
crd::{CONTAINER_IMAGE_BASE_NAME, security::ZookeeperSecurity, v1alpha1},
13+
crd::{CONTAINER_IMAGE_BASE_NAME, authentication, security::ZookeeperSecurity, v1alpha1},
1414
znode_controller::dereference::DereferencedObjects,
1515
};
1616

@@ -20,6 +20,9 @@ pub enum Error {
2020
ResolveProductImage {
2121
source: product_image_selection::Error,
2222
},
23+
24+
#[snafu(display("failed to validate authentication classes"))]
25+
InvalidAuthenticationClassConfiguration { source: authentication::Error },
2326
}
2427

2528
type Result<T, E = Error> = std::result::Result<T, E>;
@@ -47,10 +50,13 @@ pub fn validate(
4750
)
4851
.context(ResolveProductImageSnafu)?;
4952

50-
let zookeeper_security = ZookeeperSecurity::new(
51-
&dereferenced_objects.zk,
52-
dereferenced_objects.resolved_authentication_classes.clone(),
53-
);
53+
let resolved_authentication_classes = dereferenced_objects
54+
.authentication_classes
55+
.validate()
56+
.context(InvalidAuthenticationClassConfigurationSnafu)?;
57+
58+
let zookeeper_security =
59+
ZookeeperSecurity::new(&dereferenced_objects.zk, resolved_authentication_classes);
5460

5561
Ok(ValidatedInputs {
5662
resolved_product_image,

0 commit comments

Comments
 (0)