Skip to content

Commit 740bf20

Browse files
committed
refactor: use RoleGroupName, use v2 infallible labels, ResourceNames and reduce usage of RoleGroupRef.
1 parent cfeb835 commit 740bf20

9 files changed

Lines changed: 220 additions & 342 deletions

File tree

rust/operator-binary/src/controller.rs

Lines changed: 124 additions & 96 deletions
Large diffs are not rendered by default.

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

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,15 @@ use stackable_operator::{
55
builder::{configmap::ConfigMapBuilder, meta::ObjectMetaBuilder},
66
k8s_openapi::api::core::v1::ConfigMap,
77
product_logging::framework::VECTOR_CONFIG_FILE,
8-
role_utils::RoleGroupRef,
98
v2::{
109
builder::meta::ownerreference_from_resource,
1110
config_file_writer::{PropertiesWriterError, to_hadoop_xml, to_java_properties_string},
1211
},
1312
};
1413

15-
use crate::{
16-
controller::{
17-
HiveRoleGroupConfig, ValidatedCluster,
18-
build::properties::{ConfigFileName, core_site, hive_site, logging, security_properties},
19-
build_recommended_labels,
20-
},
21-
crd::v1alpha1,
14+
use crate::controller::{
15+
HiveRoleGroupConfig, RoleGroupName, ValidatedCluster,
16+
build::properties::{ConfigFileName, core_site, hive_site, logging, security_properties},
2217
};
2318

2419
#[derive(Debug, Snafu)]
@@ -29,26 +24,25 @@ pub enum Error {
2924
#[snafu(display("failed to serialize {}", ConfigFileName::Security))]
3025
WriteSecurityProperties { source: PropertiesWriterError },
3126

32-
#[snafu(display("failed to build metadata"))]
33-
MetadataBuild {
34-
source: stackable_operator::builder::meta::Error,
35-
},
36-
37-
#[snafu(display("failed to assemble ConfigMap for {rolegroup}"))]
27+
#[snafu(display("failed to assemble ConfigMap for role group {role_group}"))]
3828
Assemble {
3929
source: stackable_operator::builder::configmap::Error,
40-
rolegroup: RoleGroupRef<v1alpha1::HiveCluster>,
30+
role_group: RoleGroupName,
4131
},
4232
}
4333

4434
type Result<T, E = Error> = std::result::Result<T, E>;
4535

4636
/// The rolegroup [`ConfigMap`] configures the rolegroup based on the configuration given by the
4737
/// administrator.
38+
///
39+
/// `vector_config` is the Vector agent config (`vector.yaml`) built by the caller (where a
40+
/// `RoleGroupRef` is available); it is `None` when the Vector agent is disabled.
4841
pub fn build_metastore_rolegroup_config_map(
4942
cluster: &ValidatedCluster,
50-
rolegroup: &RoleGroupRef<v1alpha1::HiveCluster>,
43+
role_group_name: &RoleGroupName,
5144
rg: &HiveRoleGroupConfig,
45+
vector_config: Option<String>,
5246
) -> Result<ConfigMap> {
5347
// hive-site.xml
5448
let hive_site_overrides = rg.config_overrides.hive_site_xml.overrides.clone();
@@ -69,15 +63,14 @@ pub fn build_metastore_rolegroup_config_map(
6963
.metadata(
7064
ObjectMetaBuilder::new()
7165
.name_and_namespace(cluster)
72-
.name(rolegroup.object_name())
66+
.name(
67+
cluster
68+
.resource_names(role_group_name)
69+
.role_group_config_map()
70+
.to_string(),
71+
)
7372
.ownerreference(ownerreference_from_resource(cluster, None, Some(true)))
74-
.with_recommended_labels(&build_recommended_labels(
75-
cluster,
76-
&cluster.image.app_version_label_value,
77-
&rolegroup.role,
78-
&rolegroup.role_group,
79-
))
80-
.context(MetadataBuildSnafu)?
73+
.with_labels(cluster.recommended_labels(role_group_name))
8174
.build(),
8275
)
8376
.add_data(
@@ -101,11 +94,11 @@ pub fn build_metastore_rolegroup_config_map(
10194
if let Some(log4j2_properties) = logging::build_log4j2(&rg.config.logging) {
10295
cm_builder.add_data(ConfigFileName::Log4j2.to_string(), log4j2_properties);
10396
}
104-
if let Some(vector_config) = logging::build_vector_config(rolegroup, &rg.config.logging) {
97+
if let Some(vector_config) = vector_config {
10598
cm_builder.add_data(VECTOR_CONFIG_FILE, vector_config);
10699
}
107100

108101
cm_builder.build().with_context(|_| AssembleSnafu {
109-
rolegroup: rolegroup.clone(),
102+
role_group: role_group_name.clone(),
110103
})
111104
}

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

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::str::FromStr;
2+
13
use snafu::{ResultExt, Snafu};
24
use stackable_operator::{
35
builder::{configmap::ConfigMapBuilder, meta::ObjectMetaBuilder},
@@ -8,7 +10,7 @@ use stackable_operator::{
810
};
911

1012
use crate::{
11-
controller::{ValidatedCluster, build_recommended_labels},
13+
controller::{RoleGroupName, ValidatedCluster},
1214
crd::{HiveRole, v1alpha1},
1315
listener::build_listener_connection_string,
1416
};
@@ -21,10 +23,6 @@ pub enum Error {
2123
obj_ref: ObjectRef<v1alpha1::HiveCluster>,
2224
},
2325

24-
#[snafu(display("failed to build Metadata"))]
25-
MetadataBuild {
26-
source: stackable_operator::builder::meta::Error,
27-
},
2826
#[snafu(display("failed to configure listener discovery configmap"))]
2927
ListenerConfiguration { source: crate::listener::Error },
3028
}
@@ -66,13 +64,14 @@ fn build_discovery_configmap(
6664
ObjectMetaBuilder::new()
6765
.name_and_namespace(cluster)
6866
.ownerreference(ownerreference_from_resource(cluster, None, Some(true)))
69-
.with_recommended_labels(&build_recommended_labels(
70-
cluster,
71-
&cluster.image.app_version_label_value,
72-
&hive_role.to_string(),
73-
"discovery",
74-
))
75-
.context(MetadataBuildSnafu)?
67+
// Discovery is a role-level object; "discovery" is used as a placeholder role-group
68+
// name for the recommended labels.
69+
.with_labels(
70+
cluster.recommended_labels(
71+
&RoleGroupName::from_str("discovery")
72+
.expect("'discovery' is a valid role group name"),
73+
),
74+
)
7675
.build(),
7776
);
7877

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ mod tests {
9191
validated
9292
.role_group_configs
9393
.get(&HiveRole::MetaStore)
94-
.and_then(|groups| groups.get("default"))
94+
.and_then(|groups| groups.get(&"default".parse().expect("valid role group name")))
9595
.expect("metastore default role group should exist")
9696
.clone()
9797
}

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

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,22 @@ pub enum Error {
5151
source: stackable_operator::v2::controller_utils::Error,
5252
},
5353

54+
#[snafu(display("invalid role group name {role_group}"))]
55+
ParseRoleGroupName {
56+
source: stackable_operator::v2::macros::attributed_string_type::Error,
57+
role_group: String,
58+
},
59+
5460
#[snafu(display("failed to validate the config for role group {role_group}"))]
5561
ValidateConfig {
5662
source: fragment::ValidationError,
57-
role_group: String,
63+
role_group: RoleGroupName,
5864
},
5965

6066
#[snafu(display("invalid environment variable override name in role group {role_group}"))]
6167
ParseEnvVarName {
6268
source: container::Error,
63-
role_group: String,
69+
role_group: RoleGroupName,
6470
},
6571

6672
#[snafu(display("invalid metadata database connection"))]
@@ -111,8 +117,12 @@ pub fn validate_cluster(
111117

112118
let mut groups: BTreeMap<RoleGroupName, HiveRoleGroupConfig> = BTreeMap::new();
113119
for (rg_name, rg) in &role.role_groups {
114-
let validated_rg = validate_role_group_config(rg_name, rg, role, &default_config)?;
115-
groups.insert(rg_name.clone(), validated_rg);
120+
let role_group_name =
121+
RoleGroupName::from_str(rg_name).with_context(|_| ParseRoleGroupNameSnafu {
122+
role_group: rg_name.clone(),
123+
})?;
124+
let validated_rg = validate_role_group_config(&role_group_name, rg, role, &default_config)?;
125+
groups.insert(role_group_name, validated_rg);
116126
}
117127

118128
let mut role_group_configs = BTreeMap::new();
@@ -171,7 +181,7 @@ pub fn validate_cluster(
171181
/// (`HashMap`) are converted into an [`EnvVarSet`] here so invalid names fail validation
172182
/// early (the opensearch-operator pattern).
173183
fn validate_role_group_config(
174-
role_group_name: &str,
184+
role_group_name: &RoleGroupName,
175185
role_group: &crate::crd::HiveRoleGroupType,
176186
role: &crate::crd::HiveRoleType,
177187
default_config: &crate::crd::MetaStoreConfigFragment,
@@ -184,14 +194,14 @@ fn validate_role_group_config(
184194
v1alpha1::HiveConfigOverrides,
185195
>(role_group, role, default_config)
186196
.with_context(|_| ValidateConfigSnafu {
187-
role_group: role_group_name.to_owned(),
197+
role_group: role_group_name.clone(),
188198
})?;
189199

190200
let mut env_overrides = EnvVarSet::new();
191201
for (env_var_name, env_var_value) in merged.config.env_overrides {
192202
env_overrides = env_overrides.with_value(
193203
&EnvVarName::from_str(&env_var_name).with_context(|_| ParseEnvVarNameSnafu {
194-
role_group: role_group_name.to_owned(),
204+
role_group: role_group_name.clone(),
195205
})?,
196206
env_var_value,
197207
);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ mod tests {
6060
let merged_config = validated
6161
.role_group_configs
6262
.get(&role)
63-
.and_then(|groups| groups.get("default"))
63+
.and_then(|groups| groups.get(&"default".parse().expect("valid role group name")))
6464
.expect("role group should exist")
6565
.config
6666
.clone();

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

Lines changed: 3 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
use std::{collections::BTreeMap, str::FromStr};
2-
31
use databases::MetadataDatabaseConnection;
42
use security::AuthenticationConfig;
53
use serde::{Deserialize, Serialize};
6-
use snafu::{OptionExt, ResultExt, Snafu};
4+
use snafu::Snafu;
75
use stackable_operator::{
86
commons::{
97
affinity::StackableAffinity,
@@ -22,17 +20,16 @@ use stackable_operator::{
2220
crd::s3,
2321
deep_merger::ObjectOverrides,
2422
k8s_openapi::apimachinery::pkg::api::resource::Quantity,
25-
kube::{CustomResource, ResourceExt, runtime::reflector::ObjectRef},
23+
kube::{CustomResource, runtime::reflector::ObjectRef},
2624
product_logging::{self, spec::Logging},
2725
role_utils::{GenericRoleConfig, Role, RoleGroup, RoleGroupRef},
2826
schemars::{self, JsonSchema},
2927
shared::time::Duration,
3028
status::condition::{ClusterCondition, HasStatusCondition},
31-
utils::cluster_info::KubernetesClusterInfo,
3229
v2::{config_overrides::KeyValueConfigOverrides, role_utils::JavaCommonConfig},
3330
versioned::versioned,
3431
};
35-
use strum::{Display, EnumIter, EnumString, IntoEnumIterator};
32+
use strum::{Display, EnumIter, EnumString};
3633
use v1alpha1::HiveMetastoreRoleConfig;
3734

3835
use crate::{crd::affinity::get_affinity, listener::metastore_default_listener_class};
@@ -83,16 +80,6 @@ pub enum Error {
8380

8481
#[snafu(display("the role {role} is not defined"))]
8582
CannotRetrieveHiveRole { role: String },
86-
87-
#[snafu(display("the role group {role_group} is not defined"))]
88-
CannotRetrieveHiveRoleGroup { role_group: String },
89-
90-
#[snafu(display("unknown role {role}. Should be one of {roles:?}"))]
91-
UnknownHiveRole {
92-
source: strum::ParseError,
93-
role: String,
94-
roles: Vec<String>,
95-
},
9683
}
9784

9885
#[versioned(
@@ -221,65 +208,6 @@ impl v1alpha1::HiveCluster {
221208
}
222209
}
223210

224-
/// List all pods expected to form the cluster
225-
///
226-
/// We try to predict the pods here rather than looking at the current cluster state in order to
227-
/// avoid instance churn.
228-
pub fn pods(&self) -> Result<impl Iterator<Item = PodRef> + '_, NoNamespaceError> {
229-
let ns = self.metadata.namespace.clone().context(NoNamespaceSnafu)?;
230-
Ok(self
231-
.spec
232-
.metastore
233-
.iter()
234-
.flat_map(|role| &role.role_groups)
235-
// Order rolegroups consistently, to avoid spurious downstream rewrites
236-
.collect::<BTreeMap<_, _>>()
237-
.into_iter()
238-
.flat_map(move |(rolegroup_name, rolegroup)| {
239-
let rolegroup_ref = self.metastore_rolegroup_ref(rolegroup_name);
240-
let ns = ns.clone();
241-
(0..rolegroup.replicas.unwrap_or(0)).map(move |i| PodRef {
242-
namespace: ns.clone(),
243-
role_group_service_name: rolegroup_ref.object_name(),
244-
pod_name: format!("{}-{}", rolegroup_ref.object_name(), i),
245-
})
246-
}))
247-
}
248-
249-
pub fn role(&self, role_variant: &HiveRole) -> Result<&HiveRoleType, Error> {
250-
match role_variant {
251-
HiveRole::MetaStore => self.spec.metastore.as_ref(),
252-
}
253-
.with_context(|| CannotRetrieveHiveRoleSnafu {
254-
role: role_variant.to_string(),
255-
})
256-
}
257-
258-
/// The name of the role-listener provided for a specific role.
259-
/// returns a name `<cluster>-<role>`
260-
pub fn role_listener_name(&self, hive_role: &HiveRole) -> String {
261-
format!("{name}-{role}", name = self.name_any(), role = hive_role)
262-
}
263-
264-
pub fn rolegroup(
265-
&self,
266-
rolegroup_ref: &RoleGroupRef<Self>,
267-
) -> Result<HiveRoleGroupType, Error> {
268-
let role_variant =
269-
HiveRole::from_str(&rolegroup_ref.role).with_context(|_| UnknownHiveRoleSnafu {
270-
role: rolegroup_ref.role.to_owned(),
271-
roles: HiveRole::roles(),
272-
})?;
273-
274-
let role = self.role(&role_variant)?;
275-
role.role_groups
276-
.get(&rolegroup_ref.role_group)
277-
.with_context(|| CannotRetrieveHiveRoleGroupSnafu {
278-
role_group: rolegroup_ref.role_group.to_owned(),
279-
})
280-
.cloned()
281-
}
282-
283211
pub fn role_config(&self, role: &HiveRole) -> Option<&HiveMetastoreRoleConfig> {
284212
match role {
285213
HiveRole::MetaStore => self.spec.metastore.as_ref().map(|m| &m.role_config),
@@ -326,27 +254,6 @@ pub enum HiveRole {
326254
}
327255

328256
impl HiveRole {
329-
/// Metadata about a rolegroup
330-
pub fn rolegroup_ref(
331-
&self,
332-
hive: &v1alpha1::HiveCluster,
333-
group_name: impl Into<String>,
334-
) -> RoleGroupRef<v1alpha1::HiveCluster> {
335-
RoleGroupRef {
336-
cluster: ObjectRef::from_obj(hive),
337-
role: self.to_string(),
338-
role_group: group_name.into(),
339-
}
340-
}
341-
342-
pub fn roles() -> Vec<String> {
343-
let mut roles = vec![];
344-
for role in Self::iter() {
345-
roles.push(role.to_string())
346-
}
347-
roles
348-
}
349-
350257
/// A Kerberos principal has three parts, with the form username/fully.qualified.domain.name@YOUR-REALM.COM.
351258
/// We only have one role and will use "hive" everywhere (which e.g. differs from the current hdfs implementation).
352259
pub fn kerberos_service_name(&self) -> &'static str {
@@ -466,30 +373,6 @@ pub struct HiveClusterStatus {
466373
pub conditions: Vec<ClusterCondition>,
467374
}
468375

469-
#[derive(Debug, Snafu)]
470-
#[snafu(display("object has no namespace associated"))]
471-
pub struct NoNamespaceError;
472-
473-
/// Reference to a single `Pod` that is a component of a [`HiveCluster`]
474-
/// Used for service discovery.
475-
pub struct PodRef {
476-
pub namespace: String,
477-
pub role_group_service_name: String,
478-
pub pod_name: String,
479-
}
480-
481-
impl PodRef {
482-
pub fn fqdn(&self, cluster_info: &KubernetesClusterInfo) -> String {
483-
format!(
484-
"{pod_name}.{service_name}.{namespace}.svc.{cluster_domain}",
485-
pod_name = self.pod_name,
486-
service_name = self.role_group_service_name,
487-
namespace = self.namespace,
488-
cluster_domain = cluster_info.cluster_domain
489-
)
490-
}
491-
}
492-
493376
#[cfg(test)]
494377
mod tests {
495378
use stackable_operator::versioned::test_utils::RoundtripTestData;

0 commit comments

Comments
 (0)