Skip to content

Commit cad0c79

Browse files
committed
feat: extract dereference and validate steps
1 parent 343d350 commit cad0c79

3 files changed

Lines changed: 155 additions & 63 deletions

File tree

rust/operator-binary/src/controller.rs

Lines changed: 35 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use stackable_operator::{
2626
cli::OperatorEnvironmentOptions,
2727
cluster_resources::{ClusterResourceApplyStrategy, ClusterResources},
2828
commons::{
29-
product_image_selection::{self, ResolvedProductImage},
29+
product_image_selection::ResolvedProductImage,
3030
rbac::build_rbac_resources,
3131
secret_class::{
3232
SecretClassVolume, SecretClassVolumeProvisionParts, SecretClassVolumeScope,
@@ -54,7 +54,6 @@ use stackable_operator::{
5454
kvp::{LabelError, Labels, ObjectLabels},
5555
logging::controller::ReconcilerError,
5656
memory::{BinaryMultiple, MemoryQuantity},
57-
product_config_utils::{transform_all_roles_to_config, validate_all_roles_and_groups_config},
5857
product_logging::{
5958
self,
6059
framework::{
@@ -89,6 +88,9 @@ use crate::{
8988
},
9089
};
9190

91+
mod dereference;
92+
mod validate;
93+
9294
pub const OPA_CONTROLLER_NAME: &str = "opacluster";
9395
pub const OPA_FULL_CONTROLLER_NAME: &str = concatcp!(OPA_CONTROLLER_NAME, '.', OPERATOR_NAME);
9496

@@ -230,11 +232,6 @@ pub enum Error {
230232
source: stackable_operator::client::Error,
231233
},
232234

233-
#[snafu(display("invalid product config"))]
234-
InvalidProductConfig {
235-
source: stackable_operator::product_config_utils::Error,
236-
},
237-
238235
#[snafu(display("object is missing metadata to build owner reference"))]
239236
ObjectMissingMetadataForOwnerRef {
240237
source: stackable_operator::builder::meta::Error,
@@ -248,11 +245,6 @@ pub enum Error {
248245
source: stackable_operator::cluster_resources::Error,
249246
},
250247

251-
#[snafu(display("failed to transform configs"))]
252-
ProductConfigTransform {
253-
source: stackable_operator::product_config_utils::Error,
254-
},
255-
256248
#[snafu(display("failed to resolve and merge config for role and role group"))]
257249
FailedToResolveConfig { source: crate::crd::Error },
258250

@@ -332,14 +324,15 @@ pub enum Error {
332324
source: builder::pod::container::Error,
333325
},
334326

335-
#[snafu(display("failed to resolve product image"))]
336-
ResolveProductImage {
337-
source: product_image_selection::Error,
338-
},
339-
340327
#[snafu(display("failed to build service"))]
341328
BuildService { source: service::Error },
342329

330+
#[snafu(display("failed to dereference resources"))]
331+
Dereference { source: dereference::Error },
332+
333+
#[snafu(display("failed to validate cluster"))]
334+
ValidateCluster { source: validate::Error },
335+
343336
#[snafu(display("failed to build TLS volume"))]
344337
TlsVolumeBuild {
345338
source: builder::pod::volume::SecretOperatorVolumeSourceBuilderError,
@@ -448,15 +441,21 @@ pub async fn reconcile_opa(
448441
let opa_ref = ObjectRef::from_obj(opa);
449442

450443
let client = &ctx.client;
451-
let resolved_product_image = opa
452-
.spec
453-
.image
454-
.resolve(
455-
CONTAINER_IMAGE_BASE_NAME,
456-
&ctx.operator_environment.image_repository,
457-
crate::built_info::PKG_VERSION,
458-
)
459-
.context(ResolveProductImageSnafu)?;
444+
445+
// dereference (client required)
446+
let dereferenced_objects = dereference::dereference(client, opa)
447+
.await
448+
.context(DereferenceSnafu)?;
449+
450+
// validate (no client required)
451+
let validated = validate::validate(
452+
opa,
453+
&dereferenced_objects,
454+
&ctx.operator_environment,
455+
&ctx.product_config,
456+
)
457+
.context(ValidateClusterSnafu)?;
458+
460459
let opa_role = OpaRole::Server;
461460

462461
let mut cluster_resources = ClusterResources::new(
@@ -469,36 +468,14 @@ pub async fn reconcile_opa(
469468
)
470469
.context(FailedToCreateClusterResourcesSnafu)?;
471470

472-
let validated_config = validate_all_roles_and_groups_config(
473-
&resolved_product_image.product_version,
474-
&transform_all_roles_to_config(
475-
opa,
476-
&[(
477-
opa_role.to_string(),
478-
(
479-
vec![
480-
PropertyNameKind::File(CONFIG_FILE.to_string()),
481-
PropertyNameKind::Env,
482-
PropertyNameKind::Cli,
483-
],
484-
opa.spec.servers.clone(),
485-
),
486-
)]
487-
.into(),
488-
)
489-
.context(ProductConfigTransformSnafu)?,
490-
&ctx.product_config,
491-
false,
492-
false,
493-
)
494-
.context(InvalidProductConfigSnafu)?;
495-
let role_server_config = validated_config
471+
let role_server_config = validated
472+
.validated_role_config
496473
.get(&opa_role.to_string())
497474
.map(Cow::Borrowed)
498475
.unwrap_or_default();
499476

500477
let server_role_service =
501-
build_server_role_service(opa, &resolved_product_image).context(BuildServiceSnafu)?;
478+
build_server_role_service(opa, &validated.image).context(BuildServiceSnafu)?;
502479
// required for discovery config map later
503480
let server_role_service = cluster_resources
504481
.add(client, server_role_service)
@@ -534,20 +511,15 @@ pub async fn reconcile_opa(
534511
.merged_config(&opa_role, &rolegroup)
535512
.context(FailedToResolveConfigSnafu)?;
536513

537-
let rg_configmap = build_server_rolegroup_config_map(
538-
opa,
539-
&resolved_product_image,
540-
&rolegroup,
541-
&merged_config,
542-
)?;
543-
let rg_service = build_rolegroup_headless_service(opa, &resolved_product_image, &rolegroup)
514+
let rg_configmap =
515+
build_server_rolegroup_config_map(opa, &validated.image, &rolegroup, &merged_config)?;
516+
let rg_service = build_rolegroup_headless_service(opa, &validated.image, &rolegroup)
517+
.context(BuildServiceSnafu)?;
518+
let rg_metrics_service = build_rolegroup_metrics_service(opa, &validated.image, &rolegroup)
544519
.context(BuildServiceSnafu)?;
545-
let rg_metrics_service =
546-
build_rolegroup_metrics_service(opa, &resolved_product_image, &rolegroup)
547-
.context(BuildServiceSnafu)?;
548520
let rg_daemonset = build_server_rolegroup_daemonset(
549521
opa,
550-
&resolved_product_image,
522+
&validated.image,
551523
&opa_role,
552524
&rolegroup,
553525
rolegroup_config,
@@ -610,7 +582,7 @@ pub async fn reconcile_opa(
610582
for discovery_cm in build_discovery_configmaps(
611583
opa,
612584
opa,
613-
&resolved_product_image,
585+
&validated.image,
614586
&server_role_service,
615587
&client.kubernetes_cluster_info,
616588
)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//! The dereference step in the OpaCluster controller
2+
//!
3+
//! Fetches all Kubernetes objects referenced by the OpaCluster spec and returns them in
4+
//! [`DereferencedObjects`]. This is currently scaffolding — no objects are dereferenced yet.
5+
//! Follow-up work might move existing inline lookups (e.g. the `user_info_fetcher` Secrets and
6+
//! SecretClasses) through here.
7+
8+
use snafu::Snafu;
9+
use stackable_operator::client::Client;
10+
11+
use crate::crd::v1alpha2;
12+
13+
#[derive(Snafu, Debug)]
14+
pub enum Error {}
15+
16+
type Result<T, E = Error> = std::result::Result<T, E>;
17+
18+
/// Kubernetes objects referenced from the OpaCluster spec, already fetched.
19+
pub struct DereferencedObjects {}
20+
21+
/// Fetches all Kubernetes objects referenced from the [`v1alpha2::OpaCluster`] spec.
22+
pub async fn dereference(
23+
_client: &Client,
24+
_opa: &v1alpha2::OpaCluster,
25+
) -> Result<DereferencedObjects> {
26+
Ok(DereferencedObjects {})
27+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//! The validate step in the OpaCluster controller
2+
//!
3+
//! Synchronously validates inputs that don't require a Kubernetes client. Produces
4+
//! [`ValidatedInputs`], consumed by the rest of `reconcile_opa`.
5+
6+
use product_config::{ProductConfigManager, types::PropertyNameKind};
7+
use snafu::{ResultExt, Snafu};
8+
use stackable_operator::{
9+
cli::OperatorEnvironmentOptions,
10+
commons::product_image_selection::{self, ResolvedProductImage},
11+
product_config_utils::{
12+
ValidatedRoleConfigByPropertyKind, transform_all_roles_to_config,
13+
validate_all_roles_and_groups_config,
14+
},
15+
};
16+
17+
use crate::{
18+
controller::dereference::DereferencedObjects,
19+
crd::{OpaRole, v1alpha2},
20+
};
21+
22+
#[derive(Snafu, Debug)]
23+
pub enum Error {
24+
#[snafu(display("failed to resolve product image"))]
25+
ResolveProductImage {
26+
source: product_image_selection::Error,
27+
},
28+
29+
#[snafu(display("failed to transform configs"))]
30+
ProductConfigTransform {
31+
source: stackable_operator::product_config_utils::Error,
32+
},
33+
34+
#[snafu(display("invalid product config"))]
35+
InvalidProductConfig {
36+
source: stackable_operator::product_config_utils::Error,
37+
},
38+
}
39+
40+
type Result<T, E = Error> = std::result::Result<T, E>;
41+
42+
/// Synchronous inputs the rest of `reconcile_opa` needs after dereferencing.
43+
pub struct ValidatedInputs {
44+
pub image: ResolvedProductImage,
45+
pub validated_role_config: ValidatedRoleConfigByPropertyKind,
46+
}
47+
48+
/// Validates the cluster spec and the dereferenced inputs.
49+
pub fn validate(
50+
opa: &v1alpha2::OpaCluster,
51+
_dereferenced_objects: &DereferencedObjects,
52+
operator_environment: &OperatorEnvironmentOptions,
53+
product_config: &ProductConfigManager,
54+
) -> Result<ValidatedInputs> {
55+
let image = opa
56+
.spec
57+
.image
58+
.resolve(
59+
super::CONTAINER_IMAGE_BASE_NAME,
60+
&operator_environment.image_repository,
61+
crate::built_info::PKG_VERSION,
62+
)
63+
.context(ResolveProductImageSnafu)?;
64+
65+
let validated_role_config = validate_all_roles_and_groups_config(
66+
&image.product_version,
67+
&transform_all_roles_to_config(
68+
opa,
69+
&[(
70+
OpaRole::Server.to_string(),
71+
(
72+
vec![
73+
PropertyNameKind::File(super::CONFIG_FILE.to_string()),
74+
PropertyNameKind::Env,
75+
PropertyNameKind::Cli,
76+
],
77+
opa.spec.servers.clone(),
78+
),
79+
)]
80+
.into(),
81+
)
82+
.context(ProductConfigTransformSnafu)?,
83+
product_config,
84+
false,
85+
false,
86+
)
87+
.context(InvalidProductConfigSnafu)?;
88+
89+
Ok(ValidatedInputs {
90+
image,
91+
validated_role_config,
92+
})
93+
}

0 commit comments

Comments
 (0)