Skip to content

Commit 756df9c

Browse files
Add additional labels to the cluster manager service
1 parent 239a379 commit 756df9c

6 files changed

Lines changed: 110 additions & 63 deletions

File tree

rust/operator-binary/src/controller.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,8 +255,7 @@ pub async fn reconcile(
255255
.await
256256
.context(ApplyResourcesSnafu)?;
257257

258-
// create discovery ConfigMap
259-
// TODO Think about: Address from Listener has to be added to some ConfigMap
258+
// create discovery ConfigMap based on the applied resources (client required)
260259

261260
// update status (client required)
262261
update_status(&context.client, &context.names, cluster, applied_resources)

rust/operator-binary/src/controller/build/role_builder.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use super::role_group_builder::{
2020
};
2121
use crate::{
2222
controller::{ContextNames, ValidatedCluster},
23-
crd::v1alpha1,
2423
framework::{
2524
IsLabelValue,
2625
builder::{
@@ -113,18 +112,15 @@ impl<'a> RoleBuilder<'a> {
113112

114113
let metadata = self.common_metadata(self.resource_names.discovery_service_name());
115114

116-
let service_selector = [(
117-
v1alpha1::NodeRole::ClusterManager.to_string(),
118-
"true".to_owned(),
119-
)]
120-
.into();
115+
let service_selector =
116+
RoleGroupBuilder::cluster_manager_labels(&self.cluster, self.context_names);
121117

122118
let service_spec = ServiceSpec {
123119
// Internal communication does not need to be exposed
124120
type_: Some("ClusterIP".to_string()),
125121
cluster_ip: Some("None".to_string()),
126122
ports: Some(ports),
127-
selector: Some(service_selector),
123+
selector: Some(service_selector.into()),
128124
publish_not_ready_addresses: Some(true),
129125
..ServiceSpec::default()
130126
};

rust/operator-binary/src/controller/build/role_group_builder.rs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ use stackable_operator::{
1919
use super::node_config::{CONFIGURATION_FILE_OPENSEARCH_YML, NodeConfig};
2020
use crate::{
2121
controller::{ContextNames, OpenSearchRoleGroupConfig, ValidatedCluster},
22+
crd::v1alpha1,
2223
framework::{
2324
RoleGroupName,
2425
builder::meta::ownerreference_from_resource,
25-
kvp::label::{recommended_labels, role_group_selector},
26+
kvp::label::{recommended_labels, role_group_selector, role_selector},
2627
role_group_utils::ResourceNames,
2728
},
2829
};
@@ -104,7 +105,6 @@ impl<'a> RoleGroupBuilder<'a> {
104105
.resources
105106
.storage
106107
.data
107-
// TODO Compare name with Helm chart
108108
.build_pvc(DATA_VOLUME_NAME, Some(vec!["ReadWriteOnce"]));
109109

110110
let spec = StatefulSetSpec {
@@ -131,11 +131,7 @@ impl<'a> RoleGroupBuilder<'a> {
131131
fn build_pod_template(&self) -> PodTemplateSpec {
132132
let mut node_role_labels = Labels::new();
133133
for node_role in self.role_group_config.config.node_roles.iter() {
134-
node_role_labels.insert(
135-
// TODO Prefix the key
136-
Label::try_from((format!("{node_role}"), "true".to_string()))
137-
.expect("should be a valid label"),
138-
);
134+
node_role_labels.insert(Self::build_node_role_label(node_role));
139135
}
140136

141137
let metadata = ObjectMetaBuilder::new()
@@ -197,6 +193,32 @@ impl<'a> RoleGroupBuilder<'a> {
197193
pod_template
198194
}
199195

196+
pub fn cluster_manager_labels(
197+
cluster: &ValidatedCluster,
198+
context_names: &ContextNames,
199+
) -> Labels {
200+
let mut labels = role_selector(
201+
cluster,
202+
&context_names.product_name,
203+
&ValidatedCluster::role_name(),
204+
);
205+
206+
labels.insert(Self::build_node_role_label(
207+
&v1alpha1::NodeRole::ClusterManager,
208+
));
209+
210+
labels
211+
}
212+
213+
fn build_node_role_label(node_role: &v1alpha1::NodeRole) -> Label {
214+
// TODO Check the maximum length at compile-time
215+
Label::try_from((
216+
format!("stackable.tech/opensearch-role.{node_role}"),
217+
"true".to_string(),
218+
))
219+
.expect("should be a valid label")
220+
}
221+
200222
fn build_container(&self, role_group_config: &OpenSearchRoleGroupConfig) -> Container {
201223
let product_image = self
202224
.cluster

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

Lines changed: 50 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ use stackable_operator::{
99
use strum::{EnumDiscriminants, IntoStaticStr};
1010

1111
use super::{
12-
ContextNames, ProductVersion, RoleGroupName, ValidatedCluster, ValidatedOpenSearchConfig,
12+
ContextNames, OpenSearchRoleGroupConfig, ProductVersion, RoleGroupName, ValidatedCluster,
13+
ValidatedOpenSearchConfig,
1314
};
1415
use crate::{
15-
crd::v1alpha1::{self, OpenSearchConfig},
16+
crd::v1alpha1::{self, OpenSearchConfig, OpenSearchConfigFragment},
1617
framework::{
1718
ClusterName,
18-
role_utils::{RoleGroupConfig, with_validated_config},
19+
role_utils::{GenericProductSpecificCommonConfig, RoleGroupConfig, with_validated_config},
1920
},
2021
};
2122

@@ -54,10 +55,9 @@ pub enum Error {
5455

5556
type Result<T, E = Error> = std::result::Result<T, E>;
5657

57-
// TODO split
5858
// no client needed
5959
pub fn validate(
60-
names: &ContextNames,
60+
context_names: &ContextNames,
6161
cluster: &v1alpha1::OpenSearchCluster,
6262
) -> Result<ValidatedCluster> {
6363
let raw_cluster_name = cluster.meta().name.clone().context(GetClusterNameSnafu)?;
@@ -75,43 +75,8 @@ pub fn validate(
7575
let role_group_name =
7676
RoleGroupName::from_str(raw_role_group_name).context(ParseRoleGroupNameSnafu)?;
7777

78-
let merged_role_group: RoleGroup<OpenSearchConfig, _> = with_validated_config(
79-
role_group_config,
80-
&cluster.spec.nodes,
81-
&v1alpha1::OpenSearchConfig::default_config(
82-
&names.product_name,
83-
&cluster_name,
84-
&ValidatedCluster::role_name(),
85-
),
86-
)
87-
.context(ValidateOpenSearchConfigSnafu)?;
88-
89-
let graceful_shutdown_timeout = merged_role_group.config.config.graceful_shutdown_timeout;
90-
91-
let termination_grace_period_seconds = graceful_shutdown_timeout
92-
.as_secs()
93-
.try_into()
94-
.context(TerminationGracePeriodTooLongSnafu {
95-
duration: graceful_shutdown_timeout,
96-
})?;
97-
98-
let validated_config = ValidatedOpenSearchConfig {
99-
affinity: merged_role_group.config.config.affinity,
100-
node_roles: merged_role_group.config.config.node_roles,
101-
resources: merged_role_group.config.config.resources,
102-
termination_grace_period_seconds,
103-
};
104-
105-
let validated_role_group_config = RoleGroupConfig {
106-
// Kubernetes defaults to 1 if not set
107-
replicas: merged_role_group.replicas.unwrap_or(1),
108-
config: validated_config,
109-
config_overrides: merged_role_group.config.config_overrides,
110-
env_overrides: merged_role_group.config.env_overrides,
111-
cli_overrides: merged_role_group.config.cli_overrides,
112-
pod_overrides: merged_role_group.config.pod_overrides,
113-
product_specific_common_config: merged_role_group.config.product_specific_common_config,
114-
};
78+
let validated_role_group_config =
79+
validate_role_group_config(context_names, &cluster_name, cluster, role_group_config)?;
11580

11681
role_group_configs.insert(role_group_name, validated_role_group_config);
11782
}
@@ -127,3 +92,46 @@ pub fn validate(
12792
role_group_configs,
12893
})
12994
}
95+
96+
fn validate_role_group_config(
97+
context_names: &ContextNames,
98+
cluster_name: &ClusterName,
99+
cluster: &v1alpha1::OpenSearchCluster,
100+
role_group_config: &RoleGroup<OpenSearchConfigFragment, GenericProductSpecificCommonConfig>,
101+
) -> Result<OpenSearchRoleGroupConfig> {
102+
let merged_role_group: RoleGroup<OpenSearchConfig, _> = with_validated_config(
103+
role_group_config,
104+
&cluster.spec.nodes,
105+
&v1alpha1::OpenSearchConfig::default_config(
106+
&context_names.product_name,
107+
cluster_name,
108+
&ValidatedCluster::role_name(),
109+
),
110+
)
111+
.context(ValidateOpenSearchConfigSnafu)?;
112+
113+
let graceful_shutdown_timeout = merged_role_group.config.config.graceful_shutdown_timeout;
114+
let termination_grace_period_seconds = graceful_shutdown_timeout.as_secs().try_into().context(
115+
TerminationGracePeriodTooLongSnafu {
116+
duration: graceful_shutdown_timeout,
117+
},
118+
)?;
119+
120+
let validated_config = ValidatedOpenSearchConfig {
121+
affinity: merged_role_group.config.config.affinity,
122+
node_roles: merged_role_group.config.config.node_roles,
123+
resources: merged_role_group.config.config.resources,
124+
termination_grace_period_seconds,
125+
};
126+
127+
Ok(RoleGroupConfig {
128+
// Kubernetes defaults to 1 if not set
129+
replicas: merged_role_group.replicas.unwrap_or(1),
130+
config: validated_config,
131+
config_overrides: merged_role_group.config.config_overrides,
132+
env_overrides: merged_role_group.config.env_overrides,
133+
cli_overrides: merged_role_group.config.cli_overrides,
134+
pod_overrides: merged_role_group.config.pod_overrides,
135+
product_specific_common_config: merged_role_group.config.product_specific_common_config,
136+
})
137+
}

rust/operator-binary/src/framework/kvp/label.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,20 @@ pub fn recommended_labels(
3333
.expect("Labels should be created because all given parameters produce valid label values")
3434
}
3535

36+
/// Infallible variant of `Labels::role_selector`
37+
pub fn role_selector(
38+
owner: &(impl Resource + IsLabelValue),
39+
product_name: &ProductName,
40+
role_name: &RoleName,
41+
) -> Labels {
42+
Labels::role_selector(
43+
owner,
44+
&product_name.to_label_value(),
45+
&role_name.to_label_value(),
46+
)
47+
.expect("Labels should be created because all given parameters produce valid label values")
48+
}
49+
3650
/// Infallible variant of `Labels::role_group_selector`
3751
pub fn role_group_selector(
3852
owner: &(impl Resource + IsLabelValue),

tests/templates/kuttl/smoke/10-assert.yaml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ spec:
4343
app.kubernetes.io/name: opensearch
4444
app.kubernetes.io/role-group: cluster-manager
4545
app.kubernetes.io/version: 3.0.0
46-
cluster_manager: "true"
46+
stackable.tech/opensearch-role.cluster_manager: "true"
4747
stackable.tech/vendor: Stackable
4848
spec:
4949
affinity:
@@ -203,9 +203,9 @@ spec:
203203
app.kubernetes.io/name: opensearch
204204
app.kubernetes.io/role-group: data
205205
app.kubernetes.io/version: 3.0.0
206-
data: "true"
207-
ingest: "true"
208-
remote_cluster_client: "true"
206+
stackable.tech/opensearch-role.data: "true"
207+
stackable.tech/opensearch-role.ingest: "true"
208+
stackable.tech/opensearch-role.remote_cluster_client: "true"
209209
stackable.tech/vendor: Stackable
210210
spec:
211211
affinity:
@@ -455,6 +455,11 @@ metadata:
455455
app.kubernetes.io/version: 3.0.0
456456
stackable.tech/vendor: Stackable
457457
name: opensearch
458+
ownerReferences:
459+
- apiVersion: opensearch.stackable.tech/v1alpha1
460+
controller: true
461+
kind: OpenSearchCluster
462+
name: opensearch
458463
spec:
459464
ports:
460465
- name: http
@@ -467,7 +472,10 @@ spec:
467472
targetPort: 9300
468473
publishNotReadyAddresses: true
469474
selector:
470-
cluster_manager: "true"
475+
app.kubernetes.io/component: nodes
476+
app.kubernetes.io/instance: opensearch
477+
app.kubernetes.io/name: opensearch
478+
stackable.tech/opensearch-role.cluster_manager: "true"
471479
type: ClusterIP
472480
---
473481
apiVersion: v1

0 commit comments

Comments
 (0)