Skip to content

Commit 472a78b

Browse files
committed
Port to cel type
1 parent 70026e1 commit 472a78b

File tree

8 files changed

+182
-117
lines changed

8 files changed

+182
-117
lines changed

api/v1alpha1/nodereadinessrule_types.go

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -45,37 +45,6 @@ const (
4545
TaintStatusAbsent TaintStatus = "Absent"
4646
)
4747

48-
// TaintSpec defines the specific Taint (Key, Value, and Effect) to be managed.
49-
type TaintSpec struct {
50-
// key is the taint key to be applied to a node.
51-
//
52-
// +required
53-
// +kubebuilder:validation:MinLength=17
54-
// +kubebuilder:validation:MaxLength=253
55-
// +kubebuilder:validation:Pattern=`^readiness\.k8s\.io\/.*`
56-
Key string `json:"key,omitempty"`
57-
58-
// value is the taint value corresponding to the taint key.
59-
//
60-
// +optional
61-
// +kubebuilder:validation:MaxLength=63
62-
Value *string `json:"value,omitempty"`
63-
64-
// effect is the effect of the taint on pods
65-
// that do not tolerate the taint.
66-
// Valid effects are NoSchedule, PreferNoSchedule and NoExecute.
67-
//
68-
// +required
69-
// +kubebuilder:validation:Enum=NoSchedule;PreferNoSchedule;NoExecute
70-
Effect corev1.TaintEffect `json:"effect,omitempty"`
71-
72-
// timeAdded represents the time at which the taint was added.
73-
// It is only written for NoExecute taints.
74-
//
75-
// +optional
76-
TimeAdded *metav1.Time `json:"timeAdded,omitempty"`
77-
}
78-
7948
// NodeReadinessRuleSpec defines the desired state of NodeReadinessRule.
8049
type NodeReadinessRuleSpec struct {
8150
// conditions contains a list of the Node conditions that defines the specific
@@ -101,7 +70,11 @@ type NodeReadinessRuleSpec struct {
10170
// on Nodes that meet the defined condition criteria.
10271
//
10372
// +required
104-
Taint TaintSpec `json:"taint,omitempty,omitzero"`
73+
// +kubebuilder:validation:XValidation:rule="self.key.startsWith('readiness.k8s.io/')",message="taint key must start with 'readiness.k8s.io/'"
74+
// +kubebuilder:validation:XValidation:rule="self.key.size() >= 17 && self.key.size() <= 253",message="taint key length must be between 17 and 253 characters"
75+
// +kubebuilder:validation:XValidation:rule="!has(self.value) || self.value.size() <= 63",message="taint value length must be at most 63 characters"
76+
// +kubebuilder:validation:XValidation:rule="self.effect in ['NoSchedule', 'PreferNoSchedule', 'NoExecute']",message="taint effect must be one of 'NoSchedule', 'PreferNoSchedule', 'NoExecute'"
77+
Taint corev1.Taint `json:"taint,omitempty,omitzero"`
10578

10679
// nodeSelector limits the scope of this rule to a specific subset of Nodes.
10780
//

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 0 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/readiness.node.x-k8s.io_nodereadinessrules.yaml

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -160,35 +160,35 @@ spec:
160160
properties:
161161
effect:
162162
description: |-
163-
effect is the effect of the taint on pods
163+
Required. The effect of the taint on pods
164164
that do not tolerate the taint.
165165
Valid effects are NoSchedule, PreferNoSchedule and NoExecute.
166-
enum:
167-
- NoSchedule
168-
- PreferNoSchedule
169-
- NoExecute
170166
type: string
171167
key:
172-
description: key is the taint key to be applied to a node.
173-
maxLength: 253
174-
minLength: 17
175-
pattern: ^readiness\.k8s\.io\/.*
168+
description: Required. The taint key to be applied to a node.
176169
type: string
177170
timeAdded:
178-
description: |-
179-
timeAdded represents the time at which the taint was added.
180-
It is only written for NoExecute taints.
171+
description: TimeAdded represents the time at which the taint
172+
was added.
181173
format: date-time
182174
type: string
183175
value:
184-
description: value is the taint value corresponding to the taint
185-
key.
186-
maxLength: 63
176+
description: The taint value corresponding to the taint key.
187177
type: string
188178
required:
189179
- effect
190180
- key
191181
type: object
182+
x-kubernetes-validations:
183+
- message: taint key must start with 'readiness.k8s.io/'
184+
rule: self.key.startsWith('readiness.k8s.io/')
185+
- message: taint key length must be between 17 and 253 characters
186+
rule: self.key.size() >= 17 && self.key.size() <= 253
187+
- message: taint value length must be at most 63 characters
188+
rule: '!has(self.value) || self.value.size() <= 63'
189+
- message: taint effect must be one of 'NoSchedule', 'PreferNoSchedule',
190+
'NoExecute'
191+
rule: self.effect in ['NoSchedule', 'PreferNoSchedule', 'NoExecute']
192192
required:
193193
- conditions
194194
- enforcementMode

internal/controller/node_controller.go

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ func (r *RuleReadinessController) getConditionStatus(node *corev1.Node, conditio
229229
}
230230

231231
// hasTaintBySpec checks if a node has a specific taint.
232-
func (r *RuleReadinessController) hasTaintBySpec(node *corev1.Node, taintSpec readinessv1alpha1.TaintSpec) bool {
232+
func (r *RuleReadinessController) hasTaintBySpec(node *corev1.Node, taintSpec corev1.Taint) bool {
233233
for _, taint := range node.Spec.Taints {
234234
if taint.Key == taintSpec.Key && taint.Effect == taintSpec.Effect {
235235
return true
@@ -239,23 +239,14 @@ func (r *RuleReadinessController) hasTaintBySpec(node *corev1.Node, taintSpec re
239239
}
240240

241241
// addTaintBySpec adds a taint to a node.
242-
func (r *RuleReadinessController) addTaintBySpec(ctx context.Context, node *corev1.Node, taintSpec readinessv1alpha1.TaintSpec) error {
242+
func (r *RuleReadinessController) addTaintBySpec(ctx context.Context, node *corev1.Node, taintSpec corev1.Taint) error {
243243
patch := client.StrategicMergeFrom(node.DeepCopy())
244-
var value string
245-
if taintSpec.Value != nil {
246-
value = *taintSpec.Value
247-
}
248-
node.Spec.Taints = append(node.Spec.Taints, corev1.Taint{
249-
Key: taintSpec.Key,
250-
Value: value,
251-
Effect: taintSpec.Effect,
252-
TimeAdded: taintSpec.TimeAdded,
253-
})
244+
node.Spec.Taints = append(node.Spec.Taints, taintSpec)
254245
return r.Patch(ctx, node, patch)
255246
}
256247

257248
// removeTaintBySpec removes a taint from a node.
258-
func (r *RuleReadinessController) removeTaintBySpec(ctx context.Context, node *corev1.Node, taintSpec readinessv1alpha1.TaintSpec) error {
249+
func (r *RuleReadinessController) removeTaintBySpec(ctx context.Context, node *corev1.Node, taintSpec corev1.Taint) error {
259250
patch := client.StrategicMergeFrom(node.DeepCopy())
260251
var newTaints []corev1.Taint
261252
for _, taint := range node.Spec.Taints {

internal/controller/node_controller_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ var _ = Describe("Node Controller", func() {
153153
Conditions: []nodereadinessiov1alpha1.ConditionRequirement{
154154
{Type: conditionType, RequiredStatus: corev1.ConditionTrue},
155155
},
156-
Taint: nodereadinessiov1alpha1.TaintSpec{
156+
Taint: corev1.Taint{
157157
Key: taintKey,
158158
Effect: corev1.TaintEffectNoSchedule,
159159
},
@@ -398,7 +398,7 @@ var _ = Describe("Node Controller", func() {
398398
Conditions: []nodereadinessiov1alpha1.ConditionRequirement{
399399
{Type: conditionType, RequiredStatus: corev1.ConditionTrue},
400400
},
401-
Taint: nodereadinessiov1alpha1.TaintSpec{
401+
Taint: corev1.Taint{
402402
Key: taintKey,
403403
Effect: corev1.TaintEffectNoSchedule,
404404
},
@@ -566,10 +566,10 @@ var _ = Describe("Node Controller", func() {
566566
Conditions: []nodereadinessiov1alpha1.ConditionRequirement{
567567
{Type: "StatusTestCondition", RequiredStatus: corev1.ConditionTrue},
568568
},
569-
Taint: nodereadinessiov1alpha1.TaintSpec{
569+
Taint: corev1.Taint{
570570
Key: "readiness.k8s.io/status-test-taint",
571571
Effect: corev1.TaintEffectNoSchedule,
572-
Value: &val,
572+
Value: val,
573573
},
574574
NodeSelector: metav1.LabelSelector{
575575
MatchLabels: map[string]string{"test-group": "status"},

internal/controller/nodereadinessrule_controller_test.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ var _ = Describe("NodeReadinessRule Controller", func() {
8989
"node-role.kubernetes.io/worker": "",
9090
},
9191
},
92-
Taint: nodereadinessiov1alpha1.TaintSpec{
92+
Taint: corev1.Taint{
9393
Key: "readiness.k8s.io/test-taint",
9494
Effect: corev1.TaintEffectNoSchedule,
9595
},
@@ -132,7 +132,7 @@ var _ = Describe("NodeReadinessRule Controller", func() {
132132
"node-role.kubernetes.io/worker": "",
133133
},
134134
},
135-
Taint: nodereadinessiov1alpha1.TaintSpec{
135+
Taint: corev1.Taint{
136136
Key: "readiness.k8s.io/test-taint",
137137
Effect: corev1.TaintEffectNoSchedule,
138138
},
@@ -175,7 +175,7 @@ var _ = Describe("NodeReadinessRule Controller", func() {
175175
"node-role.kubernetes.io/worker": "",
176176
},
177177
},
178-
Taint: nodereadinessiov1alpha1.TaintSpec{
178+
Taint: corev1.Taint{
179179
Key: "readiness.k8s.io/test-taint",
180180
Effect: corev1.TaintEffectNoSchedule,
181181
},
@@ -236,7 +236,7 @@ var _ = Describe("NodeReadinessRule Controller", func() {
236236
Conditions: []nodereadinessiov1alpha1.ConditionRequirement{
237237
{Type: "TestCondition", RequiredStatus: corev1.ConditionTrue},
238238
},
239-
Taint: nodereadinessiov1alpha1.TaintSpec{
239+
Taint: corev1.Taint{
240240
Key: "readiness.k8s.io/immediate-test-taint",
241241
Effect: corev1.TaintEffectNoSchedule,
242242
},
@@ -298,7 +298,7 @@ var _ = Describe("NodeReadinessRule Controller", func() {
298298
"node-role.kubernetes.io/worker": "",
299299
},
300300
},
301-
Taint: nodereadinessiov1alpha1.TaintSpec{
301+
Taint: corev1.Taint{
302302
Key: "readiness.k8s.io/dry-run-taint",
303303
Effect: corev1.TaintEffectNoSchedule,
304304
},
@@ -368,7 +368,7 @@ var _ = Describe("NodeReadinessRule Controller", func() {
368368
Conditions: []nodereadinessiov1alpha1.ConditionRequirement{
369369
{Type: "Ready", RequiredStatus: corev1.ConditionTrue},
370370
},
371-
Taint: nodereadinessiov1alpha1.TaintSpec{
371+
Taint: corev1.Taint{
372372
Key: "readiness.k8s.io/node-test-taint",
373373
Effect: corev1.TaintEffectNoSchedule,
374374
},
@@ -429,7 +429,7 @@ var _ = Describe("NodeReadinessRule Controller", func() {
429429
},
430430
}
431431

432-
taintSpec := nodereadinessiov1alpha1.TaintSpec{
432+
taintSpec := corev1.Taint{
433433
Key: "readiness.k8s.io/test-key",
434434
Effect: corev1.TaintEffectNoSchedule,
435435
}
@@ -438,7 +438,7 @@ var _ = Describe("NodeReadinessRule Controller", func() {
438438
Expect(hasTaint).To(BeTrue())
439439

440440
// Test non-existent taint
441-
nonExistentTaint := nodereadinessiov1alpha1.TaintSpec{
441+
nonExistentTaint := corev1.Taint{
442442
Key: "readiness.k8s.io/missing-key",
443443
Effect: corev1.TaintEffectNoSchedule,
444444
}
@@ -534,7 +534,7 @@ var _ = Describe("NodeReadinessRule Controller", func() {
534534
},
535535
Spec: nodereadinessiov1alpha1.NodeReadinessRuleSpec{
536536
Conditions: []nodereadinessiov1alpha1.ConditionRequirement{{Type: "DBReady", RequiredStatus: corev1.ConditionTrue}},
537-
Taint: nodereadinessiov1alpha1.TaintSpec{Key: "readiness.k8s.io/db-unready", Effect: corev1.TaintEffectNoSchedule},
537+
Taint: corev1.Taint{Key: "readiness.k8s.io/db-unready", Effect: corev1.TaintEffectNoSchedule},
538538
EnforcementMode: nodereadinessiov1alpha1.EnforcementModeContinuous,
539539
NodeSelector: metav1.LabelSelector{MatchLabels: map[string]string{"app": "backend"}},
540540
},
@@ -590,7 +590,7 @@ var _ = Describe("NodeReadinessRule Controller", func() {
590590
},
591591
Spec: nodereadinessiov1alpha1.NodeReadinessRuleSpec{
592592
Conditions: []nodereadinessiov1alpha1.ConditionRequirement{{Type: "TestReady", RequiredStatus: corev1.ConditionTrue}},
593-
Taint: nodereadinessiov1alpha1.TaintSpec{Key: "readiness.k8s.io/test-unready", Effect: corev1.TaintEffectNoSchedule},
593+
Taint: corev1.Taint{Key: "readiness.k8s.io/test-unready", Effect: corev1.TaintEffectNoSchedule},
594594
EnforcementMode: nodereadinessiov1alpha1.EnforcementModeContinuous,
595595
NodeSelector: metav1.LabelSelector{MatchLabels: map[string]string{"node-group": "new-workers"}},
596596
},
@@ -679,7 +679,7 @@ var _ = Describe("NodeReadinessRule Controller", func() {
679679
Spec: nodereadinessiov1alpha1.NodeReadinessRuleSpec{
680680
Conditions: []nodereadinessiov1alpha1.ConditionRequirement{{Type: "TestReady", RequiredStatus: corev1.ConditionTrue}},
681681
NodeSelector: metav1.LabelSelector{MatchLabels: map[string]string{"kubernetes.io/hostname": "cleanup-test-node"}},
682-
Taint: nodereadinessiov1alpha1.TaintSpec{Key: "readiness.k8s.io/cleanup-taint", Effect: corev1.TaintEffectNoSchedule},
682+
Taint: corev1.Taint{Key: "readiness.k8s.io/cleanup-taint", Effect: corev1.TaintEffectNoSchedule},
683683
EnforcementMode: nodereadinessiov1alpha1.EnforcementModeContinuous,
684684
},
685685
}
@@ -767,7 +767,7 @@ var _ = Describe("NodeReadinessRule Controller", func() {
767767
},
768768
},
769769
},
770-
Taint: nodereadinessiov1alpha1.TaintSpec{Key: "readiness.k8s.io/unready", Effect: corev1.TaintEffectNoSchedule},
770+
Taint: corev1.Taint{Key: "readiness.k8s.io/unready", Effect: corev1.TaintEffectNoSchedule},
771771
EnforcementMode: nodereadinessiov1alpha1.EnforcementModeContinuous,
772772
},
773773
}
@@ -868,7 +868,7 @@ var _ = Describe("NodeReadinessRule Controller", func() {
868868
Conditions: []nodereadinessiov1alpha1.ConditionRequirement{
869869
{Type: "TestReady", RequiredStatus: corev1.ConditionTrue},
870870
},
871-
Taint: nodereadinessiov1alpha1.TaintSpec{Key: selectorChangeTaintKey, Effect: corev1.TaintEffectNoSchedule},
871+
Taint: corev1.Taint{Key: selectorChangeTaintKey, Effect: corev1.TaintEffectNoSchedule},
872872
EnforcementMode: nodereadinessiov1alpha1.EnforcementModeContinuous,
873873
NodeSelector: metav1.LabelSelector{
874874
MatchLabels: map[string]string{"env": "prod"},

internal/webhook/nodereadinessgaterule_webhook.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ package webhook
1919
import (
2020
"context"
2121
"fmt"
22+
"strings"
2223

24+
corev1 "k8s.io/api/core/v1"
2325
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2426
"k8s.io/apimachinery/pkg/runtime"
2527
"k8s.io/apimachinery/pkg/util/validation/field"
@@ -93,9 +95,36 @@ func (w *NodeReadinessRuleWebhook) validateSpec(spec readinessv1alpha1.NodeReadi
9395
taintField := specField.Child("taint")
9496
if spec.Taint.Key == "" {
9597
allErrs = append(allErrs, field.Required(taintField.Child("key"), "taint key cannot be empty"))
98+
} else {
99+
// Validate key prefix
100+
if !strings.HasPrefix(spec.Taint.Key, "readiness.k8s.io/") {
101+
allErrs = append(allErrs, field.Invalid(taintField.Child("key"), spec.Taint.Key, "taint key must start with 'readiness.k8s.io/'"))
102+
}
103+
// Validate key length
104+
if len(spec.Taint.Key) < 17 || len(spec.Taint.Key) > 253 {
105+
allErrs = append(allErrs, field.Invalid(taintField.Child("key"), spec.Taint.Key, "taint key length must be between 17 and 253 characters"))
106+
}
96107
}
108+
97109
if spec.Taint.Effect == "" {
98110
allErrs = append(allErrs, field.Required(taintField.Child("effect"), "taint effect cannot be empty"))
111+
} else {
112+
// Validate effect
113+
switch spec.Taint.Effect {
114+
case corev1.TaintEffectNoSchedule, corev1.TaintEffectPreferNoSchedule, corev1.TaintEffectNoExecute:
115+
// valid
116+
default:
117+
allErrs = append(allErrs, field.NotSupported(taintField.Child("effect"), spec.Taint.Effect, []string{
118+
string(corev1.TaintEffectNoSchedule),
119+
string(corev1.TaintEffectPreferNoSchedule),
120+
string(corev1.TaintEffectNoExecute),
121+
}))
122+
}
123+
}
124+
125+
// Validate value length
126+
if len(spec.Taint.Value) > 63 {
127+
allErrs = append(allErrs, field.Invalid(taintField.Child("value"), spec.Taint.Value, "taint value length must be at most 63 characters"))
99128
}
100129

101130
// Validate enforcement mode

0 commit comments

Comments
 (0)