Skip to content

Commit 3ab493c

Browse files
committed
feat: add nodeSelector and tolerations updates in Overcommit reconciler
- Implemented logic to update nodeSelector and tolerations in Overcommit reconciler for deployments. - Added utility functions for tolerations comparison. - Created tests for tolerations equality. - Added example YAML files for validating nodeSelector and tolerations.
1 parent 055e4c6 commit 3ab493c

8 files changed

Lines changed: 287 additions & 0 deletions

File tree

internal/controller/overcommit/overcommit_controller.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,16 @@ func (r *OvercommitReconciler) Reconcile(ctx context.Context, req ctrl.Request)
174174
overcommitClassDeployment.Spec.Template.Labels = updatedDeployment.Spec.Template.Labels
175175
updated = true
176176
}
177+
// Update nodeSelector if it changed
178+
if !mapsEqual(updatedDeployment.Spec.Template.Spec.NodeSelector, overcommitClassDeployment.Spec.Template.Spec.NodeSelector) {
179+
overcommitClassDeployment.Spec.Template.Spec.NodeSelector = updatedDeployment.Spec.Template.Spec.NodeSelector
180+
updated = true
181+
}
182+
// Update tolerations if they changed
183+
if !utils.TolerationsEqual(ctx, updatedDeployment.Spec.Template.Spec.Tolerations, overcommitClassDeployment.Spec.Template.Spec.Tolerations) {
184+
overcommitClassDeployment.Spec.Template.Spec.Tolerations = updatedDeployment.Spec.Template.Spec.Tolerations
185+
updated = true
186+
}
177187
// Only set controller reference if we actually updated something
178188
if updated {
179189
return ctrl.SetControllerReference(overcommit, overcommitClassDeployment, r.Scheme)
@@ -270,6 +280,16 @@ func (r *OvercommitReconciler) Reconcile(ctx context.Context, req ctrl.Request)
270280
validatingPodDeployment.Spec.Template.Labels = updatedDeployment.Spec.Template.Labels
271281
updated = true
272282
}
283+
// Update nodeSelector if it changed
284+
if !mapsEqual(updatedDeployment.Spec.Template.Spec.NodeSelector, validatingPodDeployment.Spec.Template.Spec.NodeSelector) {
285+
validatingPodDeployment.Spec.Template.Spec.NodeSelector = updatedDeployment.Spec.Template.Spec.NodeSelector
286+
updated = true
287+
}
288+
// Update tolerations if they changed
289+
if !utils.TolerationsEqual(ctx, updatedDeployment.Spec.Template.Spec.Tolerations, validatingPodDeployment.Spec.Template.Spec.Tolerations) {
290+
validatingPodDeployment.Spec.Template.Spec.Tolerations = updatedDeployment.Spec.Template.Spec.Tolerations
291+
updated = true
292+
}
273293
// Only set controller reference if we actually updated something
274294
if updated {
275295
return ctrl.SetControllerReference(overcommit, validatingPodDeployment, r.Scheme)
@@ -353,6 +373,16 @@ func (r *OvercommitReconciler) Reconcile(ctx context.Context, req ctrl.Request)
353373
occontroller.Spec.Template.Labels = updatedDeployment.Spec.Template.Labels
354374
updated = true
355375
}
376+
// Update nodeSelector if it changed
377+
if !mapsEqual(updatedDeployment.Spec.Template.Spec.NodeSelector, occontroller.Spec.Template.Spec.NodeSelector) {
378+
occontroller.Spec.Template.Spec.NodeSelector = updatedDeployment.Spec.Template.Spec.NodeSelector
379+
updated = true
380+
}
381+
// Update tolerations if they changed
382+
if !utils.TolerationsEqual(ctx, updatedDeployment.Spec.Template.Spec.Tolerations, occontroller.Spec.Template.Spec.Tolerations) {
383+
occontroller.Spec.Template.Spec.Tolerations = updatedDeployment.Spec.Template.Spec.Tolerations
384+
updated = true
385+
}
356386
// Only set controller reference if we actually updated something
357387
if updated {
358388
return ctrl.SetControllerReference(overcommit, occontroller, r.Scheme)

internal/controller/overcommitclass/overcommitclass_controller.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,18 @@ func (r *OvercommitClassReconciler) Reconcile(ctx context.Context, req ctrl.Requ
202202
updated = true
203203
}
204204

205+
// Update nodeSelector if it changed
206+
if !mapsEqual(updatedDeployment.Spec.Template.Spec.NodeSelector, deployment.Spec.Template.Spec.NodeSelector) {
207+
deployment.Spec.Template.Spec.NodeSelector = updatedDeployment.Spec.Template.Spec.NodeSelector
208+
updated = true
209+
}
210+
211+
// Update tolerations if they changed
212+
if !utils.TolerationsEqual(ctx, updatedDeployment.Spec.Template.Spec.Tolerations, deployment.Spec.Template.Spec.Tolerations) {
213+
deployment.Spec.Template.Spec.Tolerations = updatedDeployment.Spec.Template.Spec.Tolerations
214+
updated = true
215+
}
216+
205217
// Only set controller reference if we actually updated something
206218
if updated {
207219
return controllerutil.SetControllerReference(overcommitClass, deployment, r.Scheme)

internal/utils/comparison.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// SPDX-FileCopyrightText: 2025 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.)
2+
// SPDX-FileContributor: enriqueavi@inditex.com
3+
//
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
package utils
7+
8+
import (
9+
"context"
10+
"strings"
11+
12+
corev1 "k8s.io/api/core/v1"
13+
logf "sigs.k8s.io/controller-runtime/pkg/log"
14+
)
15+
16+
// TolerationsEqual compares two slices of tolerations to see if they're equal
17+
func TolerationsEqual(ctx context.Context, a, b []corev1.Toleration) bool {
18+
logger := logf.FromContext(ctx)
19+
20+
// Handle nil cases
21+
if a == nil && b == nil {
22+
return true
23+
}
24+
if a == nil || b == nil {
25+
logger.V(1).Info("Tolerations comparison: one slice is nil", "aIsNil", a == nil, "bIsNil", b == nil)
26+
return false
27+
}
28+
29+
if len(a) != len(b) {
30+
logger.V(1).Info("Tolerations comparison: different lengths", "lenA", len(a), "lenB", len(b))
31+
return false
32+
}
33+
34+
// Create a map for efficient comparison
35+
tolerationMapA := make(map[string]corev1.Toleration)
36+
for _, tol := range a {
37+
key := createTolerationKey(tol)
38+
tolerationMapA[key] = tol
39+
logger.V(2).Info("Adding toleration to map A", "key", key, "toleration", tol)
40+
}
41+
42+
for _, tol := range b {
43+
key := createTolerationKey(tol)
44+
if _, exists := tolerationMapA[key]; !exists {
45+
logger.V(1).Info("Tolerations comparison: toleration not found", "key", key, "toleration", tol)
46+
return false
47+
}
48+
logger.V(2).Info("Found matching toleration in map A", "key", key, "toleration", tol)
49+
}
50+
51+
logger.V(1).Info("Tolerations comparison: all tolerations match")
52+
return true
53+
}
54+
55+
// createTolerationKey creates a unique key for a toleration for comparison purposes
56+
func createTolerationKey(tol corev1.Toleration) string {
57+
var parts []string
58+
parts = append(parts, tol.Key)
59+
parts = append(parts, string(tol.Operator))
60+
parts = append(parts, tol.Value)
61+
parts = append(parts, string(tol.Effect))
62+
63+
if tol.TolerationSeconds != nil {
64+
parts = append(parts, "seconds-not-nil")
65+
} else {
66+
parts = append(parts, "seconds-nil")
67+
}
68+
69+
return strings.Join(parts, "-")
70+
}

internal/utils/comparison_test.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// SPDX-FileCopyrightText: 2025 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.)
2+
// SPDX-FileContributor: enriqueavi@inditex.com
3+
//
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
package utils
7+
8+
import (
9+
"context"
10+
"testing"
11+
12+
corev1 "k8s.io/api/core/v1"
13+
"sigs.k8s.io/controller-runtime/pkg/log"
14+
)
15+
16+
func TestTolerationsEqual(t *testing.T) {
17+
ctx := log.IntoContext(context.Background(), log.Log)
18+
19+
// Test case 1: Both nil
20+
if !TolerationsEqual(ctx, nil, nil) {
21+
t.Error("Expected true for both nil tolerations")
22+
}
23+
24+
// Test case 2: One nil, one empty
25+
empty := []corev1.Toleration{}
26+
if TolerationsEqual(ctx, nil, empty) {
27+
t.Error("Expected false for nil vs empty tolerations")
28+
}
29+
30+
// Test case 3: Same tolerations
31+
tolerations1 := []corev1.Toleration{
32+
{
33+
Key: "node.kubernetes.io/not-ready",
34+
Operator: corev1.TolerationOpExists,
35+
Effect: corev1.TaintEffectNoExecute,
36+
},
37+
}
38+
tolerations2 := []corev1.Toleration{
39+
{
40+
Key: "node.kubernetes.io/not-ready",
41+
Operator: corev1.TolerationOpExists,
42+
Effect: corev1.TaintEffectNoExecute,
43+
},
44+
}
45+
if !TolerationsEqual(ctx, tolerations1, tolerations2) {
46+
t.Error("Expected true for same tolerations")
47+
}
48+
49+
// Test case 4: Different tolerations
50+
tolerations3 := []corev1.Toleration{
51+
{
52+
Key: "node.kubernetes.io/unreachable",
53+
Operator: corev1.TolerationOpExists,
54+
Effect: corev1.TaintEffectNoExecute,
55+
},
56+
}
57+
if TolerationsEqual(ctx, tolerations1, tolerations3) {
58+
t.Error("Expected false for different tolerations")
59+
}
60+
61+
// Test case 5: Different lengths
62+
tolerations4 := []corev1.Toleration{
63+
{
64+
Key: "node.kubernetes.io/not-ready",
65+
Operator: corev1.TolerationOpExists,
66+
Effect: corev1.TaintEffectNoExecute,
67+
},
68+
{
69+
Key: "node.kubernetes.io/unreachable",
70+
Operator: corev1.TolerationOpExists,
71+
Effect: corev1.TaintEffectNoExecute,
72+
},
73+
}
74+
if TolerationsEqual(ctx, tolerations1, tolerations4) {
75+
t.Error("Expected false for different lengths")
76+
}
77+
78+
// Test case 6: Same tolerations in different order
79+
tolerations5 := []corev1.Toleration{
80+
{
81+
Key: "node.kubernetes.io/unreachable",
82+
Operator: corev1.TolerationOpExists,
83+
Effect: corev1.TaintEffectNoExecute,
84+
},
85+
{
86+
Key: "node.kubernetes.io/not-ready",
87+
Operator: corev1.TolerationOpExists,
88+
Effect: corev1.TaintEffectNoExecute,
89+
},
90+
}
91+
tolerations6 := []corev1.Toleration{
92+
{
93+
Key: "node.kubernetes.io/not-ready",
94+
Operator: corev1.TolerationOpExists,
95+
Effect: corev1.TaintEffectNoExecute,
96+
},
97+
{
98+
Key: "node.kubernetes.io/unreachable",
99+
Operator: corev1.TolerationOpExists,
100+
Effect: corev1.TaintEffectNoExecute,
101+
},
102+
}
103+
if !TolerationsEqual(ctx, tolerations5, tolerations6) {
104+
t.Error("Expected true for same tolerations in different order")
105+
}
106+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# SPDX-FileCopyrightText: 2025 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.)
2+
# SPDX-FileContributor: enriqueavi@inditex.com
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
apiVersion: apps/v1
6+
kind: Deployment
7+
metadata:
8+
name: test8-overcommit-webhook
9+
namespace: k8s-overcommit
10+
spec:
11+
template:
12+
metadata:
13+
labels:
14+
example: "label"
15+
annotations:
16+
example: "annotation"
17+
spec:
18+
nodeSelector:
19+
kubernetes.io/os: linux
20+
tolerations:
21+
- key: "example-key"
22+
operator: "Equal"
23+
value: "example-value"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
apiVersion: overcommit.inditex.dev/v1alphav1
2+
kind: OvercommitClass
3+
metadata:
4+
name: test8
5+
spec:
6+
cpuOvercommit: 0.5
7+
memoryOvercommit: 0.5
8+
isDefault: false
9+
excludedNamespaces: ".*(^(openshift|k8s-overcommit|kube).*).*"
10+
labels:
11+
example: "label"
12+
annotations:
13+
example: "annotation"
14+
nodeSelector:
15+
kubernetes.io/os: linux
16+
tolerations:
17+
- key: "example-key"
18+
operator: "Equal"
19+
value: "example-value"
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# SPDX-FileCopyrightText: 2025 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.)
2+
# SPDX-FileContributor: enriqueavi@inditex.com
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
apiVersion: apps/v1
6+
kind: Deployment
7+
metadata:
8+
name: test8-overcommit-webhook
9+
namespace: k8s-overcommit
10+
spec:
11+
template:
12+
metadata:
13+
labels:
14+
example: "label"
15+
annotations:
16+
example: "annotation"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
apiVersion: overcommit.inditex.dev/v1alphav1
2+
kind: OvercommitClass
3+
metadata:
4+
name: test8
5+
spec:
6+
cpuOvercommit: 0.5
7+
memoryOvercommit: 0.5
8+
isDefault: false
9+
excludedNamespaces: ".*(^(openshift|k8s-overcommit|kube).*).*"
10+
nodeSelector: {}
11+
tolerations: []

0 commit comments

Comments
 (0)