Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ verify: tidy download ## Verify code. Includes dependencies, linting, formatting
hack/validation/kubelet.sh
hack/validation/labels.sh
hack/validation/requirements.sh
hack/validation/taints.sh
hack/mutation/kubectl_get_ux.sh
cp pkg/apis/crds/* charts/karpenter-crd/templates
hack/github/dependabot.sh
Expand Down
16 changes: 16 additions & 0 deletions charts/karpenter-crd/templates/karpenter.sh_nodeclaims.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ spec:
type: string
minLength: 1
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*(\/))?([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$
maxLength: 316
x-kubernetes-validations:
- message: taint domain "kubernetes.azure.com" is restricted
rule: '!self.startsWith("kubernetes.azure.com/") || self == "kubernetes.azure.com/scalesetpriority"'
Comment thread
matthchr marked this conversation as resolved.
timeAdded:
description: TimeAdded represents the time at which the taint was added.
format: date-time
Expand All @@ -226,7 +230,11 @@ spec:
- effect
- key
type: object
x-kubernetes-validations:
- message: taint "kubernetes.azure.com/scalesetpriority" must have value "spot"
rule: self.key != "kubernetes.azure.com/scalesetpriority" || self.value == "spot"
type: array
maxItems: 100
taints:
description: Taints will be applied to the NodeClaim's node.
items:
Expand All @@ -249,6 +257,10 @@ spec:
type: string
minLength: 1
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*(\/))?([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$
maxLength: 316
x-kubernetes-validations:
- message: taint domain "kubernetes.azure.com" is restricted
rule: '!self.startsWith("kubernetes.azure.com/") || self == "kubernetes.azure.com/scalesetpriority"'
timeAdded:
description: TimeAdded represents the time at which the taint was added.
format: date-time
Expand All @@ -261,7 +273,11 @@ spec:
- effect
- key
type: object
x-kubernetes-validations:
- message: taint "kubernetes.azure.com/scalesetpriority" must have value "spot"
rule: self.key != "kubernetes.azure.com/scalesetpriority" || self.value == "spot"
type: array
maxItems: 100
terminationGracePeriod:
description: |-
TerminationGracePeriod is the maximum duration the controller will wait before forcefully deleting the pods on a node, measured from when deletion is first initiated.
Expand Down
16 changes: 16 additions & 0 deletions charts/karpenter-crd/templates/karpenter.sh_nodepools.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,10 @@ spec:
type: string
minLength: 1
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*(\/))?([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$
maxLength: 316
x-kubernetes-validations:
- message: taint domain "kubernetes.azure.com" is restricted
rule: '!self.startsWith("kubernetes.azure.com/") || self == "kubernetes.azure.com/scalesetpriority"'
timeAdded:
description: TimeAdded represents the time at which the taint was added.
format: date-time
Expand All @@ -378,7 +382,11 @@ spec:
- effect
- key
type: object
x-kubernetes-validations:
- message: taint "kubernetes.azure.com/scalesetpriority" must have value "spot"
rule: self.key != "kubernetes.azure.com/scalesetpriority" || self.value == "spot"
type: array
maxItems: 100
taints:
description: Taints will be applied to the NodeClaim's node.
items:
Expand All @@ -401,6 +409,10 @@ spec:
type: string
minLength: 1
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*(\/))?([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$
maxLength: 316
x-kubernetes-validations:
- message: taint domain "kubernetes.azure.com" is restricted
rule: '!self.startsWith("kubernetes.azure.com/") || self == "kubernetes.azure.com/scalesetpriority"'
timeAdded:
description: TimeAdded represents the time at which the taint was added.
format: date-time
Expand All @@ -413,7 +425,11 @@ spec:
- effect
- key
type: object
x-kubernetes-validations:
- message: taint "kubernetes.azure.com/scalesetpriority" must have value "spot"
rule: self.key != "kubernetes.azure.com/scalesetpriority" || self.value == "spot"
type: array
maxItems: 100
terminationGracePeriod:
description: |-
TerminationGracePeriod is the maximum duration the controller will wait before forcefully deleting the pods on a node, measured from when deletion is first initiated.
Expand Down
73 changes: 73 additions & 0 deletions hack/validation/taints.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/bin/bash
set -euo pipefail

# taints validation for nodeclaim and nodepool
# checking for restricted taint keys while filtering out well known taints

rule=$'!self.startsWith("kubernetes.azure.com/") || self == "kubernetes.azure.com/scalesetpriority"
'
# above regex: everything before the first '/' (any characters except '/' at the beginning of the string)

rule=${rule//\"/\\\"} # escape double quotes
rule=${rule//$'\n'/} # remove newlines
rule=$(echo "$rule" | tr -s ' ') # remove extra spaces

# check that .spec.versions has 1 entry
[[ $(yq e '.spec.versions | length' pkg/apis/crds/karpenter.sh_nodepools.yaml) -eq 1 ]] || { echo "expected one version"; exit 1; }
[[ $(yq e '.spec.versions | length' pkg/apis/crds/karpenter.sh_nodeclaims.yaml) -eq 1 ]] || { echo "expected one version"; exit 1; }

# Add maxLength to taint key fields (required for CEL cost estimation with string operations)
# Using 316 to match the maxLength used for requirement keys (253 prefix + '/' + 63 name)
yq eval '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.startupTaints.items.properties.key.maxLength = 316' -i pkg/apis/crds/karpenter.sh_nodeclaims.yaml
yq eval '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.taints.items.properties.key.maxLength = 316' -i pkg/apis/crds/karpenter.sh_nodeclaims.yaml
yq eval '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.startupTaints.items.properties.key.maxLength = 316' -i pkg/apis/crds/karpenter.sh_nodepools.yaml
yq eval '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.taints.items.properties.key.maxLength = 316' -i pkg/apis/crds/karpenter.sh_nodepools.yaml

# Add maxItems to taint arrays (required for CEL cost estimation to bound per-item rule cost)
yq eval '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.startupTaints.maxItems = 100' -i pkg/apis/crds/karpenter.sh_nodeclaims.yaml
yq eval '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.taints.maxItems = 100' -i pkg/apis/crds/karpenter.sh_nodeclaims.yaml
yq eval '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.startupTaints.maxItems = 100' -i pkg/apis/crds/karpenter.sh_nodepools.yaml
yq eval '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.taints.maxItems = 100' -i pkg/apis/crds/karpenter.sh_nodepools.yaml

# nodeclaim - startupTaints
printf -v expr '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.startupTaints.items.properties.key.x-kubernetes-validations +=
[{"message": "taint domain \\"kubernetes.azure.com\\" is restricted", "rule": "%s"}]' "$rule"
yq eval "${expr}" -i pkg/apis/crds/karpenter.sh_nodeclaims.yaml

# nodeclaim - taints
printf -v expr '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.taints.items.properties.key.x-kubernetes-validations +=
[{"message": "taint domain \\"kubernetes.azure.com\\" is restricted", "rule": "%s"}]' "$rule"
yq eval "${expr}" -i pkg/apis/crds/karpenter.sh_nodeclaims.yaml

# nodepool - startupTaints
printf -v expr '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.startupTaints.items.properties.key.x-kubernetes-validations +=
[{"message": "taint domain \\"kubernetes.azure.com\\" is restricted", "rule": "%s"}]' "$rule"
yq eval "${expr}" -i pkg/apis/crds/karpenter.sh_nodepools.yaml

# nodepool - taints
printf -v expr '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.taints.items.properties.key.x-kubernetes-validations +=
[{"message": "taint domain \\"kubernetes.azure.com\\" is restricted", "rule": "%s"}]' "$rule"
yq eval "${expr}" -i pkg/apis/crds/karpenter.sh_nodepools.yaml

# Value validation: kubernetes.azure.com/scalesetpriority taint must have value "spot"
value_rule='self.key != \"kubernetes.azure.com/scalesetpriority\" || self.value == \"spot\"'

# nodeclaim - startupTaints (item-level)
printf -v expr '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.startupTaints.items.x-kubernetes-validations +=
[{"message": "taint \\"kubernetes.azure.com/scalesetpriority\\" must have value \\"spot\\"", "rule": "%s"}]' "$value_rule"
yq eval "${expr}" -i pkg/apis/crds/karpenter.sh_nodeclaims.yaml

# nodeclaim - taints (item-level)
printf -v expr '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.taints.items.x-kubernetes-validations +=
[{"message": "taint \\"kubernetes.azure.com/scalesetpriority\\" must have value \\"spot\\"", "rule": "%s"}]' "$value_rule"
yq eval "${expr}" -i pkg/apis/crds/karpenter.sh_nodeclaims.yaml

# nodepool - startupTaints (item-level)
printf -v expr '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.startupTaints.items.x-kubernetes-validations +=
[{"message": "taint \\"kubernetes.azure.com/scalesetpriority\\" must have value \\"spot\\"", "rule": "%s"}]' "$value_rule"
yq eval "${expr}" -i pkg/apis/crds/karpenter.sh_nodepools.yaml

# nodepool - taints (item-level)
printf -v expr '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.taints.items.x-kubernetes-validations +=
[{"message": "taint \\"kubernetes.azure.com/scalesetpriority\\" must have value \\"spot\\"", "rule": "%s"}]' "$value_rule"
yq eval "${expr}" -i pkg/apis/crds/karpenter.sh_nodepools.yaml
16 changes: 16 additions & 0 deletions pkg/apis/crds/karpenter.sh_nodeclaims.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ spec:
type: string
minLength: 1
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*(\/))?([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$
maxLength: 316
x-kubernetes-validations:
- message: taint domain "kubernetes.azure.com" is restricted
rule: '!self.startsWith("kubernetes.azure.com/") || self == "kubernetes.azure.com/scalesetpriority"'
timeAdded:
description: TimeAdded represents the time at which the taint was added.
format: date-time
Expand All @@ -226,7 +230,11 @@ spec:
- effect
- key
type: object
x-kubernetes-validations:
- message: taint "kubernetes.azure.com/scalesetpriority" must have value "spot"
rule: self.key != "kubernetes.azure.com/scalesetpriority" || self.value == "spot"
type: array
maxItems: 100
taints:
description: Taints will be applied to the NodeClaim's node.
items:
Expand All @@ -249,6 +257,10 @@ spec:
type: string
minLength: 1
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*(\/))?([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$
maxLength: 316
x-kubernetes-validations:
- message: taint domain "kubernetes.azure.com" is restricted
rule: '!self.startsWith("kubernetes.azure.com/") || self == "kubernetes.azure.com/scalesetpriority"'
timeAdded:
description: TimeAdded represents the time at which the taint was added.
format: date-time
Expand All @@ -261,7 +273,11 @@ spec:
- effect
- key
type: object
x-kubernetes-validations:
- message: taint "kubernetes.azure.com/scalesetpriority" must have value "spot"
rule: self.key != "kubernetes.azure.com/scalesetpriority" || self.value == "spot"
type: array
maxItems: 100
terminationGracePeriod:
description: |-
TerminationGracePeriod is the maximum duration the controller will wait before forcefully deleting the pods on a node, measured from when deletion is first initiated.
Expand Down
16 changes: 16 additions & 0 deletions pkg/apis/crds/karpenter.sh_nodepools.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,10 @@ spec:
type: string
minLength: 1
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*(\/))?([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$
maxLength: 316
x-kubernetes-validations:
- message: taint domain "kubernetes.azure.com" is restricted
rule: '!self.startsWith("kubernetes.azure.com/") || self == "kubernetes.azure.com/scalesetpriority"'
timeAdded:
description: TimeAdded represents the time at which the taint was added.
format: date-time
Expand All @@ -378,7 +382,11 @@ spec:
- effect
- key
type: object
x-kubernetes-validations:
- message: taint "kubernetes.azure.com/scalesetpriority" must have value "spot"
rule: self.key != "kubernetes.azure.com/scalesetpriority" || self.value == "spot"
type: array
maxItems: 100
taints:
description: Taints will be applied to the NodeClaim's node.
items:
Expand All @@ -401,6 +409,10 @@ spec:
type: string
minLength: 1
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*(\/))?([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$
maxLength: 316
x-kubernetes-validations:
- message: taint domain "kubernetes.azure.com" is restricted
rule: '!self.startsWith("kubernetes.azure.com/") || self == "kubernetes.azure.com/scalesetpriority"'
timeAdded:
description: TimeAdded represents the time at which the taint was added.
format: date-time
Expand All @@ -413,7 +425,11 @@ spec:
- effect
- key
type: object
x-kubernetes-validations:
- message: taint "kubernetes.azure.com/scalesetpriority" must have value "spot"
rule: self.key != "kubernetes.azure.com/scalesetpriority" || self.value == "spot"
type: array
maxItems: 100
terminationGracePeriod:
description: |-
TerminationGracePeriod is the maximum duration the controller will wait before forcefully deleting the pods on a node, measured from when deletion is first initiated.
Expand Down
55 changes: 55 additions & 0 deletions pkg/apis/v1alpha2/crd_validation_cel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,61 @@ var _ = Describe("CEL/Validation", func() {
})
})

Context("Taints", func() {
It("should allow the kubernetes.azure.com/scalesetpriority taint", func() {
oldNodePool := nodePool.DeepCopy()
nodePool.Spec.Template.Spec.Taints = []corev1.Taint{
{Key: v1beta1.AKSLabelScaleSetPriority, Value: "spot", Effect: corev1.TaintEffectNoSchedule},
}
Expect(env.Client.Create(ctx, nodePool)).To(Succeed())
Expect(env.Client.Delete(ctx, nodePool)).To(Succeed())
nodePool = oldNodePool.DeepCopy()
})
It("should reject kubernetes.azure.com/scalesetpriority taint with non-spot value", func() {
oldNodePool := nodePool.DeepCopy()
nodePool.Spec.Template.Spec.Taints = []corev1.Taint{
{Key: v1beta1.AKSLabelScaleSetPriority, Value: "regular", Effect: corev1.TaintEffectNoSchedule},
}
Expect(env.Client.Create(ctx, nodePool)).ToNot(Succeed())
nodePool = oldNodePool.DeepCopy()
})
It("should allow the kubernetes.azure.com/scalesetpriority startup taint", func() {
oldNodePool := nodePool.DeepCopy()
nodePool.Spec.Template.Spec.StartupTaints = []corev1.Taint{
{Key: v1beta1.AKSLabelScaleSetPriority, Value: "spot", Effect: corev1.TaintEffectNoSchedule},
}
Expect(env.Client.Create(ctx, nodePool)).To(Succeed())
Expect(env.Client.Delete(ctx, nodePool)).To(Succeed())
nodePool = oldNodePool.DeepCopy()
})
It("should allow taints with non-restricted domains", func() {
oldNodePool := nodePool.DeepCopy()
nodePool.Spec.Template.Spec.Taints = []corev1.Taint{
{Key: "example.com/my-taint", Value: "test", Effect: corev1.TaintEffectNoSchedule},
}
Expect(env.Client.Create(ctx, nodePool)).To(Succeed())
Expect(env.Client.Delete(ctx, nodePool)).To(Succeed())
nodePool = oldNodePool.DeepCopy()
})
It("should reject taints with restricted kubernetes.azure.com domain", func() {
oldNodePool := nodePool.DeepCopy()
nodePool.Spec.Template.Spec.Taints = []corev1.Taint{
{Key: "kubernetes.azure.com/some-other-taint", Value: "test", Effect: corev1.TaintEffectNoSchedule},
}
Expect(env.Client.Create(ctx, nodePool)).ToNot(Succeed())
nodePool = oldNodePool.DeepCopy()
})
It("should reject startup taints with restricted kubernetes.azure.com domain", func() {
oldNodePool := nodePool.DeepCopy()
nodePool.Spec.Template.Spec.StartupTaints = []corev1.Taint{
{Key: "kubernetes.azure.com/some-other-taint", Value: "test", Effect: corev1.TaintEffectNoSchedule},
}
Expect(env.Client.Create(ctx, nodePool)).ToNot(Succeed())
nodePool = oldNodePool.DeepCopy()
})

})

Context("Tags", func() {
It("should allow tags with valid keys and values", func() {
nodeClass := &v1alpha2.AKSNodeClass{
Expand Down
Loading