Skip to content

Commit b655fe7

Browse files
committed
Add affinity structs (#556)
## Description For stackabletech/issues#323
1 parent 0a99c46 commit b655fe7

File tree

6 files changed

+452
-170
lines changed

6 files changed

+452
-170
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ All notable changes to this project will be documented in this file.
99
### Added
1010

1111
- Added airlift json source and airlift json transform to vector.toml ([#553]).
12+
- Added commons structs as well as helper functions for Affinity ([#556]).
1213

1314
[#553]: https://github.com/stackabletech/operator-rs/pull/553
15+
[#556]: https://github.com/stackabletech/operator-rs/pull/556
1416

1517
## [0.34.0] - 2023-02-06
1618

src/builder/pod/mod.rs

Lines changed: 33 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,22 @@ pub mod container;
22
pub mod security;
33
pub mod volume;
44

5+
use std::collections::BTreeMap;
6+
57
use crate::builder::meta::ObjectMetaBuilder;
8+
use crate::commons::affinity::StackableAffinity;
69
use crate::commons::product_image_selection::ResolvedProductImage;
710
use crate::error::{Error, OperatorResult};
811

912
use super::{ListenerOperatorVolumeSourceBuilder, ListenerReference, VolumeBuilder};
1013
use k8s_openapi::apimachinery::pkg::api::resource::Quantity;
1114
use k8s_openapi::{
1215
api::core::v1::{
13-
Affinity, Container, LocalObjectReference, NodeAffinity, NodeSelector,
14-
NodeSelectorRequirement, NodeSelectorTerm, Pod, PodAffinity, PodAntiAffinity, PodCondition,
15-
PodSecurityContext, PodSpec, PodStatus, PodTemplateSpec, Toleration, Volume,
16+
Affinity, Container, LocalObjectReference, NodeAffinity, Pod, PodAffinity, PodAntiAffinity,
17+
PodCondition, PodSecurityContext, PodSpec, PodStatus, PodTemplateSpec, Toleration, Volume,
1618
},
17-
apimachinery::pkg::apis::meta::v1::{LabelSelector, LabelSelectorRequirement, ObjectMeta},
19+
apimachinery::pkg::apis::meta::v1::ObjectMeta,
1820
};
19-
use std::collections::BTreeMap;
2021

2122
/// A builder to build [`Pod`] or [`PodTemplateSpec`] objects.
2223
#[derive(Clone, Default)]
@@ -26,7 +27,8 @@ pub struct PodBuilder {
2627
init_containers: Option<Vec<Container>>,
2728
metadata: Option<ObjectMeta>,
2829
node_name: Option<String>,
29-
node_selector: Option<LabelSelector>,
30+
node_selector: Option<BTreeMap<String, String>>,
31+
node_affinity: Option<NodeAffinity>,
3032
pod_affinity: Option<PodAffinity>,
3133
pod_anti_affinity: Option<PodAntiAffinity>,
3234
status: Option<PodStatus>,
@@ -82,6 +84,16 @@ impl PodBuilder {
8284
self
8385
}
8486

87+
pub fn node_affinity(&mut self, affinity: NodeAffinity) -> &mut Self {
88+
self.node_affinity = Some(affinity);
89+
self
90+
}
91+
92+
pub fn node_affinity_opt(&mut self, affinity: Option<NodeAffinity>) -> &mut Self {
93+
self.node_affinity = affinity;
94+
self
95+
}
96+
8597
pub fn pod_affinity(&mut self, affinity: PodAffinity) -> &mut Self {
8698
self.pod_affinity = Some(affinity);
8799
self
@@ -102,16 +114,27 @@ impl PodBuilder {
102114
self
103115
}
104116

105-
pub fn node_selector(&mut self, node_selector: LabelSelector) -> &mut Self {
117+
pub fn node_selector(&mut self, node_selector: BTreeMap<String, String>) -> &mut Self {
106118
self.node_selector = Some(node_selector);
107119
self
108120
}
109121

110-
pub fn node_selector_opt(&mut self, node_selector: Option<LabelSelector>) -> &mut Self {
122+
pub fn node_selector_opt(
123+
&mut self,
124+
node_selector: Option<BTreeMap<String, String>>,
125+
) -> &mut Self {
111126
self.node_selector = node_selector;
112127
self
113128
}
114129

130+
pub fn affinity(&mut self, affinities: &StackableAffinity) -> &mut Self {
131+
self.pod_affinity = affinities.pod_affinity.clone();
132+
self.pod_anti_affinity = affinities.pod_anti_affinity.clone();
133+
self.node_affinity = affinities.node_affinity.clone();
134+
self.node_selector = affinities.node_selector.clone().map(|ns| ns.node_selector);
135+
self
136+
}
137+
115138
pub fn phase(&mut self, phase: &str) -> &mut Self {
116139
let mut status = self.status.get_or_insert_with(PodStatus::default);
117140
status.phase = Some(phase.to_string());
@@ -338,58 +361,15 @@ impl PodBuilder {
338361
self
339362
}
340363

341-
/// Hack because [`Pod`] predates [`LabelSelector`], and so its functionality is split between [`PodSpec::node_selector`] and [`Affinity::node_affinity`]
342-
fn node_selector_for_label_selector(
343-
label_selector: Option<LabelSelector>,
344-
) -> (Option<BTreeMap<String, String>>, Option<NodeAffinity>) {
345-
let (node_labels, node_label_exprs) = match label_selector {
346-
Some(LabelSelector {
347-
match_labels,
348-
match_expressions,
349-
}) => (match_labels, match_expressions),
350-
None => (None, None),
351-
};
352-
353-
let node_affinity = node_label_exprs.map(|node_label_exprs| NodeAffinity {
354-
required_during_scheduling_ignored_during_execution: Some(NodeSelector {
355-
node_selector_terms: vec![NodeSelectorTerm {
356-
match_expressions: Some(
357-
node_label_exprs
358-
.into_iter()
359-
.map(
360-
|LabelSelectorRequirement {
361-
key,
362-
operator,
363-
values,
364-
}| {
365-
NodeSelectorRequirement {
366-
key,
367-
operator,
368-
values,
369-
}
370-
},
371-
)
372-
.collect(),
373-
),
374-
..NodeSelectorTerm::default()
375-
}],
376-
}),
377-
..NodeAffinity::default()
378-
});
379-
(node_labels, node_affinity)
380-
}
381-
382364
fn build_spec(&self) -> PodSpec {
383-
let (node_selector_labels, node_affinity) =
384-
Self::node_selector_for_label_selector(self.node_selector.clone());
385365
PodSpec {
386366
containers: self.containers.clone(),
387367
host_network: self.host_network,
388368
init_containers: self.init_containers.clone(),
389369
node_name: self.node_name.clone(),
390-
node_selector: node_selector_labels,
370+
node_selector: self.node_selector.clone(),
391371
affinity: Some(Affinity {
392-
node_affinity,
372+
node_affinity: self.node_affinity.clone(),
393373
pod_affinity: self.pod_affinity.clone(),
394374
pod_anti_affinity: self.pod_anti_affinity.clone(),
395375
}),
@@ -463,38 +443,6 @@ mod tests {
463443
builder
464444
}
465445

466-
// A fixture for a node selector to use on a Pod, and the resulting node selector labels and node affinity.
467-
#[fixture]
468-
fn node_selector1() -> (
469-
LabelSelector,
470-
Option<BTreeMap<String, String>>,
471-
Option<NodeAffinity>,
472-
) {
473-
let labels = BTreeMap::from([("key".to_owned(), "value".to_owned())]);
474-
let label_selector = LabelSelector {
475-
match_expressions: Some(vec![LabelSelectorRequirement {
476-
key: "security".to_owned(),
477-
operator: "In".to_owned(),
478-
values: Some(vec!["S1".to_owned(), "S2".to_owned()]),
479-
}]),
480-
match_labels: Some(labels.clone()),
481-
};
482-
let affinity = Some(NodeAffinity {
483-
required_during_scheduling_ignored_during_execution: Some(NodeSelector {
484-
node_selector_terms: vec![NodeSelectorTerm {
485-
match_expressions: Some(vec![NodeSelectorRequirement {
486-
key: "security".to_owned(),
487-
operator: "In".to_owned(),
488-
values: Some(vec!["S1".to_owned(), "S2".to_owned()]),
489-
}]),
490-
..Default::default()
491-
}],
492-
}),
493-
..Default::default()
494-
});
495-
(label_selector, Some(labels), affinity)
496-
}
497-
498446
#[fixture]
499447
fn pod_affinity() -> PodAffinity {
500448
PodAffinity {
@@ -594,88 +542,4 @@ mod tests {
594542
}]
595543
);
596544
}
597-
598-
/// Test if setting a node selector generates the correct node selector labels and node affinity on the Pod.
599-
#[rstest]
600-
fn test_pod_builder_node_selector(
601-
mut pod_builder_with_name_and_container: PodBuilder,
602-
node_selector1: (
603-
LabelSelector,
604-
Option<BTreeMap<String, String>>,
605-
Option<NodeAffinity>,
606-
),
607-
) {
608-
// destruct fixture
609-
let (node_selector, expected_labels, expected_affinity) = node_selector1;
610-
// first test with the normal node_selector function
611-
let pod = pod_builder_with_name_and_container
612-
.clone()
613-
.node_selector(node_selector.clone())
614-
.build()
615-
.unwrap();
616-
617-
let spec = pod.spec.unwrap();
618-
assert_eq!(spec.node_selector, expected_labels);
619-
assert_eq!(spec.affinity.unwrap().node_affinity, expected_affinity);
620-
621-
// test the node_selector_opt function
622-
let pod = pod_builder_with_name_and_container
623-
.node_selector_opt(Some(node_selector))
624-
.build()
625-
.unwrap();
626-
627-
// asserts
628-
let spec = pod.spec.unwrap();
629-
assert_eq!(spec.node_selector, expected_labels);
630-
assert_eq!(spec.affinity.unwrap().node_affinity, expected_affinity);
631-
}
632-
633-
/// Test if setting a node selector generates the correct node selector labels and node affinity on the Pod,
634-
/// while keeping the manually set Pod affinities. Since they are mangled together, it makes sense to make sure that
635-
/// one is not replacing the other
636-
#[rstest]
637-
fn test_pod_builder_node_selector_and_affinity(
638-
mut pod_builder_with_name_and_container: PodBuilder,
639-
node_selector1: (
640-
LabelSelector,
641-
Option<BTreeMap<String, String>>,
642-
Option<NodeAffinity>,
643-
),
644-
pod_affinity: PodAffinity,
645-
pod_anti_affinity: PodAntiAffinity,
646-
) {
647-
// destruct fixture
648-
let (node_selector, expected_labels, expected_affinity) = node_selector1;
649-
// first test with the normal functions
650-
let pod = pod_builder_with_name_and_container
651-
.clone()
652-
.node_selector(node_selector.clone())
653-
.pod_affinity(pod_affinity.clone())
654-
.pod_anti_affinity(pod_anti_affinity.clone())
655-
.build()
656-
.unwrap();
657-
658-
let spec = pod.spec.unwrap();
659-
assert_eq!(spec.node_selector, expected_labels);
660-
let affinity = spec.affinity.unwrap();
661-
assert_eq!(affinity.node_affinity, expected_affinity);
662-
assert_eq!(affinity.pod_affinity, Some(pod_affinity.clone()));
663-
assert_eq!(affinity.pod_anti_affinity, Some(pod_anti_affinity.clone()));
664-
665-
// test the *_opt functions
666-
let pod = pod_builder_with_name_and_container
667-
.node_selector_opt(Some(node_selector))
668-
.pod_affinity_opt(Some(pod_affinity.clone()))
669-
.pod_anti_affinity_opt(Some(pod_anti_affinity.clone()))
670-
.build()
671-
.unwrap();
672-
673-
// asserts
674-
let spec = pod.spec.unwrap();
675-
assert_eq!(spec.node_selector, expected_labels);
676-
let affinity = spec.affinity.unwrap();
677-
assert_eq!(affinity.node_affinity, expected_affinity);
678-
assert_eq!(affinity.pod_affinity, Some(pod_affinity));
679-
assert_eq!(affinity.pod_anti_affinity, Some(pod_anti_affinity));
680-
}
681545
}

0 commit comments

Comments
 (0)