Skip to content

Commit 6348288

Browse files
authored
Merge pull request #2276 from robscott/cel-httproute
Adding channel-based CEL validation
2 parents b6f8729 + c18b942 commit 6348288

16 files changed

+410
-19
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ vet:
8282

8383
# Run go test against code
8484
test:
85-
go test -race -cover ./pkg/... ./apis/... ./conformance/utils/...
85+
go test -race -cover ./pkg/admission/... ./apis/... ./conformance/utils/...
8686

8787
# Run conformance tests against controller implementation
8888
.PHONY: conformance

apis/v1beta1/shared_types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,8 @@ type CommonRouteSpec struct {
201201
//
202202
// +optional
203203
// +kubebuilder:validation:MaxItems=32
204+
// <gateway:standard:validation:XValidation:message="sectionName must be unique when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && ((!has(p1.__namespace__) && !has(p2.__namespace__)) || (!has(p1.__namespace__) && p2.__namespace__ == '') || (p1.__namespace__ == '' && !has(p2.__namespace__)) || (p1.__namespace__ == p2.__namespace__)) && p1.name == p2.name && ((!has(p1.sectionName) && !has(p2.sectionName)) || (!has(p1.sectionName) && p2.sectionName == '') || (p1.sectionName == '' && !has(p2.sectionName)) || (p1.sectionName == p2.sectionName))))">
205+
// <gateway:experimental:validation:XValidation:message="sectionName or port must be unique when parentRefs includes 2 or more references to the same parent",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && ((!has(p1.__namespace__) && !has(p2.__namespace__)) || (!has(p1.__namespace__) && p2.__namespace__ == '') || (p1.__namespace__ == '' && !has(p2.__namespace__)) || (p1.__namespace__ == p2.__namespace__)) && p1.name == p2.name && ((!has(p1.sectionName) && !has(p2.sectionName)) || (!has(p1.sectionName) && p2.sectionName == '') || (p1.sectionName == '' && !has(p2.sectionName)) || (p1.sectionName == p2.sectionName)) && ((!has(p1.port) && !has(p2.port)) || (!has(p1.port) && p2.port == 0) || (p1.port == 0 && !has(p2.port)) || (p1.port == p2.port))))">
204206
ParentRefs []ParentReference `json:"parentRefs,omitempty"`
205207
}
206208

config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml

Lines changed: 13 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml

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

config/crd/experimental/gateway.networking.k8s.io_tcproutes.yaml

Lines changed: 13 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml

Lines changed: 13 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/experimental/gateway.networking.k8s.io_udproutes.yaml

Lines changed: 13 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/standard/gateway.networking.k8s.io_httproutes.yaml

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

hack/verify-examples-kind.sh renamed to hack/verify-crds-kind.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ for CHANNEL in experimental standard; do
6161
kubectl apply -f "config/crd/${CHANNEL}/gateway*.yaml"
6262

6363
# Run tests.
64-
go test -timeout=120s -count=1 sigs.k8s.io/gateway-api/hack/cel-validation
64+
go test -timeout=120s -count=1 --tags ${CHANNEL} sigs.k8s.io/gateway-api/pkg/test/cel
6565

6666
# Delete CRDs to reset environment.
6767
kubectl delete -f "config/crd/${CHANNEL}/gateway*.yaml"

pkg/generator/main.go

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -175,18 +175,44 @@ func gatewayTweaks(channel string, props map[string]apiext.JSONSchemaProps) map[
175175
jsonProps.Type = "string"
176176
}
177177

178-
if channel == "experimental" && strings.Contains(jsonProps.Description, "<gateway:experimental:validation:") {
179-
validationRe := regexp.MustCompile(`<gateway:experimental:validation:Enum=([A-Za-z;]*)>`)
180-
match := validationRe.FindStringSubmatch(jsonProps.Description)
181-
if len(match) != 2 {
182-
log.Fatalf("Invalid gateway:experimental:validation tag for %s", name)
178+
validationPrefix := fmt.Sprintf("<gateway:%s:validation:", channel)
179+
numExpressions := strings.Count(jsonProps.Description, validationPrefix)
180+
numValid := 0
181+
if numExpressions > 0 {
182+
enumRe := regexp.MustCompile(validationPrefix + "Enum=([A-Za-z;]*)>")
183+
enumMatches := enumRe.FindAllStringSubmatch(jsonProps.Description, 64)
184+
for _, enumMatch := range enumMatches {
185+
if len(enumMatch) != 2 {
186+
log.Fatalf("Invalid %s Enum tag for %s", validationPrefix, name)
187+
}
188+
189+
numValid++
190+
jsonProps.Enum = []apiext.JSON{}
191+
for _, val := range strings.Split(enumMatch[1], ";") {
192+
jsonProps.Enum = append(jsonProps.Enum, apiext.JSON{Raw: []byte("\"" + val + "\"")})
193+
}
183194
}
184-
jsonProps.Enum = []apiext.JSON{}
185-
for _, val := range strings.Split(match[1], ";") {
186-
jsonProps.Enum = append(jsonProps.Enum, apiext.JSON{Raw: []byte("\"" + val + "\"")})
195+
196+
celRe := regexp.MustCompile(validationPrefix + "XValidation:message=\"([^\"]*)\",rule=\"([^\"]*)\">")
197+
celMatches := celRe.FindAllStringSubmatch(jsonProps.Description, 64)
198+
for _, celMatch := range celMatches {
199+
if len(celMatch) != 3 {
200+
log.Fatalf("Invalid %s CEL tag for %s", validationPrefix, name)
201+
}
202+
203+
numValid++
204+
jsonProps.XValidations = append(jsonProps.XValidations, apiext.ValidationRule{
205+
Message: celMatch[1],
206+
Rule: celMatch[2],
207+
})
187208
}
188209
}
189210

211+
if numValid < numExpressions {
212+
fmt.Printf("Description: %s\n", jsonProps.Description)
213+
log.Fatalf("Found %d Gateway validation expressions, but only %d were valid", numExpressions, numValid)
214+
}
215+
190216
gatewayRe := regexp.MustCompile(`<gateway:.*>`)
191217
jsonProps.Description = gatewayRe.ReplaceAllLiteralString(jsonProps.Description, "")
192218

0 commit comments

Comments
 (0)