Skip to content

Commit e6a9197

Browse files
committed
refactor: build_pdb returns PDB via infallible v2 builder; add typed name helpers
1 parent 09c8d1a commit e6a9197

4 files changed

Lines changed: 62 additions & 54 deletions

File tree

rust/operator-binary/src/controller.rs

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use stackable_operator::{
4545
role_group_utils::ResourceNames,
4646
types::{
4747
kubernetes::{ContainerName, VolumeName},
48-
operator::RoleGroupName,
48+
operator::{ControllerName, OperatorName, ProductName, RoleGroupName},
4949
},
5050
},
5151
};
@@ -57,7 +57,7 @@ use crate::{
5757
LISTENER_VOLUME_DIR, LISTENER_VOLUME_NAME, build_group_listener,
5858
build_group_listener_pvc, group_listener_name, secret_volume_listener_scope,
5959
},
60-
pdb::add_pdbs,
60+
pdb::build_pdb,
6161
service::{build_rolegroup_headless_service, build_rolegroup_metrics_service},
6262
},
6363
crd::{
@@ -85,6 +85,22 @@ pub const FULL_CONTROLLER_NAME: &str = concatcp!(DRUID_CONTROLLER_NAME, '.', OPE
8585

8686
pub(super) const CONTAINER_IMAGE_BASE_NAME: &str = "druid";
8787

88+
/// The product name (`druid`) as a type-safe label value.
89+
pub(crate) fn product_name() -> ProductName {
90+
ProductName::from_str(APP_NAME).expect("'druid' is a valid product name")
91+
}
92+
93+
/// The operator name as a type-safe label value.
94+
pub(crate) fn operator_name() -> OperatorName {
95+
OperatorName::from_str(OPERATOR_NAME).expect("the operator name is a valid label value")
96+
}
97+
98+
/// The controller name as a type-safe label value.
99+
pub(crate) fn controller_name() -> ControllerName {
100+
ControllerName::from_str(DRUID_CONTROLLER_NAME)
101+
.expect("the controller name is a valid label value")
102+
}
103+
88104
// volume names
89105
const DRUID_CONFIG_VOLUME_NAME: &str = "config";
90106
const HDFS_CONFIG_VOLUME_NAME: &str = "hdfs";
@@ -192,9 +208,9 @@ pub enum Error {
192208
source: stackable_operator::commons::rbac::Error,
193209
},
194210

195-
#[snafu(display("failed to create PodDisruptionBudget"))]
196-
FailedToCreatePdb {
197-
source: crate::controller::build::resource::pdb::Error,
211+
#[snafu(display("failed to apply PodDisruptionBudget"))]
212+
ApplyPdb {
213+
source: stackable_operator::cluster_resources::Error,
198214
},
199215

200216
#[snafu(display("failed to configure graceful shutdown"))]
@@ -417,15 +433,16 @@ pub async fn reconcile_druid(
417433

418434
let role_config = druid.generic_role_config(druid_role);
419435

420-
add_pdbs(
436+
if let Some(pdb) = build_pdb(
421437
&role_config.pod_disruption_budget,
422-
druid,
438+
&validated_cluster,
423439
druid_role,
424-
client,
425-
&mut cluster_resources,
426-
)
427-
.await
428-
.context(FailedToCreatePdbSnafu)?;
440+
) {
441+
cluster_resources
442+
.add(client, pdb)
443+
.await
444+
.context(ApplyPdbSnafu)?;
445+
}
429446
}
430447

431448
let cluster_operation_cond_builder =

rust/operator-binary/src/controller/build/resource/pdb.rs

Lines changed: 19 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,24 @@
1-
use snafu::{ResultExt, Snafu};
1+
use std::str::FromStr;
2+
23
use stackable_operator::{
3-
builder::pdb::PodDisruptionBudgetBuilder, client::Client, cluster_resources::ClusterResources,
4-
commons::pdb::PdbConfig, kube::ResourceExt,
4+
commons::pdb::PdbConfig,
5+
k8s_openapi::api::policy::v1::PodDisruptionBudget,
6+
v2::{builder::pdb::pod_disruption_budget_builder_with_role, types::operator::RoleName},
57
};
68

79
use crate::{
8-
controller::DRUID_CONTROLLER_NAME,
9-
crd::{APP_NAME, DruidRole, OPERATOR_NAME, v1alpha1},
10+
controller::{controller_name, operator_name, product_name, validate::ValidatedCluster},
11+
crd::DruidRole,
1012
};
1113

12-
#[derive(Snafu, Debug)]
13-
pub enum Error {
14-
#[snafu(display("Cannot create PodDisruptionBudget for role [{role}]"))]
15-
CreatePdb {
16-
source: stackable_operator::builder::pdb::Error,
17-
role: String,
18-
},
19-
#[snafu(display("Cannot apply PodDisruptionBudget [{name}]"))]
20-
ApplyPdb {
21-
source: stackable_operator::cluster_resources::Error,
22-
name: String,
23-
},
24-
}
25-
26-
pub async fn add_pdbs(
14+
/// Builds the [`PodDisruptionBudget`] for the given `role`, or `None` if PDBs are disabled.
15+
pub fn build_pdb(
2716
pdb: &PdbConfig,
28-
druid: &v1alpha1::DruidCluster,
17+
cluster: &ValidatedCluster,
2918
role: &DruidRole,
30-
client: &Client,
31-
cluster_resources: &mut ClusterResources<'_>,
32-
) -> Result<(), Error> {
19+
) -> Option<PodDisruptionBudget> {
3320
if !pdb.enabled {
34-
return Ok(());
21+
return None;
3522
}
3623
let max_unavailable = pdb.max_unavailable.unwrap_or(match role {
3724
DruidRole::Broker => max_unavailable_brokers(),
@@ -40,25 +27,17 @@ pub async fn add_pdbs(
4027
DruidRole::MiddleManager => max_unavailable_middle_managers(),
4128
DruidRole::Router => max_unavailable_routers(),
4229
});
43-
let pdb = PodDisruptionBudgetBuilder::new_with_role(
44-
druid,
45-
APP_NAME,
46-
&role.to_string(),
47-
OPERATOR_NAME,
48-
DRUID_CONTROLLER_NAME,
30+
let pdb = pod_disruption_budget_builder_with_role(
31+
cluster,
32+
&product_name(),
33+
&RoleName::from_str(&role.to_string()).expect("a DruidRole is a valid role name"),
34+
&operator_name(),
35+
&controller_name(),
4936
)
50-
.with_context(|_| CreatePdbSnafu {
51-
role: role.to_string(),
52-
})?
5337
.with_max_unavailable(max_unavailable)
5438
.build();
55-
let pdb_name = pdb.name_any();
56-
cluster_resources
57-
.add(client, pdb)
58-
.await
59-
.with_context(|_| ApplyPdbSnafu { name: pdb_name })?;
6039

61-
Ok(())
40+
Some(pdb)
6241
}
6342

6443
fn max_unavailable_brokers() -> u16 {

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use stackable_operator::{
1414
k8s_openapi::api::core::v1::Volume,
1515
kube::{Resource, api::ObjectMeta},
1616
v2::{
17-
HasName, HasUid,
17+
HasName, HasUid, NameIsValidLabelValue,
1818
controller_utils::{get_cluster_name, get_namespace, get_uid},
1919
role_group_utils::ResourceNames,
2020
types::{
@@ -195,6 +195,12 @@ impl HasUid for ValidatedCluster {
195195
}
196196
}
197197

198+
impl NameIsValidLabelValue for ValidatedCluster {
199+
fn to_label_value(&self) -> String {
200+
self.name.to_label_value()
201+
}
202+
}
203+
198204
/// Validates the cluster spec and the dereferenced inputs.
199205
pub fn validate(
200206
druid: &v1alpha1::DruidCluster,

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,11 +447,17 @@ impl v1alpha1::DruidCluster {
447447
s3_ingestion || s3_storage
448448
}
449449

450-
/// Merges and validates all role groups of the given role.
450+
/// Merges and validates all role groups of the given role. Invoked from the validate step
451+
/// (`controller::validate`).
451452
///
452453
/// All four override categories (config / env / cli / pod) are merged by
453454
/// [`with_validated_config`] (role group wins over role); the typed per-role config is then
454455
/// erased to the shared [`ValidatedDruidConfig`] view consumed by the build step.
456+
///
457+
/// This lives in `crate::crd` and is a `macro_rules!` rather than a generic function on purpose: the erasure
458+
/// reads the per-role configs' private `resources` field and calls their private
459+
/// `default_config`, and the five roles wrap *different* `resources` types into different
460+
/// [`RoleResource`] variants.
455461
pub fn merged_role(
456462
&self,
457463
role: &DruidRole,

0 commit comments

Comments
 (0)