Skip to content

Commit

Permalink
CEL Validation
Browse files Browse the repository at this point in the history
  • Loading branch information
engedaam committed Oct 23, 2023
1 parent c716531 commit d364f5a
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 2 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ verify: tidy download ## Verify code. Includes dependencies, linting, formatting
go generate ./...
hack/boilerplate.sh
cp $(KARPENTER_CORE_DIR)/pkg/apis/crds/* pkg/apis/crds
hack/validation/requirements.sh
$(foreach dir,$(MOD_DIRS),cd $(dir) && golangci-lint run $(newline))
@git diff --quiet ||\
{ echo "New file modification detected in the Git working tree. Please check in before commit."; git --no-pager diff --name-only | uniq | awk '{print " - " $$0}'; \
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ module github.com/aws/karpenter

go 1.21

replace github.com/aws/karpenter-core => github.com/engedaam/karpenter-core v0.0.0-20231023201107-aec165a74327

require (
github.com/Pallinder/go-randomdata v1.2.0
github.com/PuerkitoBio/goquery v1.8.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHS
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
github.com/aws/aws-sdk-go v1.46.1 h1:U26quvBWFZMQuultLw5tloW4GnmWaChEwMZNq8uYatw=
github.com/aws/aws-sdk-go v1.46.1/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/karpenter-core v0.31.1-0.20231020234031-e0623869f604 h1:eQFElFqH3K64na70WZBh6FUFonVRKhtyUptWtpO/JdI=
github.com/aws/karpenter-core v0.31.1-0.20231020234031-e0623869f604/go.mod h1:rb3kp/3cj38tACF6udfpmIvKoQMwirSVoHNlrd66LyE=
github.com/aws/karpenter/tools/kompat v0.0.0-20231010173459-62c25a3ea85c h1:oXWwIttmjYLbBKhLazG21aQvpJ3NOOr8IXhCJ/p6e/M=
github.com/aws/karpenter/tools/kompat v0.0.0-20231010173459-62c25a3ea85c/go.mod h1:l/TIBsaCx/IrOr0Xvlj/cHLOf05QzuQKEZ1hx2XWmfU=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
Expand Down Expand Up @@ -91,6 +89,8 @@ github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsP
github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/engedaam/karpenter-core v0.0.0-20231023201107-aec165a74327 h1:DQ6Pr3J5xvFdqhn47+EMV/Lf2VzuDfOXs4Lk4B8RNTo=
github.com/engedaam/karpenter-core v0.0.0-20231023201107-aec165a74327/go.mod h1:rb3kp/3cj38tACF6udfpmIvKoQMwirSVoHNlrd66LyE=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
Expand Down
12 changes: 12 additions & 0 deletions hack/validation/requirements.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Requirements Validation

# Adding validation for nodeclaim

## checking for restricted labels while filtering out well known labels
yq eval '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.requirements.items.properties.key.x-kubernetes-validations += [
{"message": "label domain \"karpenter.k8s.aws\" is restricted", "rule": "self.find(\"^([^/]+)\").endsWith(\"karpenter.k8s.aws\") ? self in [\"karpenter.k8s.aws/instance-encryption-in-transit-supported\", \"karpenter.k8s.aws/instance-category\", \"karpenter.k8s.aws/instance-hypervisor\", \"karpenter.k8s.aws/instance-family\", \"karpenter.k8s.aws/instance-generation\", \"karpenter.k8s.aws/instance-local-nvme\", \"karpenter.k8s.aws/instance-size\", \"karpenter.k8s.aws/instance-cpu\",\"karpenter.k8s.aws/instance-memory\", \"karpenter.k8s.aws/instance-network-bandwidth\", \"karpenter.k8s.aws/instance-pods\", \"karpenter.k8s.aws/instance-gpu-name\", \"karpenter.k8s.aws/instance-gpu-manufacturer\", \"karpenter.k8s.aws/instance-gpu-count\", \"karpenter.k8s.aws/instance-gpu-memory\", \"karpenter.k8s.aws/instance-accelerator-name\", \"karpenter.k8s.aws/instance-accelerator-manufacturer\", \"karpenter.k8s.aws/instance-accelerator-count\"] : true"}]' -i pkg/apis/crds/karpenter.sh_nodeclaims.yaml
# # Adding validation for nodepool

# ## checking for restricted labels while filtering out well known labels
yq eval '.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.requirements.items.properties.key.x-kubernetes-validations += [
{"message": "label domain \"karpenter.k8s.aws\" is restricted", "rule": "self.find(\"^([^/]+)\").endsWith(\"karpenter.k8s.aws\") ? self in [\"karpenter.k8s.aws/instance-encryption-in-transit-supported\", \"karpenter.k8s.aws/instance-category\", \"karpenter.k8s.aws/instance-hypervisor\", \"karpenter.k8s.aws/instance-family\", \"karpenter.k8s.aws/instance-generation\", \"karpenter.k8s.aws/instance-local-nvme\", \"karpenter.k8s.aws/instance-size\", \"karpenter.k8s.aws/instance-cpu\",\"karpenter.k8s.aws/instance-memory\", \"karpenter.k8s.aws/instance-network-bandwidth\", \"karpenter.k8s.aws/instance-pods\", \"karpenter.k8s.aws/instance-gpu-name\", \"karpenter.k8s.aws/instance-gpu-manufacturer\", \"karpenter.k8s.aws/instance-gpu-count\", \"karpenter.k8s.aws/instance-gpu-memory\", \"karpenter.k8s.aws/instance-accelerator-name\", \"karpenter.k8s.aws/instance-accelerator-manufacturer\", \"karpenter.k8s.aws/instance-accelerator-count\"] : true"}]' -i pkg/apis/crds/karpenter.sh_nodepools.yaml
30 changes: 30 additions & 0 deletions pkg/apis/crds/karpenter.sh_nodeclaims.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -182,19 +182,49 @@ spec:
key:
description: The label key that the selector applies to.
type: string
maxLength: 316
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]$
x-kubernetes-validations:
- message: label domain "kubernetes.io" is restricted
rule: ' self == "beta.kubernetes.io/instance-type" || self == "failure-domain.beta.kubernetes.io/region"|| self == "beta.kubernetes.io/os" || self == "beta.kubernetes.io/arch" || self == "failure-domain.beta.kubernetes.io/zone" || self.startsWith("node.kubernetes.io/") || self.startsWith("node-restriction.kubernetes.io/") || (self.find("^([^/]+)").endsWith("kubernetes.io") ? self in ["topology.kubernetes.io/zone", "topology.kubernetes.io/region", "node.kubernetes.io/instance-type", "kubernetes.io/arch", "kubernetes.io/os", "node.kubernetes.io/windows-build"] : true)'
- message: label domain "k8s.io" is restricted
rule: self.startsWith("kops.k8s.io/") || !self.find("^([^/]+)").endsWith("k8s.io")
- message: label domain "karpenter.sh" is restricted
rule: 'self.find("^([^/]+)").endsWith("karpenter.sh") ? self in ["karpenter.sh/nodepool", "karpenter.sh/capacity-type"] : true'
- message: label "kubernetes.io/hostname" is restricted
rule: self != "kubernetes.io/hostname"
- message: label domain "karpenter.k8s.aws" is restricted
rule: 'self.find("^([^/]+)").endsWith("karpenter.k8s.aws") ? self in ["karpenter.k8s.aws/instance-encryption-in-transit-supported", "karpenter.k8s.aws/instance-category", "karpenter.k8s.aws/instance-hypervisor", "karpenter.k8s.aws/instance-family", "karpenter.k8s.aws/instance-generation", "karpenter.k8s.aws/instance-local-nvme", "karpenter.k8s.aws/instance-size", "karpenter.k8s.aws/instance-cpu","karpenter.k8s.aws/instance-memory", "karpenter.k8s.aws/instance-network-bandwidth", "karpenter.k8s.aws/instance-pods", "karpenter.k8s.aws/instance-gpu-name", "karpenter.k8s.aws/instance-gpu-manufacturer", "karpenter.k8s.aws/instance-gpu-count", "karpenter.k8s.aws/instance-gpu-memory", "karpenter.k8s.aws/instance-accelerator-name", "karpenter.k8s.aws/instance-accelerator-manufacturer", "karpenter.k8s.aws/instance-accelerator-count"] : true'
operator:
description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
type: string
enum:
- In
- NotIn
- Exists
- DoesNotExist
- Gt
- Lt
values:
description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch.
items:
type: string
type: array
maxLength: 63
pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$
required:
- key
- operator
type: object
maxItems: 20
type: array
x-kubernetes-validations:
- message: requirements with operator 'In' must have a value defined
rule: 'self.all(x, x.operator == ''In'' ? x.values.size() != 0 : true)'
- message: requirements operator 'Gt' or 'Lt' must have a single value
rule: 'self.all(x, (x.operator == ''Gt'' || x.operator == ''Lt'') ? x.values.size() == 1 : true)'
- message: requirements operator 'Gt' or 'Lt' must have a single positive integer value
rule: 'self.all(x, (x.operator == ''Gt'' || x.operator == ''Lt'') ? int(x.values[0]) >= 0 : true)'
resources:
description: Resources models the resource requirements for the NodeClaim to launch
properties:
Expand Down
32 changes: 32 additions & 0 deletions pkg/apis/crds/karpenter.sh_nodepools.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -218,19 +218,51 @@ spec:
key:
description: The label key that the selector applies to.
type: string
maxLength: 316
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]$
x-kubernetes-validations:
- message: label domain "kubernetes.io" is restricted
rule: 'self == "beta.kubernetes.io/instance-type" || self == "failure-domain.beta.kubernetes.io/region"|| self == "beta.kubernetes.io/os" || self == "beta.kubernetes.io/arch" || self == "failure-domain.beta.kubernetes.io/zone" || self.startsWith("node.kubernetes.io/") || self.startsWith("node-restriction.kubernetes.io/") || (self.find("^([^/]+)").endsWith("kubernetes.io") ? self in ["topology.kubernetes.io/zone", "topology.kubernetes.io/region", "node.kubernetes.io/instance-type", "kubernetes.io/arch", "kubernetes.io/os", "node.kubernetes.io/windows-build"] : true)'
- message: label domain "k8s.io" is restricted
rule: self.startsWith("kops.k8s.io/") || !self.find("^([^/]+)").endsWith("k8s.io")
- message: label domain "karpenter.sh" is restricted
rule: 'self.find("^([^/]+)").endsWith("karpenter.sh") ? self in ["karpenter.sh/nodepool", "karpenter.sh/capacity-type"] : true'
- message: label "karpenter.sh/nodepool" is restricted
rule: self != "karpenter.sh/nodepool"
- message: label "kubernetes.io/hostname" is restricted
rule: self != "kubernetes.io/hostname"
- message: label domain "karpenter.k8s.aws" is restricted
rule: 'self.find("^([^/]+)").endsWith("karpenter.k8s.aws") ? self in ["karpenter.k8s.aws/instance-encryption-in-transit-supported", "karpenter.k8s.aws/instance-category", "karpenter.k8s.aws/instance-hypervisor", "karpenter.k8s.aws/instance-family", "karpenter.k8s.aws/instance-generation", "karpenter.k8s.aws/instance-local-nvme", "karpenter.k8s.aws/instance-size", "karpenter.k8s.aws/instance-cpu","karpenter.k8s.aws/instance-memory", "karpenter.k8s.aws/instance-network-bandwidth", "karpenter.k8s.aws/instance-pods", "karpenter.k8s.aws/instance-gpu-name", "karpenter.k8s.aws/instance-gpu-manufacturer", "karpenter.k8s.aws/instance-gpu-count", "karpenter.k8s.aws/instance-gpu-memory", "karpenter.k8s.aws/instance-accelerator-name", "karpenter.k8s.aws/instance-accelerator-manufacturer", "karpenter.k8s.aws/instance-accelerator-count"] : true'
operator:
description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
type: string
enum:
- In
- NotIn
- Exists
- DoesNotExist
- Gt
- Lt
values:
description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch.
items:
type: string
type: array
maxLength: 63
pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$
required:
- key
- operator
type: object
maxItems: 20
type: array
x-kubernetes-validations:
- message: requirements with operator 'In' must have a value defined
rule: 'self.all(x, x.operator == ''In'' ? x.values.size() != 0 : true)'
- message: requirements operator 'Gt' or 'Lt' must have a single value
rule: 'self.all(x, (x.operator == ''Gt'' || x.operator == ''Lt'') ? x.values.size() == 1 : true)'
- message: requirements operator 'Gt' or 'Lt' must have a single positive integer value
rule: 'self.all(x, (x.operator == ''Gt'' || x.operator == ''Lt'') ? int(x.values[0]) >= 0 : true)'
resources:
description: Resources models the resource requirements for the NodeClaim to launch
properties:
Expand Down

0 comments on commit d364f5a

Please sign in to comment.