Skip to content

Commit db4689c

Browse files
committed
refactor: move to v2 types for ResourceNames, labels, ownerrefs. Reduce RoleGroupRef usage.
1 parent 9e5c83f commit db4689c

11 files changed

Lines changed: 468 additions & 298 deletions

File tree

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,15 @@ pub fn get_affinity(cluster_name: &str, role: &ZookeeperRole) -> StackableAffini
2525
#[cfg(test)]
2626
mod tests {
2727

28-
use std::collections::BTreeMap;
28+
use std::{collections::BTreeMap, str::FromStr};
2929

3030
use stackable_operator::{
3131
commons::affinity::StackableAffinity,
3232
k8s_openapi::{
3333
api::core::v1::{PodAffinityTerm, PodAntiAffinity, WeightedPodAffinityTerm},
3434
apimachinery::pkg::apis::meta::v1::LabelSelector,
3535
},
36+
v2::types::operator::RoleGroupName,
3637
};
3738

3839
use crate::{
@@ -98,7 +99,9 @@ mod tests {
9899
node_selector: None,
99100
};
100101

101-
let affinity = validated_cluster(&zk).role_group_configs[&ZookeeperRole::Server]["default"]
102+
let default_group = RoleGroupName::from_str("default").expect("valid role group name");
103+
let affinity = validated_cluster(&zk).role_group_configs[&ZookeeperRole::Server]
104+
[&default_group]
102105
.config
103106
.affinity
104107
.clone();

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use stackable_operator::{
1414
crd::ClusterRef,
1515
deep_merger::ObjectOverrides,
1616
k8s_openapi::apimachinery::pkg::api::resource::Quantity,
17-
kube::{CustomResource, runtime::reflector::ObjectRef},
17+
kube::{CustomResource, ResourceExt, runtime::reflector::ObjectRef},
1818
product_logging::{self, spec::Logging},
1919
role_utils::{GenericRoleConfig, Role, RoleGroupRef},
2020
schemars::{self, JsonSchema},
@@ -450,7 +450,7 @@ impl v1alpha1::ZookeeperCluster {
450450
) -> Option<String> {
451451
Some(format!(
452452
"{role_listener_name}.{namespace}.svc.{cluster_domain}",
453-
role_listener_name = role_listener_name(self, &ZookeeperRole::Server),
453+
role_listener_name = role_listener_name(&self.name_any(), &ZookeeperRole::Server),
454454
namespace = self.metadata.namespace.as_ref()?,
455455
cluster_domain = cluster_info.cluster_domain
456456
))

rust/operator-binary/src/listener.rs

Lines changed: 27 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,49 @@
11
//! Types and functions for exposing product endpoints via [listener::v1alpha1::Listener].
22
3-
use snafu::{ResultExt as _, Snafu};
3+
use std::str::FromStr;
4+
45
use stackable_operator::{
5-
builder::meta::ObjectMetaBuilder, commons::product_image_selection::ResolvedProductImage,
6-
crd::listener, kube::ResourceExt as _,
6+
builder::meta::ObjectMetaBuilder,
7+
crd::listener,
8+
v2::{builder::meta::ownerreference_from_resource, types::operator::RoleGroupName},
79
};
810

911
use crate::{
10-
crd::{ZOOKEEPER_SERVER_PORT_NAME, ZookeeperRole, security::ZookeeperSecurity, v1alpha1},
11-
utils::build_recommended_labels,
12-
zk_controller::ZK_CONTROLLER_NAME,
12+
crd::{ZOOKEEPER_SERVER_PORT_NAME, ZookeeperRole, security::ZookeeperSecurity},
13+
zk_controller::validate::ValidatedCluster,
1314
};
1415

15-
type Result<T, E = Error> = std::result::Result<T, E>;
16-
17-
#[derive(Snafu, Debug)]
18-
pub enum Error {
19-
#[snafu(display("Role {zk_role:?} is not defined in the ZooKeeperCluster spec"))]
20-
InvalidRole {
21-
source: crate::crd::Error,
22-
zk_role: String,
23-
},
24-
25-
#[snafu(display("object is missing metadata to build owner reference"))]
26-
ObjectMissingMetadataForOwnerRef {
27-
source: stackable_operator::builder::meta::Error,
28-
},
29-
30-
#[snafu(display("failed to build recommended labels"))]
31-
RecommendedLabels {
32-
source: stackable_operator::builder::meta::Error,
33-
},
34-
}
35-
16+
/// Builds the role-level [`Listener`](listener::v1alpha1::Listener) exposing the ZooKeeper servers.
17+
///
18+
/// The listener is owned by, labelled and named from the [`ValidatedCluster`]; the ListenerClass
19+
/// and security settings are taken from its validated cluster config.
3620
pub fn build_role_listener(
37-
zk: &v1alpha1::ZookeeperCluster,
21+
cluster: &ValidatedCluster,
3822
zk_role: &ZookeeperRole,
39-
resolved_product_image: &ResolvedProductImage,
40-
zookeeper_security: &ZookeeperSecurity,
41-
) -> Result<listener::v1alpha1::Listener> {
42-
let listener_name = role_listener_name(zk, zk_role);
43-
let listener_class = &zk
44-
.role(zk_role)
45-
.with_context(|_| InvalidRoleSnafu {
46-
zk_role: zk_role.to_string(),
47-
})?
48-
.role_config
49-
.listener_class;
23+
) -> listener::v1alpha1::Listener {
24+
// The listener is a role-level resource, so it has no role group. The recommended labels
25+
// require a role-group value, so a constant "none" is used (matching the previous behaviour).
26+
let role_group_name =
27+
RoleGroupName::from_str("none").expect("'none' is a valid role group name");
5028

51-
let listener = listener::v1alpha1::Listener {
29+
listener::v1alpha1::Listener {
5230
metadata: ObjectMetaBuilder::new()
53-
.name_and_namespace(zk)
54-
.name(listener_name)
55-
.ownerreference_from_resource(zk, None, Some(true))
56-
.context(ObjectMissingMetadataForOwnerRefSnafu)?
57-
// Since we only make a listener for the role, which labels should we use?
58-
// We can't use with_recommended_labels because it requires an ObjectLabels which
59-
// in turn requires RoleGroup stuff)
60-
// TODO (@NickLarsenNZ): Make separate functions for with_recommended_labels with/without rolegroups
61-
// .with_labels(manual_labels).build()
62-
.with_recommended_labels(&build_recommended_labels(
63-
zk,
64-
ZK_CONTROLLER_NAME,
65-
&resolved_product_image.app_version_label_value,
66-
&zk_role.to_string(),
67-
"none", // TODO (@NickLarsenNZ): update build_recommended_labels to have an optional role_group
68-
))
69-
.context(RecommendedLabelsSnafu)?
31+
.name_and_namespace(cluster)
32+
.name(role_listener_name(cluster.name.as_ref(), zk_role))
33+
.ownerreference(ownerreference_from_resource(cluster, None, Some(true)))
34+
.with_labels(cluster.recommended_labels(&role_group_name))
7035
.build(),
7136
spec: listener::v1alpha1::ListenerSpec {
72-
class_name: Some(listener_class.to_owned()),
73-
ports: Some(listener_ports(zookeeper_security)),
37+
class_name: Some(cluster.cluster_config.listener_class.clone()),
38+
ports: Some(listener_ports(&cluster.cluster_config.zookeeper_security)),
7439
..listener::v1alpha1::ListenerSpec::default()
7540
},
7641
status: None,
77-
};
78-
79-
Ok(listener)
42+
}
8043
}
8144

82-
// TODO (@NickLarsenNZ): This could be a method we can put on a Resource that takes a role_name
83-
pub fn role_listener_name(zk: &v1alpha1::ZookeeperCluster, zk_role: &ZookeeperRole) -> String {
84-
// TODO (@NickLarsenNZ): Make a convention, do we use name_any() and allow empty string? or handle the error (as unlikely as it would be)?
85-
format!("{zk}-{zk_role}", zk = zk.name_any())
45+
pub fn role_listener_name(cluster_name: &str, zk_role: &ZookeeperRole) -> String {
46+
format!("{cluster_name}-{zk_role}")
8647
}
8748

8849
// We only use the server port here and intentionally omit the metrics one.

rust/operator-binary/src/operations/pdb.rs

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
1+
use std::str::FromStr;
2+
13
use snafu::{ResultExt, Snafu};
24
use stackable_operator::{
3-
builder::pdb::PodDisruptionBudgetBuilder, client::Client, cluster_resources::ClusterResources,
4-
commons::pdb::PdbConfig, kube::ResourceExt,
5+
client::Client,
6+
cluster_resources::ClusterResources,
7+
commons::pdb::PdbConfig,
8+
kube::ResourceExt,
9+
v2::{
10+
builder::pdb::pod_disruption_budget_builder_with_role,
11+
types::operator::{ControllerName, OperatorName, ProductName, RoleName},
12+
},
513
};
614

715
use crate::{
8-
crd::{APP_NAME, OPERATOR_NAME, ZookeeperRole, v1alpha1},
9-
zk_controller::ZK_CONTROLLER_NAME,
16+
crd::{APP_NAME, OPERATOR_NAME, ZookeeperRole},
17+
zk_controller::{ZK_CONTROLLER_NAME, validate::ValidatedCluster},
1018
};
1119

1220
#[derive(Snafu, Debug)]
1321
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-
},
1922
#[snafu(display("Cannot apply PodDisruptionBudget [{name}]"))]
2023
ApplyPdb {
2124
source: stackable_operator::cluster_resources::Error,
@@ -25,7 +28,7 @@ pub enum Error {
2528

2629
pub async fn add_pdbs(
2730
pdb: &PdbConfig,
28-
zookeeper: &v1alpha1::ZookeeperCluster,
31+
validated_cluster: &ValidatedCluster,
2932
role: &ZookeeperRole,
3033
client: &Client,
3134
cluster_resources: &mut ClusterResources<'_>,
@@ -36,16 +39,25 @@ pub async fn add_pdbs(
3639
let max_unavailable = pdb.max_unavailable.unwrap_or(match role {
3740
ZookeeperRole::Server => max_unavailable_servers(),
3841
});
39-
let pdb = PodDisruptionBudgetBuilder::new_with_role(
40-
zookeeper,
41-
APP_NAME,
42-
&role.to_string(),
43-
OPERATOR_NAME,
44-
ZK_CONTROLLER_NAME,
42+
43+
// These names are derived from compile-time constants and a validated role enum, so they are
44+
// guaranteed to be valid and we use the infallible v2 builder.
45+
let product_name =
46+
ProductName::from_str(APP_NAME).expect("APP_NAME should be a valid product name");
47+
let operator_name = OperatorName::from_str(OPERATOR_NAME)
48+
.expect("OPERATOR_NAME should be a valid operator name");
49+
let controller_name = ControllerName::from_str(ZK_CONTROLLER_NAME)
50+
.expect("ZK_CONTROLLER_NAME should be a valid controller name");
51+
let role_name =
52+
RoleName::from_str(&role.to_string()).expect("role name should be a valid role name");
53+
54+
let pdb = pod_disruption_budget_builder_with_role(
55+
validated_cluster,
56+
&product_name,
57+
&role_name,
58+
&operator_name,
59+
&controller_name,
4560
)
46-
.with_context(|_| CreatePdbSnafu {
47-
role: role.to_string(),
48-
})?
4961
.with_max_unavailable(max_unavailable)
5062
.build();
5163
let pdb_name = pdb.name_any();

0 commit comments

Comments
 (0)