diff --git a/README.md b/README.md index 2b7ce2e79..996dfe205 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ The following table lists the software versions NGINX Gateway Fabric supports. | NGINX Gateway Fabric | Gateway API | Kubernetes | NGINX OSS | NGINX Plus | |----------------------|-------------|------------|-----------|------------| -| Edge | 1.1.0 | 1.25+ | 1.27.2 | R32 | +| Edge | 1.2.0 | 1.25+ | 1.27.2 | R32 | | 1.4.0 | 1.1.0 | 1.25+ | 1.27.1 | R32 | | 1.3.0 | 1.1.0 | 1.25+ | 1.27.0 | R32 | | 1.2.0 | 1.0.0 | 1.23+ | 1.25.4 | R31 | diff --git a/cmd/gateway/validation.go b/cmd/gateway/validation.go index 5559713f6..536fa4432 100644 --- a/cmd/gateway/validation.go +++ b/cmd/gateway/validation.go @@ -14,7 +14,7 @@ import ( ) const ( - // Regex from: https://github.com/kubernetes-sigs/gateway-api/blob/v1.1.0/apis/v1/shared_types.go#L647 + // Regex from: https://github.com/kubernetes-sigs/gateway-api/blob/v1.2.0/apis/v1/shared_types.go#L647 controllerNameRegex = `^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$` //nolint:lll ) diff --git a/config/crd/gateway-api/experimental/kustomization.yaml b/config/crd/gateway-api/experimental/kustomization.yaml index 0eaa2d293..0988b5a4f 100644 --- a/config/crd/gateway-api/experimental/kustomization.yaml +++ b/config/crd/gateway-api/experimental/kustomization.yaml @@ -1,4 +1,4 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - - https://github.com/kubernetes-sigs/gateway-api/config/crd/experimental?timeout=120&ref=v1.1.0 + - https://github.com/kubernetes-sigs/gateway-api/config/crd/experimental?timeout=120&ref=v1.2.0 diff --git a/config/crd/gateway-api/standard/kustomization.yaml b/config/crd/gateway-api/standard/kustomization.yaml index 4f2165d71..aa5be5af1 100644 --- a/config/crd/gateway-api/standard/kustomization.yaml +++ b/config/crd/gateway-api/standard/kustomization.yaml @@ -1,4 +1,4 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: -- https://github.com/kubernetes-sigs/gateway-api/config/crd?timeout=120&ref=v1.1.0 +- https://github.com/kubernetes-sigs/gateway-api/config/crd?timeout=120&ref=v1.2.0 diff --git a/go.mod b/go.mod index 42ea08c67..6a1df43c1 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( k8s.io/client-go v0.31.1 k8s.io/klog/v2 v2.130.1 sigs.k8s.io/controller-runtime v0.19.0 - sigs.k8s.io/gateway-api v1.1.0 + sigs.k8s.io/gateway-api v1.2.0 ) require ( @@ -84,7 +84,7 @@ require ( gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/grpc v1.66.1 // indirect + google.golang.org/grpc v1.66.2 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index c5e030f02..f77ec09c8 100644 --- a/go.sum +++ b/go.sum @@ -198,8 +198,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1: google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.66.1 h1:hO5qAXR19+/Z44hmvIM4dQFMSYX9XcWsByfoxutBpAM= -google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= +google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -230,8 +230,8 @@ k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1 k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= -sigs.k8s.io/gateway-api v1.1.0 h1:DsLDXCi6jR+Xz8/xd0Z1PYl2Pn0TyaFMOPPZIj4inDM= -sigs.k8s.io/gateway-api v1.1.0/go.mod h1:ZH4lHrL2sDi0FHZ9jjneb8kKnGzFWyrTya35sWUTrRs= +sigs.k8s.io/gateway-api v1.2.0 h1:LrToiFwtqKTKZcZtoQPTuo3FxhrrhTgzQG0Te+YGSo8= +sigs.k8s.io/gateway-api v1.2.0/go.mod h1:EpNfEXNjiYfUJypf0eZ0P5iXA9ekSGWaS1WgPaM42X0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= diff --git a/internal/framework/gatewayclass/validate.go b/internal/framework/gatewayclass/validate.go index 14bef9828..57b249de7 100644 --- a/internal/framework/gatewayclass/validate.go +++ b/internal/framework/gatewayclass/validate.go @@ -13,7 +13,7 @@ const ( // BundleVersionAnnotation is the annotation on Gateway API CRDs that contains the installed version. BundleVersionAnnotation = "gateway.networking.k8s.io/bundle-version" // SupportedVersion is the supported version of the Gateway API CRDs. - SupportedVersion = "v1.1.0" + SupportedVersion = "v1.2.0" ) var gatewayCRDs = map[string]apiVersion{ diff --git a/internal/mode/static/state/graph/grpcroute.go b/internal/mode/static/state/graph/grpcroute.go index 4d4ed05b7..9a9c81f60 100644 --- a/internal/mode/static/state/graph/grpcroute.go +++ b/internal/mode/static/state/graph/grpcroute.go @@ -232,7 +232,7 @@ func validateGRPCMatch( for j, h := range match.Headers { headerPath := matchPath.Child("headers").Index(j) - allErrs = append(allErrs, validateHeaderMatch(validator, h.Type, string(h.Name), h.Value, headerPath)...) + allErrs = append(allErrs, validateGRPCHeaderMatch(validator, h.Type, string(h.Name), h.Value, headerPath)...) } return allErrs @@ -277,3 +277,27 @@ func validateGRPCMethodMatch( } return allErrs } + +func validateGRPCHeaderMatch( + validator validation.HTTPFieldsValidator, + headerType *v1.GRPCHeaderMatchType, + headerName, headerValue string, + headerPath *field.Path, +) field.ErrorList { + var allErrs field.ErrorList + + if headerType == nil { + allErrs = append(allErrs, field.Required(headerPath.Child("type"), "cannot be empty")) + } else if *headerType != v1.GRPCHeaderMatchExact { + valErr := field.NotSupported( + headerPath.Child("type"), + *headerType, + []string{string(v1.GRPCHeaderMatchExact)}, + ) + allErrs = append(allErrs, valErr) + } + + allErrs = append(allErrs, validateHeaderMatchNameAndValue(validator, headerName, headerValue, headerPath)...) + + return allErrs +} diff --git a/internal/mode/static/state/graph/grpcroute_test.go b/internal/mode/static/state/graph/grpcroute_test.go index 1045939bf..782856dc1 100644 --- a/internal/mode/static/state/graph/grpcroute_test.go +++ b/internal/mode/static/state/graph/grpcroute_test.go @@ -42,7 +42,7 @@ func createGRPCHeadersMatch(headerType, headerName, headerValue string) v1.GRPCR { Headers: []v1.GRPCHeaderMatch{ { - Type: (*v1.HeaderMatchType)(&headerType), + Type: (*v1.GRPCHeaderMatchType)(&headerType), Name: v1.GRPCHeaderName(headerName), Value: headerValue, }, @@ -242,6 +242,19 @@ func TestBuildGRPCRoute(t *testing.T) { methodMatchNilType := createGRPCMethodMatch("myService", "myMethod", "nilType") headersMatchInvalid := createGRPCHeadersMatch("", "MyHeader", "SomeValue") + headersMatchEmptyType := v1.GRPCRouteRule{ + Matches: []v1.GRPCRouteMatch{ + { + Headers: []v1.GRPCHeaderMatch{ + { + Name: v1.GRPCHeaderName("MyHeader"), + Value: "SomeValue", + }, + }, + }, + }, + } + grBoth := createGRPCRoute( "gr-1", gatewayNsName.Name, @@ -290,12 +303,19 @@ func TestBuildGRPCRoute(t *testing.T) { "example.com", []v1.GRPCRouteRule{methodMatchNilType}, ) - grInvalidHeadersEmptyType := createGRPCRoute( + grInvalidHeadersInvalidType := createGRPCRoute( "gr-1", gatewayNsName.Name, "example.com", []v1.GRPCRouteRule{headersMatchInvalid}, ) + + grInvalidHeadersEmptyType := createGRPCRoute( + "gr-1", + gatewayNsName.Name, + "example.com", + []v1.GRPCRouteRule{headersMatchEmptyType}, + ) grOneInvalid := createGRPCRoute( "gr-1", gatewayNsName.Name, @@ -736,6 +756,44 @@ func TestBuildGRPCRoute(t *testing.T) { }, name: "invalid headers and valid method", }, + { + validator: createAllValidValidator(), + gr: grInvalidHeadersInvalidType, + expected: &L7Route{ + Source: grInvalidHeadersInvalidType, + RouteType: RouteTypeGRPC, + Valid: false, + Attachable: true, + ParentRefs: []ParentRef{ + { + Idx: 0, + Gateway: gatewayNsName, + SectionName: grInvalidHeadersInvalidType.Spec.ParentRefs[0].SectionName, + }, + }, + Conditions: []conditions.Condition{ + staticConds.NewRouteUnsupportedValue( + `All rules are invalid: spec.rules[0].matches[0].headers[0].type: ` + + `Unsupported value: "": supported values: "Exact"`, + ), + }, + Spec: L7RouteSpec{ + Hostnames: grInvalidHeadersInvalidType.Spec.Hostnames, + Rules: []RouteRule{ + { + ValidMatches: false, + Filters: RouteRuleFilters{ + Valid: true, + Filters: []Filter{}, + }, + Matches: convertGRPCMatches(grInvalidHeadersInvalidType.Spec.Rules[0].Matches), + RouteBackendRefs: []RouteBackendRef{}, + }, + }, + }, + }, + name: "invalid headers with invalid type", + }, { validator: createAllValidValidator(), gr: grInvalidHeadersEmptyType, @@ -754,7 +812,7 @@ func TestBuildGRPCRoute(t *testing.T) { Conditions: []conditions.Condition{ staticConds.NewRouteUnsupportedValue( `All rules are invalid: spec.rules[0].matches[0].headers[0].type: ` + - `Unsupported value: "": supported values: "Exact"`, + `Required value: cannot be empty`, ), }, Spec: L7RouteSpec{ @@ -772,7 +830,7 @@ func TestBuildGRPCRoute(t *testing.T) { }, }, }, - name: "invalid headers with empty type", + name: "invalid headers with no header type specified", }, { validator: createAllValidValidator(), diff --git a/internal/mode/static/state/graph/route_common.go b/internal/mode/static/state/graph/route_common.go index 9a4dbe3a1..4b2e767c6 100644 --- a/internal/mode/static/state/graph/route_common.go +++ b/internal/mode/static/state/graph/route_common.go @@ -868,6 +868,17 @@ func validateHeaderMatch( allErrs = append(allErrs, valErr) } + allErrs = append(allErrs, validateHeaderMatchNameAndValue(validator, headerName, headerValue, headerPath)...) + + return allErrs +} + +func validateHeaderMatchNameAndValue( + validator validation.HTTPFieldsValidator, + headerName, headerValue string, + headerPath *field.Path, +) field.ErrorList { + var allErrs field.ErrorList if err := validator.ValidateHeaderNameInMatch(headerName); err != nil { valErr := field.Invalid(headerPath.Child("name"), headerName, err.Error()) allErrs = append(allErrs, valErr) @@ -877,7 +888,6 @@ func validateHeaderMatch( valErr := field.Invalid(headerPath.Child("value"), headerValue, err.Error()) allErrs = append(allErrs, valErr) } - return allErrs } diff --git a/tests/go.mod b/tests/go.mod index 7cf833545..585c837a9 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -14,7 +14,7 @@ require ( k8s.io/apimachinery v0.31.1 k8s.io/client-go v0.31.1 sigs.k8s.io/controller-runtime v0.19.0 - sigs.k8s.io/gateway-api v1.1.0 + sigs.k8s.io/gateway-api v1.2.0 sigs.k8s.io/yaml v1.4.0 ) @@ -46,7 +46,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/miekg/dns v1.1.61 // indirect + github.com/miekg/dns v1.1.62 // indirect github.com/moby/spdystream v0.4.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -72,7 +72,7 @@ require ( golang.org/x/tools v0.25.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/grpc v1.66.1 // indirect + google.golang.org/grpc v1.66.2 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/tests/go.sum b/tests/go.sum index a11306d56..36d5481c6 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -77,8 +77,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= -github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= +github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= +github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -187,8 +187,8 @@ gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJ gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.66.1 h1:hO5qAXR19+/Z44hmvIM4dQFMSYX9XcWsByfoxutBpAM= -google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= +google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -221,8 +221,8 @@ pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= -sigs.k8s.io/gateway-api v1.1.0 h1:DsLDXCi6jR+Xz8/xd0Z1PYl2Pn0TyaFMOPPZIj4inDM= -sigs.k8s.io/gateway-api v1.1.0/go.mod h1:ZH4lHrL2sDi0FHZ9jjneb8kKnGzFWyrTya35sWUTrRs= +sigs.k8s.io/gateway-api v1.2.0 h1:LrToiFwtqKTKZcZtoQPTuo3FxhrrhTgzQG0Te+YGSo8= +sigs.k8s.io/gateway-api v1.2.0/go.mod h1:EpNfEXNjiYfUJypf0eZ0P5iXA9ekSGWaS1WgPaM42X0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=