Skip to content

Commit 239a379

Browse files
Implement affinities
1 parent 3209375 commit 239a379

9 files changed

Lines changed: 125 additions & 56 deletions

File tree

rust/operator-binary/src/controller.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use build::build;
55
use snafu::{ResultExt, Snafu};
66
use stackable_operator::{
77
cluster_resources::ClusterResourceApplyStrategy,
8-
commons::product_image_selection::ProductImage,
8+
commons::{affinity::StackableAffinity, product_image_selection::ProductImage},
99
k8s_openapi::api::{
1010
apps::v1::StatefulSet,
1111
core::v1::{ConfigMap, Service, ServiceAccount},
@@ -28,7 +28,7 @@ use crate::{
2828
},
2929
framework::{
3030
ClusterName, ControllerName, HasNamespace, HasObjectName, HasUid, IsLabelValue,
31-
OperatorName, ProductName, ProductVersion, RoleGroupName,
31+
OperatorName, ProductName, ProductVersion, RoleGroupName, RoleName,
3232
role_utils::{GenericProductSpecificCommonConfig, RoleGroupConfig},
3333
},
3434
};
@@ -103,6 +103,7 @@ type OpenSearchRoleGroupConfig =
103103

104104
#[derive(Clone, Debug, PartialEq)]
105105
pub struct ValidatedOpenSearchConfig {
106+
pub affinity: StackableAffinity,
106107
pub node_roles: NodeRoles,
107108
pub resources: stackable_operator::commons::resources::Resources<v1alpha1::StorageConfig>,
108109
pub termination_grace_period_seconds: i64,
@@ -125,6 +126,10 @@ pub struct ValidatedCluster {
125126
}
126127

127128
impl ValidatedCluster {
129+
pub fn role_name() -> RoleName {
130+
RoleName::from_str("nodes").expect("should be a valid role name")
131+
}
132+
128133
pub fn is_single_node(&self) -> bool {
129134
self.node_count() == 1
130135
}
@@ -233,7 +238,7 @@ pub async fn reconcile(
233238
// dereference (client required)
234239

235240
// validate (no client required)
236-
let validated_cluster = validate(cluster).context(ValidateClusterSnafu)?;
241+
let validated_cluster = validate(&context.names, cluster).context(ValidateClusterSnafu)?;
237242

238243
// build (no client required; infallible)
239244
let prepared_resources = build(&context.names, validated_cluster.clone());

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
use std::{marker::PhantomData, str::FromStr};
1+
use std::marker::PhantomData;
22

33
use role_builder::RoleBuilder;
44

55
use super::{ContextNames, KubernetesResources, Prepared, ValidatedCluster};
6-
use crate::framework::RoleName;
76

87
pub mod node_config;
98
pub mod role_builder;
@@ -14,9 +13,7 @@ pub fn build(names: &ContextNames, cluster: ValidatedCluster) -> KubernetesResou
1413
let mut stateful_sets = vec![];
1514
let mut services = vec![];
1615

17-
let role_name = RoleName::from_str("nodes").expect("should be a valid role name");
18-
19-
let role_builder = RoleBuilder::new(role_name, cluster.clone(), names);
16+
let role_builder = RoleBuilder::new(cluster.clone(), names);
2017

2118
for role_group_builder in role_builder.role_group_builders() {
2219
config_maps.push(role_group_builder.build_config_map());

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

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use super::ValidatedCluster;
55
use crate::{
66
controller::OpenSearchRoleGroupConfig,
77
crd::v1alpha1,
8-
framework::{RoleName, builder::pod::container::EnvVarSet, role_group_utils},
8+
framework::{builder::pod::container::EnvVarSet, role_group_utils},
99
};
1010

1111
pub const CONFIGURATION_FILE_OPENSEARCH_YML: &str = "opensearch.yml";
@@ -67,7 +67,6 @@ pub const CONFIG_OPTION_NODE_ROLES: &str = "node.roles";
6767
pub const CONFIG_OPTION_PLUGINS_SECURITY_NODES_DN: &str = "plugins.security.nodes_dn";
6868

6969
pub struct NodeConfig {
70-
role_name: RoleName,
7170
cluster: ValidatedCluster,
7271
role_group_config: OpenSearchRoleGroupConfig,
7372
discovery_service_name: String,
@@ -77,13 +76,11 @@ pub struct NodeConfig {
7776
// variables.
7877
impl NodeConfig {
7978
pub fn new(
80-
role_name: RoleName,
8179
cluster: ValidatedCluster,
8280
role_group_config: OpenSearchRoleGroupConfig,
8381
discovery_service_name: String,
8482
) -> Self {
8583
Self {
86-
role_name,
8784
cluster,
8885
role_group_config,
8986
discovery_service_name,
@@ -221,7 +218,7 @@ impl NodeConfig {
221218
for (role_group_name, role_group_config) in cluster_manager_configs {
222219
let role_group_resource_names = role_group_utils::ResourceNames {
223220
cluster_name: self.cluster.name.clone(),
224-
role_name: self.role_name.clone(),
221+
role_name: ValidatedCluster::role_name(),
225222
role_group_name,
226223
};
227224

@@ -249,14 +246,18 @@ mod tests {
249246
};
250247

251248
use stackable_operator::{
252-
commons::{product_image_selection::ProductImage, resources::Resources},
249+
commons::{
250+
affinity::StackableAffinity, product_image_selection::ProductImage,
251+
resources::Resources,
252+
},
253253
k8s_openapi::api::core::v1::{EnvVar, EnvVarSource, ObjectFieldSelector, PodTemplateSpec},
254254
kube::api::ObjectMeta,
255255
role_utils::GenericRoleConfig,
256256
};
257257

258258
use super::*;
259259
use crate::{
260+
controller::ValidatedOpenSearchConfig,
260261
crd::NodeRoles,
261262
framework::{ClusterName, ProductVersion, role_utils::GenericProductSpecificCommonConfig},
262263
};
@@ -277,13 +278,14 @@ mod tests {
277278
role_config: GenericRoleConfig::default(),
278279
role_group_configs: BTreeMap::new(),
279280
};
280-
let role_name = RoleName::from_str("nodes").expect("should be a valid role name");
281281

282282
let role_group_config = OpenSearchRoleGroupConfig {
283283
replicas: 1,
284-
config: v1alpha1::OpenSearchConfig {
284+
config: ValidatedOpenSearchConfig {
285+
affinity: StackableAffinity::default(),
285286
node_roles: NodeRoles::default(),
286287
resources: Resources::default(),
288+
termination_grace_period_seconds: 30,
287289
},
288290
config_overrides: HashMap::default(),
289291
env_overrides: [("TEST".to_owned(), "value".to_owned())].into(),
@@ -293,7 +295,6 @@ mod tests {
293295
};
294296

295297
let node_config = NodeConfig::new(
296-
role_name,
297298
cluster,
298299
role_group_config,
299300
"my-opensearch-cluster-manager".to_owned(),

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

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::{
2222
controller::{ContextNames, ValidatedCluster},
2323
crd::v1alpha1,
2424
framework::{
25-
RoleName,
25+
IsLabelValue,
2626
builder::{
2727
meta::ownerreference_from_resource, pdb::pod_disruption_budget_builder_with_role,
2828
},
@@ -33,20 +33,14 @@ use crate::{
3333
const PDB_DEFAULT_MAX_UNAVAILABLE: u16 = 1;
3434

3535
pub struct RoleBuilder<'a> {
36-
role_name: RoleName,
3736
cluster: ValidatedCluster,
3837
context_names: &'a ContextNames,
3938
resource_names: ResourceNames,
4039
}
4140

4241
impl<'a> RoleBuilder<'a> {
43-
pub fn new(
44-
role_name: RoleName,
45-
cluster: ValidatedCluster,
46-
context_names: &'a ContextNames,
47-
) -> RoleBuilder<'a> {
42+
pub fn new(cluster: ValidatedCluster, context_names: &'a ContextNames) -> RoleBuilder<'a> {
4843
RoleBuilder {
49-
role_name: role_name.clone(),
5044
cluster: cluster.clone(),
5145
context_names,
5246
resource_names: ResourceNames {
@@ -64,7 +58,6 @@ impl<'a> RoleBuilder<'a> {
6458
.iter()
6559
.map(|(role_group_name, role_group_config)| {
6660
RoleGroupBuilder::new(
67-
self.role_name.clone(),
6861
self.resource_names.service_account_name(),
6962
self.cluster.clone(),
7063
role_group_name.clone(),
@@ -154,7 +147,7 @@ impl<'a> RoleBuilder<'a> {
154147
pod_disruption_budget_builder_with_role(
155148
&self.cluster,
156149
&self.context_names.product_name,
157-
&self.role_name,
150+
&ValidatedCluster::role_name(),
158151
&self.context_names.operator_name,
159152
&self.context_names.controller_name,
160153
)
@@ -184,8 +177,8 @@ impl<'a> RoleBuilder<'a> {
184177
// Well-known Kubernetes labels
185178
let mut labels = Labels::role_selector(
186179
&self.cluster,
187-
&self.context_names.product_name.to_string(),
188-
&self.role_name.to_string(),
180+
&self.context_names.product_name.to_label_value(),
181+
&ValidatedCluster::role_name().to_label_value(),
189182
)
190183
.unwrap();
191184

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

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use stackable_operator::{
55
api::{
66
apps::v1::{StatefulSet, StatefulSetSpec},
77
core::v1::{
8-
ConfigMap, ConfigMapVolumeSource, Container, ContainerPort, PodSecurityContext,
9-
PodSpec, PodTemplateSpec, Probe, Service, ServicePort, ServiceSpec,
10-
TCPSocketAction, Volume, VolumeMount,
8+
Affinity, ConfigMap, ConfigMapVolumeSource, Container, ContainerPort,
9+
PodSecurityContext, PodSpec, PodTemplateSpec, Probe, Service, ServicePort,
10+
ServiceSpec, TCPSocketAction, Volume, VolumeMount,
1111
},
1212
},
1313
apimachinery::pkg::{apis::meta::v1::LabelSelector, util::intstr::IntOrString},
@@ -20,7 +20,7 @@ use super::node_config::{CONFIGURATION_FILE_OPENSEARCH_YML, NodeConfig};
2020
use crate::{
2121
controller::{ContextNames, OpenSearchRoleGroupConfig, ValidatedCluster},
2222
framework::{
23-
RoleGroupName, RoleName,
23+
RoleGroupName,
2424
builder::meta::ownerreference_from_resource,
2525
kvp::label::{recommended_labels, role_group_selector},
2626
role_group_utils::ResourceNames,
@@ -39,7 +39,6 @@ const DATA_VOLUME_NAME: &str = "data";
3939
const OPENSEARCH_BASE_PATH: &str = "/usr/share/opensearch";
4040

4141
pub struct RoleGroupBuilder<'a> {
42-
role_name: RoleName,
4342
service_account_name: String,
4443
cluster: ValidatedCluster,
4544
node_config: NodeConfig,
@@ -51,7 +50,6 @@ pub struct RoleGroupBuilder<'a> {
5150

5251
impl<'a> RoleGroupBuilder<'a> {
5352
pub fn new(
54-
role_name: RoleName,
5553
service_account_name: String,
5654
cluster: ValidatedCluster,
5755
role_group_name: RoleGroupName,
@@ -60,11 +58,9 @@ impl<'a> RoleGroupBuilder<'a> {
6058
discovery_service_name: String,
6159
) -> RoleGroupBuilder<'a> {
6260
RoleGroupBuilder {
63-
role_name: role_name.clone(),
6461
service_account_name,
6562
cluster: cluster.clone(),
6663
node_config: NodeConfig::new(
67-
role_name.clone(),
6864
cluster.clone(),
6965
role_group_config.clone(),
7066
discovery_service_name,
@@ -74,7 +70,7 @@ impl<'a> RoleGroupBuilder<'a> {
7470
context_names,
7571
resource_names: ResourceNames {
7672
cluster_name: cluster.name.clone(),
77-
role_name,
73+
role_name: ValidatedCluster::role_name(),
7874
role_group_name,
7975
},
8076
}
@@ -136,6 +132,7 @@ impl<'a> RoleGroupBuilder<'a> {
136132
let mut node_role_labels = Labels::new();
137133
for node_role in self.role_group_config.config.node_roles.iter() {
138134
node_role_labels.insert(
135+
// TODO Prefix the key
139136
Label::try_from((format!("{node_role}"), "true".to_string()))
140137
.expect("should be a valid label"),
141138
);
@@ -155,7 +152,24 @@ impl<'a> RoleGroupBuilder<'a> {
155152
let mut pod_template = PodTemplateSpec {
156153
metadata: Some(metadata),
157154
spec: Some(PodSpec {
155+
affinity: Some(Affinity {
156+
node_affinity: self.role_group_config.config.affinity.node_affinity.clone(),
157+
pod_affinity: self.role_group_config.config.affinity.pod_affinity.clone(),
158+
pod_anti_affinity: self
159+
.role_group_config
160+
.config
161+
.affinity
162+
.pod_anti_affinity
163+
.clone(),
164+
}),
158165
containers: vec![container],
166+
node_selector: self
167+
.role_group_config
168+
.config
169+
.affinity
170+
.node_selector
171+
.clone()
172+
.map(|wrapped| wrapped.node_selector),
159173
security_context: Some(PodSecurityContext {
160174
fs_group: Some(1000),
161175
..PodSecurityContext::default()
@@ -326,7 +340,7 @@ impl<'a> RoleGroupBuilder<'a> {
326340
&self.cluster.product_version,
327341
&self.context_names.operator_name,
328342
&self.context_names.controller_name,
329-
&self.role_name,
343+
&ValidatedCluster::role_name(),
330344
&self.role_group_name,
331345
)
332346
}
@@ -335,7 +349,7 @@ impl<'a> RoleGroupBuilder<'a> {
335349
role_group_selector(
336350
&self.cluster,
337351
&self.context_names.product_name,
338-
&self.role_name,
352+
&ValidatedCluster::role_name(),
339353
&self.role_group_name,
340354
)
341355
}

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ use stackable_operator::{
88
};
99
use strum::{EnumDiscriminants, IntoStaticStr};
1010

11-
use super::{ProductVersion, RoleGroupName, ValidatedCluster, ValidatedOpenSearchConfig};
11+
use super::{
12+
ContextNames, ProductVersion, RoleGroupName, ValidatedCluster, ValidatedOpenSearchConfig,
13+
};
1214
use crate::{
1315
crd::v1alpha1::{self, OpenSearchConfig},
1416
framework::{
@@ -54,7 +56,10 @@ type Result<T, E = Error> = std::result::Result<T, E>;
5456

5557
// TODO split
5658
// no client needed
57-
pub fn validate(cluster: &v1alpha1::OpenSearchCluster) -> Result<ValidatedCluster> {
59+
pub fn validate(
60+
names: &ContextNames,
61+
cluster: &v1alpha1::OpenSearchCluster,
62+
) -> Result<ValidatedCluster> {
5863
let raw_cluster_name = cluster.meta().name.clone().context(GetClusterNameSnafu)?;
5964
let cluster_name = ClusterName::from_str(&raw_cluster_name).context(ParseClusterNameSnafu)?;
6065

@@ -73,7 +78,11 @@ pub fn validate(cluster: &v1alpha1::OpenSearchCluster) -> Result<ValidatedCluste
7378
let merged_role_group: RoleGroup<OpenSearchConfig, _> = with_validated_config(
7479
role_group_config,
7580
&cluster.spec.nodes,
76-
&v1alpha1::OpenSearchConfig::default_config(),
81+
&v1alpha1::OpenSearchConfig::default_config(
82+
&names.product_name,
83+
&cluster_name,
84+
&ValidatedCluster::role_name(),
85+
),
7786
)
7887
.context(ValidateOpenSearchConfigSnafu)?;
7988

@@ -87,6 +96,7 @@ pub fn validate(cluster: &v1alpha1::OpenSearchCluster) -> Result<ValidatedCluste
8796
})?;
8897

8998
let validated_config = ValidatedOpenSearchConfig {
99+
affinity: merged_role_group.config.config.affinity,
90100
node_roles: merged_role_group.config.config.node_roles,
91101
resources: merged_role_group.config.config.resources,
92102
termination_grace_period_seconds,

0 commit comments

Comments
 (0)