Skip to content

Commit ea5bed0

Browse files
committed
refactor: consolidate object metadata + identity helpers
1 parent 7747afd commit ea5bed0

9 files changed

Lines changed: 91 additions & 93 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub mod tls;
4848
/// exposing the given `zk_role`, `<cluster>-<role>`.
4949
///
5050
/// Lives in the `crd` module (rather than the controller build tree) because it is shared by both
51-
/// controllers and by [`ZookeeperCluster::server_role_listener_fqdn`].
51+
/// controllers and by [`v1alpha1::ZookeeperCluster::server_role_listener_fqdn`].
5252
pub fn role_listener_name(cluster_name: &str, zk_role: &ZookeeperRole) -> ListenerName {
5353
ListenerName::from_str(&format!("{cluster_name}-{zk_role}"))
5454
.expect("the role listener name should be a valid Listener name")

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,22 @@
99
//! remaining submodules ([`command`], [`graceful_shutdown`], [`jvm`],
1010
//! [`properties`]) produce fragments that those resource builders assemble.
1111
12+
use std::str::FromStr;
13+
14+
use stackable_operator::v2::types::operator::{ProductVersion, RoleGroupName};
15+
16+
// Placeholder role-group name used for the recommended labels of the role-level discovery
17+
// `ConfigMap` (which is not tied to a single role group).
18+
stackable_operator::constant!(pub(crate) PLACEHOLDER_DISCOVERY_ROLE_GROUP: RoleGroupName = "discovery");
19+
20+
// Placeholder role-group name used for the recommended labels of the role-level `Listener`
21+
// (which is not tied to a single role group).
22+
stackable_operator::constant!(pub(crate) PLACEHOLDER_LISTENER_ROLE_GROUP: RoleGroupName = "none");
23+
24+
// Placeholder product version used for labels on PVC templates, which cannot be modified once
25+
// deployed. A constant value keeps the labels stable across version upgrades.
26+
stackable_operator::constant!(pub(crate) UNVERSIONED_PRODUCT_VERSION: ProductVersion = "none");
27+
1228
pub mod command;
1329
pub mod graceful_shutdown;
1430
pub mod jvm;

rust/operator-binary/src/zk_controller/build/resource/config_map.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//! Assembles the per-rolegroup `ConfigMap` from the [`ValidatedCluster`],
2-
//! without reaching into the [`v1alpha1::ZookeeperCluster`] except for the owner
2+
//! without reaching into the [`crate::crd::v1alpha1::ZookeeperCluster`] except for the owner
33
//! reference and object metadata.
44
//!
55
//! The individual files are rendered by the [`properties`](crate::zk_controller::build::properties)
@@ -9,11 +9,10 @@ use std::collections::BTreeMap;
99

1010
use snafu::{ResultExt, Snafu};
1111
use stackable_operator::{
12-
builder::{configmap::ConfigMapBuilder, meta::ObjectMetaBuilder},
12+
builder::configmap::ConfigMapBuilder,
1313
k8s_openapi::api::core::v1::ConfigMap,
1414
product_logging::framework::VECTOR_CONFIG_FILE,
1515
v2::{
16-
builder::meta::ownerreference_from_resource,
1716
config_file_writer::{PropertiesWriterError, to_java_properties_string},
1817
types::operator::RoleGroupName,
1918
},
@@ -92,16 +91,14 @@ pub fn build_server_rolegroup_config_map(
9291

9392
ConfigMapBuilder::new()
9493
.metadata(
95-
ObjectMetaBuilder::new()
96-
.name_and_namespace(cluster)
97-
.name(
94+
cluster
95+
.object_meta(
9896
cluster
9997
.resource_names(role_group_name)
10098
.role_group_config_map()
10199
.to_string(),
100+
role_group_name,
102101
)
103-
.ownerreference(ownerreference_from_resource(cluster, None, Some(true)))
104-
.with_labels(cluster.recommended_labels(role_group_name))
105102
.build(),
106103
)
107104
.data(data)

rust/operator-binary/src/zk_controller/build/resource/discovery.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@ use stackable_operator::{
1010
HasName, HasUid, NameIsValidLabelValue,
1111
builder::meta::ownerreference_from_resource,
1212
kvp::label::recommended_labels,
13-
types::operator::{ControllerName, ProductVersion, RoleGroupName},
13+
types::operator::{ControllerName, ProductVersion},
1414
},
1515
};
1616

1717
use crate::{
1818
crd::{ZOOKEEPER_SERVER_PORT_NAME, security::ZookeeperSecurity},
19-
zk_controller::validate::{ValidatedCluster, operator_name, product_name},
19+
zk_controller::{
20+
build::PLACEHOLDER_DISCOVERY_ROLE_GROUP,
21+
validate::{ValidatedCluster, operator_name, product_name},
22+
},
2023
znode_controller::validate::ValidatedZnode,
2124
};
2225

@@ -97,8 +100,8 @@ pub fn build_znode_discovery_configmap(
97100
/// Build a discovery [`ConfigMap`] containing ZooKeeper connection details from a
98101
/// [`listener::v1alpha1::Listener`].
99102
///
100-
/// `owner` owns the ConfigMap (the [`ZookeeperCluster`](v1alpha1::ZookeeperCluster) for the cluster
101-
/// controller, or the [`ZookeeperZnode`](v1alpha1::ZookeeperZnode) for the znode controller) and
103+
/// `owner` owns the ConfigMap (the [`ZookeeperCluster`](crate::crd::v1alpha1::ZookeeperCluster) for the cluster
104+
/// controller, or the [`ZookeeperZnode`](crate::crd::v1alpha1::ZookeeperZnode) for the znode controller) and
102105
/// `namespace` is where the ConfigMap is placed.
103106
fn build_discovery_configmap_for_owner(
104107
owner: &(impl Resource<DynamicType = ()> + HasName + HasUid + NameIsValidLabelValue),
@@ -116,8 +119,7 @@ fn build_discovery_configmap_for_owner(
116119
// znode controllers, so it is passed in and validated into the type-safe newtype here.
117120
let controller_name = ControllerName::from_str(controller_name)
118121
.expect("the controller name is a valid label value");
119-
let role_group_name =
120-
RoleGroupName::from_str("discovery").expect("'discovery' is a valid role group name");
122+
let role_group_name = PLACEHOLDER_DISCOVERY_ROLE_GROUP.clone();
121123

122124
let listener_addresses = listener_addresses(&listener, ZOOKEEPER_SERVER_PORT_NAME)?;
123125

rust/operator-binary/src/zk_controller/build/resource/listener.rs

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
//! Types and functions for exposing product endpoints via [listener::v1alpha1::Listener].
22
3-
use std::str::FromStr;
4-
5-
use stackable_operator::{
6-
builder::meta::ObjectMetaBuilder,
7-
crd::listener,
8-
v2::{builder::meta::ownerreference_from_resource, types::operator::RoleGroupName},
9-
};
3+
use stackable_operator::crd::listener;
104

115
use crate::{
126
crd::{
137
ZOOKEEPER_SERVER_PORT_NAME, ZookeeperRole, role_listener_name, security::ZookeeperSecurity,
148
},
15-
zk_controller::validate::ValidatedCluster,
9+
zk_controller::{build::PLACEHOLDER_LISTENER_ROLE_GROUP, validate::ValidatedCluster},
1610
};
1711

1812
/// Builds the role-level [`Listener`](listener::v1alpha1::Listener) exposing the ZooKeeper servers.
@@ -23,17 +17,12 @@ pub fn build_role_listener(
2317
cluster: &ValidatedCluster,
2418
zk_role: &ZookeeperRole,
2519
) -> listener::v1alpha1::Listener {
26-
// The listener is a role-level resource, so it has no role group. The recommended labels
27-
// require a role-group value, so a constant "none" is used (matching the previous behaviour).
28-
let role_group_name =
29-
RoleGroupName::from_str("none").expect("'none' is a valid role group name");
30-
3120
listener::v1alpha1::Listener {
32-
metadata: ObjectMetaBuilder::new()
33-
.name_and_namespace(cluster)
34-
.name(role_listener_name(cluster.name.as_ref(), zk_role))
35-
.ownerreference(ownerreference_from_resource(cluster, None, Some(true)))
36-
.with_labels(cluster.recommended_labels(&role_group_name))
21+
metadata: cluster
22+
.object_meta(
23+
role_listener_name(cluster.name.as_ref(), zk_role),
24+
&PLACEHOLDER_LISTENER_ROLE_GROUP,
25+
)
3726
.build(),
3827
spec: listener::v1alpha1::ListenerSpec {
3928
class_name: Some(cluster.cluster_config.listener_class.to_string()),

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

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
1-
use std::str::FromStr;
2-
31
use stackable_operator::{
4-
commons::pdb::PdbConfig,
5-
k8s_openapi::api::policy::v1::PodDisruptionBudget,
6-
v2::{
7-
builder::pdb::pod_disruption_budget_builder_with_role,
8-
types::operator::{ControllerName, OperatorName, ProductName, RoleName},
9-
},
2+
commons::pdb::PdbConfig, k8s_openapi::api::policy::v1::PodDisruptionBudget,
3+
v2::builder::pdb::pod_disruption_budget_builder_with_role,
104
};
115

126
use crate::{
13-
crd::{APP_NAME, OPERATOR_NAME, ZookeeperRole},
14-
zk_controller::{ZK_CONTROLLER_NAME, validate::ValidatedCluster},
7+
crd::ZookeeperRole,
8+
zk_controller::validate::{ValidatedCluster, controller_name, operator_name, product_name},
159
};
1610

1711
/// Builds the [`PodDisruptionBudget`] for the given `role`, or `None` if PDBs are disabled.
1812
pub fn build_pdb(
1913
pdb: &PdbConfig,
20-
validated_cluster: &ValidatedCluster,
14+
cluster: &ValidatedCluster,
2115
role: &ZookeeperRole,
2216
) -> Option<PodDisruptionBudget> {
2317
if !pdb.enabled {
@@ -27,23 +21,12 @@ pub fn build_pdb(
2721
ZookeeperRole::Server => max_unavailable_servers(),
2822
});
2923

30-
// These names are derived from compile-time constants and a validated role enum, so they are
31-
// guaranteed to be valid and we use the infallible v2 builder.
32-
let product_name =
33-
ProductName::from_str(APP_NAME).expect("APP_NAME should be a valid product name");
34-
let operator_name = OperatorName::from_str(OPERATOR_NAME)
35-
.expect("OPERATOR_NAME should be a valid operator name");
36-
let controller_name = ControllerName::from_str(ZK_CONTROLLER_NAME)
37-
.expect("ZK_CONTROLLER_NAME should be a valid controller name");
38-
let role_name =
39-
RoleName::from_str(&role.to_string()).expect("role name should be a valid role name");
40-
4124
let pdb = pod_disruption_budget_builder_with_role(
42-
validated_cluster,
43-
&product_name,
44-
&role_name,
45-
&operator_name,
46-
&controller_name,
25+
cluster,
26+
&product_name(),
27+
&ValidatedCluster::role_name(),
28+
&operator_name(),
29+
&controller_name(),
4730
)
4831
.with_max_unavailable(max_unavailable)
4932
.build();

rust/operator-binary/src/zk_controller/build/resource/service.rs

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
use stackable_operator::{
2-
builder::meta::ObjectMetaBuilder,
32
k8s_openapi::api::core::v1::{Service, ServicePort, ServiceSpec},
43
kvp::{Annotations, Labels},
5-
v2::{
6-
builder::meta::ownerreference_from_resource,
7-
types::{common::Port, operator::RoleGroupName},
8-
},
4+
v2::types::{common::Port, operator::RoleGroupName},
95
};
106

117
use crate::{
@@ -24,16 +20,14 @@ pub(crate) fn build_server_rolegroup_headless_service(
2420
cluster: &ValidatedCluster,
2521
role_group_name: &RoleGroupName,
2622
) -> Service {
27-
let metadata = ObjectMetaBuilder::new()
28-
.name_and_namespace(cluster)
29-
.name(
23+
let metadata = cluster
24+
.object_meta(
3025
cluster
3126
.resource_names(role_group_name)
3227
.headless_service_name()
3328
.to_string(),
29+
role_group_name,
3430
)
35-
.ownerreference(ownerreference_from_resource(cluster, None, Some(true)))
36-
.with_labels(cluster.recommended_labels(role_group_name))
3731
.build();
3832

3933
let service_spec = ServiceSpec {
@@ -73,15 +67,13 @@ pub(crate) fn build_server_rolegroup_metrics_service(
7367
rolegroup_config: &ValidatedRoleGroupConfig,
7468
) -> Service {
7569
let metrics_port = cluster.metrics_http_port(rolegroup_config);
76-
let metadata = ObjectMetaBuilder::new()
77-
.name_and_namespace(cluster)
78-
.name(
70+
let metadata = cluster
71+
.object_meta(
7972
cluster
8073
.resource_names(role_group_name)
8174
.metrics_service_name(),
75+
role_group_name,
8276
)
83-
.ownerreference(ownerreference_from_resource(cluster, None, Some(true)))
84-
.with_labels(cluster.recommended_labels(role_group_name))
8577
.with_labels(prometheus_labels())
8678
.with_annotations(prometheus_annotations(metrics_port.clone()))
8779
.build();

rust/operator-binary/src/zk_controller/build/resource/statefulset.rs

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,11 @@ use stackable_operator::{
3737
},
3838
utils::COMMON_BASH_TRAP_FUNCTIONS,
3939
v2::{
40-
builder::{
41-
meta::ownerreference_from_resource,
42-
pod::container::{EnvVarName, EnvVarSet},
43-
},
40+
builder::pod::container::{EnvVarName, EnvVarSet},
4441
product_logging::framework::{ValidatedContainerLogConfigChoice, vector_container},
4542
types::{
4643
kubernetes::{ContainerName, VolumeName},
47-
operator::{ProductVersion, RoleGroupName},
44+
operator::RoleGroupName,
4845
},
4946
},
5047
};
@@ -61,6 +58,7 @@ use crate::{
6158
zk_controller::{
6259
LISTENER_VOLUME_DIR, LISTENER_VOLUME_NAME,
6360
build::{
61+
UNVERSIONED_PRODUCT_VERSION,
6462
command::create_init_container_command_args,
6563
graceful_shutdown::add_graceful_shutdown_config,
6664
jvm::{construct_non_heap_jvm_args, construct_zk_server_heap_env},
@@ -197,12 +195,10 @@ pub fn build_server_rolegroup_statefulset(
197195
ContainerBuilder::new(APP_NAME).expect("invalid hard-coded container name");
198196
let mut pod_builder = PodBuilder::new();
199197

200-
// Used for PVC templates that cannot be modified once they are deployed. A version value is
201-
// required, so a constant "none" is used to keep the labels stable across version upgrades.
202-
let unversioned_recommended_labels = cluster.recommended_labels_for(
203-
&ProductVersion::from_str("none").expect("'none' is a valid product version"),
204-
role_group_name,
205-
);
198+
// Used for PVC templates that cannot be modified once they are deployed. A constant version
199+
// keeps the labels stable across version upgrades.
200+
let unversioned_recommended_labels =
201+
cluster.recommended_labels_for(&UNVERSIONED_PRODUCT_VERSION, role_group_name);
206202

207203
let listener_pvc = build_role_listener_pvc(
208204
role_listener_name(cluster.name.as_ref(), &ZookeeperRole::Server).as_ref(),
@@ -436,11 +432,11 @@ pub fn build_server_rolegroup_statefulset(
436432
let mut pod_template = pod_builder.build_template();
437433
pod_template.merge_from(rolegroup_config.pod_overrides.clone());
438434

439-
let metadata = ObjectMetaBuilder::new()
440-
.name_and_namespace(cluster)
441-
.name(resource_names.stateful_set_name().to_string())
442-
.ownerreference(ownerreference_from_resource(cluster, None, Some(true)))
443-
.with_labels(cluster.recommended_labels(role_group_name))
435+
let metadata = cluster
436+
.object_meta(
437+
resource_names.stateful_set_name().to_string(),
438+
role_group_name,
439+
)
444440
.with_label(RESTART_CONTROLLER_ENABLED_LABEL.to_owned())
445441
.build();
446442

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

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::{collections::BTreeMap, str::FromStr};
1111

1212
use snafu::{OptionExt, ResultExt, Snafu};
1313
use stackable_operator::{
14+
builder::meta::ObjectMetaBuilder,
1415
cli::OperatorEnvironmentOptions,
1516
commons::{
1617
cluster_operation::ClusterOperation,
@@ -26,7 +27,10 @@ use stackable_operator::{
2627
utils::cluster_info::KubernetesClusterInfo,
2728
v2::{
2829
HasName, HasUid, NameIsValidLabelValue,
29-
builder::pod::container::{self, EnvVarName, EnvVarSet},
30+
builder::{
31+
meta::ownerreference_from_resource,
32+
pod::container::{self, EnvVarName, EnvVarSet},
33+
},
3034
controller_utils::{get_cluster_name, get_namespace, get_uid},
3135
jvm_argument_overrides::JvmArgumentOverrides,
3236
kvp::label::{recommended_labels, role_group_selector},
@@ -314,6 +318,25 @@ impl ValidatedCluster {
314318
pub fn role_group_selector(&self, role_group_name: &RoleGroupName) -> Labels {
315319
role_group_selector(self, &product_name(), &Self::role_name(), role_group_name)
316320
}
321+
322+
/// Returns an [`ObjectMetaBuilder`] pre-filled with the namespace, an owner reference back to
323+
/// this cluster, and the recommended labels for a resource named `name` in `role_group_name`.
324+
///
325+
/// Consolidates the metadata chain repeated by the child-resource builders. Call sites that
326+
/// need extra labels/annotations chain them onto the returned builder.
327+
pub(crate) fn object_meta(
328+
&self,
329+
name: impl Into<String>,
330+
role_group_name: &RoleGroupName,
331+
) -> ObjectMetaBuilder {
332+
let mut builder = ObjectMetaBuilder::new();
333+
builder
334+
.name_and_namespace(self)
335+
.name(name)
336+
.ownerreference(ownerreference_from_resource(self, None, Some(true)))
337+
.with_labels(self.recommended_labels(role_group_name));
338+
builder
339+
}
317340
}
318341

319342
/// The product name (`zookeeper`) as a type-safe label value.
@@ -327,7 +350,7 @@ pub(crate) fn operator_name() -> OperatorName {
327350
}
328351

329352
/// The controller name as a type-safe label value.
330-
fn controller_name() -> ControllerName {
353+
pub(crate) fn controller_name() -> ControllerName {
331354
ControllerName::from_str(ZK_CONTROLLER_NAME)
332355
.expect("the controller name is a valid label value")
333356
}

0 commit comments

Comments
 (0)