Skip to content

Commit 88c2129

Browse files
committed
refactor: move ValidatedCluster + siblings to controller/mod.rs
1 parent 8e8095f commit 88c2129

8 files changed

Lines changed: 242 additions & 226 deletions

File tree

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ use stackable_operator::{
1010
};
1111

1212
use crate::{
13-
controller::build::properties::{
14-
ConfigFileName, core_site, hadoop_policy, hdfs_site, logging, security_properties,
15-
ssl_client, ssl_server,
13+
controller::{
14+
ValidatedCluster,
15+
build::properties::{
16+
ConfigFileName, core_site, hadoop_policy, hdfs_site, logging, security_properties,
17+
ssl_client, ssl_server,
18+
},
1619
},
1720
crd::{HdfsNodeRole, v1alpha1},
18-
hdfs_controller::ValidatedCluster,
1921
};
2022

2123
#[derive(Snafu, Debug)]

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ use stackable_operator::{
1010
use crate::{
1111
build_recommended_labels,
1212
config::{CoreSiteConfigBuilder, HdfsSiteConfigBuilder},
13-
controller::build::properties::ConfigFileName,
13+
controller::{ValidatedCluster, build::properties::ConfigFileName},
1414
crd::{HdfsNodeRole, HdfsPodRef},
15-
hdfs_controller::{HDFS_CONTROLLER_NAME, ValidatedCluster},
15+
hdfs_controller::HDFS_CONTROLLER_NAME,
1616
security::kerberos::KerberosConfig,
1717
};
1818

rust/operator-binary/src/controller/build/properties/core_site.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ use stackable_operator::{
77
};
88

99
use crate::{
10-
config::CoreSiteConfigBuilder, controller::build::properties::resolved_overrides,
11-
crd::HdfsNodeRole, hdfs_controller::ValidatedCluster, security::kerberos::KerberosConfig,
10+
config::CoreSiteConfigBuilder,
11+
controller::{ValidatedCluster, build::properties::resolved_overrides},
12+
crd::HdfsNodeRole,
13+
security::kerberos::KerberosConfig,
1214
};
1315

1416
/// Renders `core-site.xml`: operator defaults + kerberos/OPA security config,

rust/operator-binary/src/controller/build/properties/hdfs_site.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ use stackable_operator::{
88

99
use crate::{
1010
config::HdfsSiteConfigBuilder,
11-
controller::build::properties::resolved_overrides,
11+
controller::{ValidatedCluster, build::properties::resolved_overrides},
1212
crd::{AnyNodeConfig, HdfsNodeRole},
13-
hdfs_controller::ValidatedCluster,
1413
};
1514

1615
/// Renders `hdfs-site.xml`: operator defaults, HA wiring derived from the pod

rust/operator-binary/src/controller/build/properties/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ pub(crate) mod test_support {
7575
};
7676

7777
use crate::{
78-
controller::validate::validate_cluster, crd::v1alpha1, hdfs_controller::ValidatedCluster,
78+
controller::{ValidatedCluster, validate::validate_cluster},
79+
crd::v1alpha1,
7980
};
8081

8182
/// Builds a [`KeyValueConfigOverrides`] from `(key, value)` pairs for tests.
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,217 @@
1+
use std::collections::{BTreeMap, HashMap};
2+
3+
use stackable_operator::{
4+
builder::meta::ObjectMetaBuilder,
5+
commons::product_image_selection::ResolvedProductImage,
6+
kube::{Resource, api::ObjectMeta},
7+
role_utils::RoleGroupRef,
8+
v2::types::{
9+
kubernetes::{NamespaceName, Uid},
10+
operator::ClusterName,
11+
},
12+
};
13+
14+
use crate::{
15+
build_recommended_labels,
16+
crd::{AnyNodeConfig, HdfsNodeRole, HdfsPodRef, security::AuthenticationConfig, v1alpha1},
17+
hdfs_controller::RESOURCE_MANAGER_HDFS_CONTROLLER,
18+
security::opa::HdfsOpaConfig,
19+
};
20+
121
pub mod build;
222
pub mod dereference;
323
pub mod validate;
24+
25+
/// The validated cluster: proves that config merging and validation succeeded
26+
/// for every role and role group before any resources are created. Placed in the
27+
/// controller so that subsequent steps that reference this struct only depend on
28+
/// the controller.
29+
#[derive(Clone, Debug)]
30+
pub struct ValidatedCluster {
31+
/// The cluster's object metadata (name, namespace and uid). Kept private and only
32+
/// exposed via the [`Resource`] implementation so this type can act as the owner
33+
/// when building owned objects.
34+
metadata: ObjectMeta,
35+
/// The logical (and Kubernetes object) name of the cluster.
36+
pub name: ClusterName,
37+
/// The cluster namespace, used to build kerberos principals.
38+
pub namespace: NamespaceName,
39+
pub image: ResolvedProductImage,
40+
pub cluster_config: ValidatedClusterConfig,
41+
pub role_groups: BTreeMap<HdfsNodeRole, BTreeMap<String, ValidatedRoleGroupConfig>>,
42+
pub role_configs: BTreeMap<HdfsNodeRole, ValidatedRoleConfig>,
43+
}
44+
45+
impl ValidatedCluster {
46+
pub fn new(
47+
name: ClusterName,
48+
namespace: NamespaceName,
49+
uid: Uid,
50+
image: ResolvedProductImage,
51+
cluster_config: ValidatedClusterConfig,
52+
role_groups: BTreeMap<HdfsNodeRole, BTreeMap<String, ValidatedRoleGroupConfig>>,
53+
role_configs: BTreeMap<HdfsNodeRole, ValidatedRoleConfig>,
54+
) -> Self {
55+
Self {
56+
metadata: ObjectMeta {
57+
name: Some(name.to_string()),
58+
namespace: Some(namespace.to_string()),
59+
// The uid is required so this type can produce valid owner references
60+
// (Kubernetes rejects owner references without a uid).
61+
uid: Some(uid.to_string()),
62+
..ObjectMeta::default()
63+
},
64+
name,
65+
namespace,
66+
image,
67+
cluster_config,
68+
role_groups,
69+
role_configs,
70+
}
71+
}
72+
73+
/// Builds the [`HdfsPodRef`]s expected for every pod of the given `role`, across
74+
/// all of its role groups.
75+
///
76+
/// These pod refs can only access HDFS from inside the Kubernetes cluster (they
77+
/// use the cluster-internal headless service DNS names). For downstream clients,
78+
/// the listener-based refs collected during reconciliation are used instead.
79+
///
80+
/// This is infallible: all required information (namespace, replicas and ports)
81+
/// is already resolved on `self` during validation.
82+
pub fn pod_refs(&self, role: &HdfsNodeRole) -> Vec<HdfsPodRef> {
83+
let ports: HashMap<String, u16> =
84+
crate::crd::role_data_ports(role, self.cluster_config.authentication.is_some())
85+
.into_iter()
86+
.collect();
87+
88+
self.role_groups
89+
.get(role)
90+
.into_iter()
91+
.flatten()
92+
.flat_map(|(role_group_name, role_group)| {
93+
let object_name = format!("{}-{role}-{role_group_name}", self.name);
94+
let ports = ports.clone();
95+
(0..role_group.replicas).map(move |i| HdfsPodRef {
96+
namespace: self.namespace.to_string(),
97+
role_group_service_name: object_name.clone(),
98+
pod_name: format!("{object_name}-{i}"),
99+
ports: ports.clone(),
100+
fqdn_override: None,
101+
})
102+
})
103+
.collect()
104+
}
105+
106+
/// Builds the common [`ObjectMetaBuilder`] shared by a role group's owned resources
107+
/// (the ConfigMap and the StatefulSet): name, namespace, owner reference and the
108+
/// recommended labels, all derived from this validated cluster.
109+
///
110+
/// This is infallible: a [`ValidatedCluster`] always carries a name, namespace and
111+
/// uid, and its fail-safe typed values always produce valid label values, so neither
112+
/// the owner reference nor the recommended labels can fail to build.
113+
pub fn rolegroup_metadata(
114+
&self,
115+
rolegroup_ref: &RoleGroupRef<v1alpha1::HdfsCluster>,
116+
) -> ObjectMetaBuilder {
117+
let mut metadata = ObjectMetaBuilder::new();
118+
metadata
119+
.name_and_namespace(self)
120+
.name(rolegroup_ref.object_name())
121+
.ownerreference_from_resource(self, None, Some(true))
122+
.expect(
123+
"the owner reference is valid because the ValidatedCluster has an \
124+
api_version, kind, name and uid",
125+
)
126+
.with_recommended_labels(&build_recommended_labels(
127+
self,
128+
RESOURCE_MANAGER_HDFS_CONTROLLER,
129+
&self.image.app_version_label_value,
130+
&rolegroup_ref.role,
131+
&rolegroup_ref.role_group,
132+
))
133+
.expect(
134+
"the recommended labels are valid because the ValidatedCluster uses \
135+
fail-safe typed values",
136+
);
137+
metadata
138+
}
139+
}
140+
141+
/// Lets [`ValidatedCluster`] be used as the owner [`Resource`] (e.g. in
142+
/// [`ObjectMetaBuilder::ownerreference_from_resource`]). The kind/group/version/plural
143+
/// are delegated to [`v1alpha1::HdfsCluster`] so the generated owner references are
144+
/// identical to the ones built from the raw cluster object.
145+
impl Resource for ValidatedCluster {
146+
type DynamicType = <v1alpha1::HdfsCluster as Resource>::DynamicType;
147+
type Scope = <v1alpha1::HdfsCluster as Resource>::Scope;
148+
149+
fn kind(dt: &Self::DynamicType) -> std::borrow::Cow<'_, str> {
150+
v1alpha1::HdfsCluster::kind(dt)
151+
}
152+
153+
fn group(dt: &Self::DynamicType) -> std::borrow::Cow<'_, str> {
154+
v1alpha1::HdfsCluster::group(dt)
155+
}
156+
157+
fn version(dt: &Self::DynamicType) -> std::borrow::Cow<'_, str> {
158+
v1alpha1::HdfsCluster::version(dt)
159+
}
160+
161+
fn plural(dt: &Self::DynamicType) -> std::borrow::Cow<'_, str> {
162+
v1alpha1::HdfsCluster::plural(dt)
163+
}
164+
165+
fn meta(&self) -> &ObjectMeta {
166+
&self.metadata
167+
}
168+
169+
fn meta_mut(&mut self) -> &mut ObjectMeta {
170+
&mut self.metadata
171+
}
172+
}
173+
174+
/// Cluster-wide settings resolved once during validation, so the build steps no
175+
/// longer need the raw `HdfsCluster` to render config.
176+
#[derive(Clone, Debug)]
177+
pub struct ValidatedClusterConfig {
178+
pub dfs_replication: u8,
179+
/// The authentication config, if configured. Its presence enables both Kerberos
180+
/// and HTTPS; it also carries the TLS and Kerberos secret class names.
181+
pub authentication: Option<AuthenticationConfig>,
182+
/// The resolved OPA authorization config, if authorization is configured.
183+
pub authorization: Option<HdfsOpaConfig>,
184+
pub rack_awareness: Option<String>,
185+
}
186+
187+
impl ValidatedClusterConfig {
188+
pub fn resolve(
189+
hdfs: &v1alpha1::HdfsCluster,
190+
authorization: Option<HdfsOpaConfig>,
191+
) -> ValidatedClusterConfig {
192+
ValidatedClusterConfig {
193+
dfs_replication: hdfs.spec.cluster_config.dfs_replication,
194+
authentication: hdfs.authentication_config().cloned(),
195+
authorization,
196+
rack_awareness: hdfs.rackawareness_config(),
197+
}
198+
}
199+
}
200+
201+
/// Per-role configuration extracted during validation.
202+
#[derive(Clone, Debug)]
203+
pub struct ValidatedRoleConfig {
204+
pub pdb: stackable_operator::commons::pdb::PdbConfig,
205+
}
206+
207+
/// Per-rolegroup configuration: the merged CRD config plus the merged
208+
/// (role <- role group) `configOverrides` and `envOverrides`.
209+
#[derive(Clone, Debug)]
210+
pub struct ValidatedRoleGroupConfig {
211+
/// The number of replicas (pods) for this role group, used to derive the
212+
/// per-pod [`HdfsPodRef`]s via [`ValidatedCluster::pod_refs`].
213+
pub replicas: u16,
214+
pub config: AnyNodeConfig,
215+
pub config_overrides: v1alpha1::HdfsConfigOverrides,
216+
pub env_overrides: BTreeMap<String, String>,
217+
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ use stackable_operator::{
1717
use strum::IntoEnumIterator;
1818

1919
use crate::{
20-
crd::{HdfsNodeRole, v1alpha1},
21-
hdfs_controller::{
22-
CONTAINER_IMAGE_BASE_NAME, ValidatedCluster, ValidatedClusterConfig, ValidatedRoleConfig,
23-
ValidatedRoleGroupConfig,
20+
controller::{
21+
ValidatedCluster, ValidatedClusterConfig, ValidatedRoleConfig, ValidatedRoleGroupConfig,
2422
},
23+
crd::{HdfsNodeRole, v1alpha1},
24+
hdfs_controller::CONTAINER_IMAGE_BASE_NAME,
2525
security::opa::HdfsOpaConfig,
2626
};
2727

0 commit comments

Comments
 (0)