diff --git a/api/v1alpha1/ratelimit_types.go b/api/v1alpha1/ratelimit_types.go index de195ffd760..cc9b742fa65 100644 --- a/api/v1alpha1/ratelimit_types.go +++ b/api/v1alpha1/ratelimit_types.go @@ -98,7 +98,6 @@ type RateLimitRule struct { // the request path and do not reduce the rate limit counters on the response path. // // +optional - // +notImplementedHide Cost *RateLimitCost `json:"cost,omitempty"` } @@ -112,7 +111,6 @@ type RateLimitCost struct { // enough capacity, the request is rate limited. // // +optional - // +notImplementedHide Request *RateLimitCostSpecifier `json:"request,omitempty"` // Response specifies the number to reduce the rate limit counters // after the response is sent back to the client or the request stream is closed. @@ -127,7 +125,6 @@ type RateLimitCost struct { // Currently, this is only supported for HTTP Global Rate Limits. // // +optional - // +notImplementedHide Response *RateLimitCostSpecifier `json:"response,omitempty"` } @@ -143,12 +140,10 @@ type RateLimitCostSpecifier struct { // Using zero can be used to only check the rate limit counters without reducing them. // // +optional - // +notImplementedHide Number *uint64 `json:"number,omitempty"` // Metadata specifies the per-request metadata to retrieve the usage number from. // // +optional - // +notImplementedHide Metadata *RateLimitCostMetadata `json:"metadata,omitempty"` } diff --git a/examples/grpc-ext-proc/main.go b/examples/grpc-ext-proc/main.go index 0aab517f298..fa333f7d3f5 100644 --- a/examples/grpc-ext-proc/main.go +++ b/examples/grpc-ext-proc/main.go @@ -20,7 +20,6 @@ import ( envoy_api_v3_core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" envoy_service_proc_v3 "github.com/envoyproxy/go-control-plane/envoy/service/ext_proc/v3" - "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" @@ -329,10 +328,26 @@ func (s *extProcServer) Process(srv envoy_service_proc_v3.ExternalProcessor_Proc }, }, } + resp = &envoy_service_proc_v3.ProcessingResponse{ Response: &envoy_service_proc_v3.ProcessingResponse_ResponseHeaders{ ResponseHeaders: rhq, }, + DynamicMetadata: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "io.envoyproxy.gateway.e2e": { + Kind: &structpb.Value_StructValue{ + StructValue: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "request_cost_set_by_ext_proc": { + Kind: &structpb.Value_NumberValue{NumberValue: float64(10)}, + }, + }, + }, + }, + }, + }, + }, } break default: diff --git a/internal/gatewayapi/backendtrafficpolicy.go b/internal/gatewayapi/backendtrafficpolicy.go index 2d07982cfef..0246c4115bc 100644 --- a/internal/gatewayapi/backendtrafficpolicy.go +++ b/internal/gatewayapi/backendtrafficpolicy.go @@ -791,9 +791,30 @@ func buildRateLimitRule(rule egv1a1.RateLimitRule) (*ir.RateLimitRule, error) { irRule.CIDRMatch = cidrMatch } } + + if cost := rule.Cost; cost != nil { + if cost.Request != nil { + irRule.RequestCost = translateRateLimitCost(cost.Request) + } + if cost.Response != nil { + irRule.ResponseCost = translateRateLimitCost(cost.Response) + } + } return irRule, nil } +func translateRateLimitCost(cost *egv1a1.RateLimitCostSpecifier) *ir.RateLimitCost { + ret := &ir.RateLimitCost{} + if cost.Number != nil { + ret.Number = cost.Number + } + if cost.Metadata != nil { + ret.Format = ptr.To(fmt.Sprintf("%%DYNAMIC_METADATA(%s:%s)%%", + cost.Metadata.Namespace, cost.Metadata.Key)) + } + return ret +} + func int64ToUint32(in int64) (uint32, bool) { if in >= 0 && in <= math.MaxUint32 { return uint32(in), true diff --git a/internal/gatewayapi/backendtrafficpolicy_test.go b/internal/gatewayapi/backendtrafficpolicy_test.go index ebf721fb07d..e104f3b0bae 100644 --- a/internal/gatewayapi/backendtrafficpolicy_test.go +++ b/internal/gatewayapi/backendtrafficpolicy_test.go @@ -11,6 +11,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "k8s.io/utils/ptr" egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" "github.com/envoyproxy/gateway/internal/ir" @@ -107,3 +108,27 @@ func TestMakeIrTriggerSet(t *testing.T) { }) } } + +func Test_translateRateLimitCost(t *testing.T) { + for _, tc := range []struct { + name string + cost *egv1a1.RateLimitCostSpecifier + exp *ir.RateLimitCost + }{ + { + name: "number", + cost: &egv1a1.RateLimitCostSpecifier{Number: ptr.To[uint64](1)}, + exp: &ir.RateLimitCost{Number: ptr.To[uint64](1)}, + }, + { + name: "metadata", + cost: &egv1a1.RateLimitCostSpecifier{Metadata: &egv1a1.RateLimitCostMetadata{Namespace: "something.com", Key: "name"}}, + exp: &ir.RateLimitCost{Format: ptr.To(`%DYNAMIC_METADATA(something.com:name)%`)}, + }, + } { + t.Run(tc.name, func(t *testing.T) { + act := translateRateLimitCost(tc.cost) + require.Equal(t, tc.exp, act) + }) + } +} diff --git a/internal/gatewayapi/clienttrafficpolicy.go b/internal/gatewayapi/clienttrafficpolicy.go index 1c8d0f8af4a..162f1698061 100644 --- a/internal/gatewayapi/clienttrafficpolicy.go +++ b/internal/gatewayapi/clienttrafficpolicy.go @@ -484,6 +484,12 @@ func (t *Translator) translateClientTrafficPolicyForListener(policy *egv1a1.Clie // Early return if got any errors if errs != nil { + for _, route := range httpIR.Routes { + // Return a 500 direct response + route.DirectResponse = &ir.CustomResponse{ + StatusCode: ptr.To(uint32(500)), + } + } return errs } @@ -504,6 +510,9 @@ func (t *Translator) translateClientTrafficPolicyForListener(policy *egv1a1.Clie // Early return if got any errors if errs != nil { + // Remove all TCP routes if there are any errors + // The listener will still be created, but any client traffic will be forwarded to the default empty cluster + tcpIR.Routes = nil return errs } diff --git a/internal/gatewayapi/ext_service.go b/internal/gatewayapi/ext_service.go index b1111ffa0f4..26452399ed0 100644 --- a/internal/gatewayapi/ext_service.go +++ b/internal/gatewayapi/ext_service.go @@ -95,8 +95,7 @@ func (t *Translator) processExtServiceDestination( if !t.BackendEnabled { return nil, fmt.Errorf("resource %s of type Backend cannot be used since Backend is disabled in Envoy Gateway configuration", string(backendRef.Name)) } - ds = t.processBackendDestinationSetting(backendRef.BackendObjectReference, backendNamespace, resources) - ds.Protocol = protocol + ds = t.processBackendDestinationSetting(backendRef.BackendObjectReference, backendNamespace, protocol, resources) } if ds == nil { diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index 56466649d80..8145c49f773 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -1359,7 +1359,7 @@ func (t *Translator) processDestination(backendRefContext BackendRefContext, } ds.IPFamily = getServiceIPFamily(resources.GetService(backendNamespace, string(backendRef.Name))) case egv1a1.KindBackend: - ds = t.processBackendDestinationSetting(backendRef.BackendObjectReference, backendNamespace, resources) + ds = t.processBackendDestinationSetting(backendRef.BackendObjectReference, backendNamespace, protocol, resources) ds.TLS, err = t.applyBackendTLSSetting( backendRef.BackendObjectReference, backendNamespace, @@ -1725,11 +1725,10 @@ func getTargetBackendReference(backendRef gwapiv1a2.BackendObjectReference, back return ref } -func (t *Translator) processBackendDestinationSetting(backendRef gwapiv1.BackendObjectReference, backendNamespace string, resources *resource.Resources) *ir.DestinationSetting { +func (t *Translator) processBackendDestinationSetting(backendRef gwapiv1.BackendObjectReference, backendNamespace string, protocol ir.AppProtocol, resources *resource.Resources) *ir.DestinationSetting { var ( dstEndpoints []*ir.DestinationEndpoint dstAddrType *ir.DestinationAddressType - dstProtocol ir.AppProtocol ) addrTypeMap := make(map[ir.DestinationAddressType]int) @@ -1775,14 +1774,16 @@ func (t *Translator) processBackendDestinationSetting(backendRef gwapiv1.Backend } for _, ap := range backend.Spec.AppProtocols { - if ap == egv1a1.AppProtocolTypeH2C { - dstProtocol = ir.HTTP2 - break + switch ap { + case egv1a1.AppProtocolTypeH2C: + protocol = ir.HTTP2 + case "grpc": + protocol = ir.GRPC } } ds := &ir.DestinationSetting{ - Protocol: dstProtocol, + Protocol: protocol, Endpoints: dstEndpoints, AddressType: dstAddrType, } diff --git a/internal/gatewayapi/testdata/backend-with-fallback.out.yaml b/internal/gatewayapi/testdata/backend-with-fallback.out.yaml index 74bd61795fe..d5f7e87642d 100644 --- a/internal/gatewayapi/testdata/backend-with-fallback.out.yaml +++ b/internal/gatewayapi/testdata/backend-with-fallback.out.yaml @@ -160,12 +160,14 @@ xdsIR: endpoints: - host: 1.1.1.1 port: 3001 + protocol: HTTP weight: 1 - addressType: IP endpoints: - host: 2.2.2.2 port: 3001 priority: 1 + protocol: HTTP weight: 1 hostname: '*' isHTTP2: false diff --git a/internal/gatewayapi/testdata/backendtlspolicy-default-ns-targetrefs.out.yaml b/internal/gatewayapi/testdata/backendtlspolicy-default-ns-targetrefs.out.yaml index bbea6c79f5f..a6cf1223961 100644 --- a/internal/gatewayapi/testdata/backendtlspolicy-default-ns-targetrefs.out.yaml +++ b/internal/gatewayapi/testdata/backendtlspolicy-default-ns-targetrefs.out.yaml @@ -300,6 +300,7 @@ xdsIR: endpoints: - host: 2.2.2.2 port: 3443 + protocol: HTTP tls: alpnProtocols: null caCertificate: @@ -357,6 +358,7 @@ xdsIR: endpoints: - host: 2.2.2.2 port: 3443 + protocol: HTTP tls: alpnProtocols: null caCertificate: diff --git a/internal/gatewayapi/testdata/backendtlspolicy-default-ns.out.yaml b/internal/gatewayapi/testdata/backendtlspolicy-default-ns.out.yaml index 0fbf1d8d411..5dab3f46b19 100644 --- a/internal/gatewayapi/testdata/backendtlspolicy-default-ns.out.yaml +++ b/internal/gatewayapi/testdata/backendtlspolicy-default-ns.out.yaml @@ -261,6 +261,7 @@ xdsIR: endpoints: - host: 2.2.2.2 port: 3443 + protocol: HTTP tls: alpnProtocols: null caCertificate: @@ -272,6 +273,7 @@ xdsIR: endpoints: - host: 3.3.3.3 port: 3443 + protocol: HTTP weight: 1 hostname: '*' isHTTP2: false diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.in.yaml index f536d9a20bc..67874070632 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.in.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.in.yaml @@ -110,3 +110,12 @@ backendTrafficPolicies: limit: requests: 20 unit: Hour + cost: + request: + from: Number + number: 1 + response: + from: Metadata + metadata: + namespace: something.com + key: some_cost_set_by_foo diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.out.yaml index 07fa997e109..a7eb921e023 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.out.yaml @@ -13,6 +13,15 @@ backendTrafficPolicies: - sourceCIDR: type: Distinct value: 192.168.0.0/16 + cost: + request: + from: Number + number: 1 + response: + from: Metadata + metadata: + key: some_cost_set_by_foo + namespace: something.com limit: requests: 20 unit: Hour @@ -370,3 +379,7 @@ xdsIR: limit: requests: 20 unit: Hour + requestCost: + number: 1 + responseCost: + format: '%DYNAMIC_METADATA(something.com:some_cost_set_by_foo)%' diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-invalid-settings.in.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-invalid-settings.in.yaml new file mode 100644 index 00000000000..d205efd678f --- /dev/null +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-invalid-settings.in.yaml @@ -0,0 +1,147 @@ +clientTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: ClientTrafficPolicy + metadata: + namespace: default + name: target-gateway-1 + spec: + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + headers: + xForwardedClientCert: + mode: Sanitize + certDetailsToAdd: + - Cert + tls: + clientValidation: + caCertificateRefs: + - name: tls-secret-1 + namespace: default +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: default + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http-1 + protocol: HTTPS + port: 443 + allowedRoutes: + namespaces: + from: Same + tls: + mode: Terminate + certificateRefs: + - name: tls-secret-1 + namespace: default + - name: http-2 + protocol: HTTP + port: 8080 + allowedRoutes: + namespaces: + from: Same + - name: tcp-1 + protocol: TLS + port: 8443 + allowedRoutes: + namespaces: + from: Same + tls: + mode: Terminate + certificateRefs: + - name: tls-secret-1 + namespace: default + - name: tcp-2 + protocol: TCP + port: 5000 + allowedRoutes: + namespaces: + from: Same +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + parentRefs: + - namespace: default + name: gateway-1 + sectionName: http-1 + rules: + - backendRefs: + - name: service-1 + port: 8080 +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-2 + spec: + parentRefs: + - namespace: default + name: gateway-1 + sectionName: http-1 + rules: + - backendRefs: + - name: service-1 + port: 8080 +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-3 + spec: + parentRefs: + - namespace: default + name: gateway-1 + sectionName: http-2 + rules: + - backendRefs: + - name: service-1 + port: 8080 +tcpRoutes: +- apiVersion: gateway.networking.k8s.io/v1alpha2 + kind: TCPRoute + metadata: + name: tcp-route-1 + namespace: default + spec: + parentRefs: + - namespace: default + name: gateway-1 + sectionName: tcp-1 + rules: + - backendRefs: + - name: service-1 + port: 8080 +- apiVersion: gateway.networking.k8s.io/v1alpha2 + kind: TCPRoute + metadata: + name: tcp-route-1 + namespace: default + spec: + parentRefs: + - namespace: default + name: gateway-1 + sectionName: tcp-2 + rules: + - backendRefs: + - name: service-1 + port: 8080 +secrets: +- apiVersion: v1 + kind: Secret + metadata: + namespace: default + name: tls-secret-1 + type: kubernetes.io/tls + data: + invalid-ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURPekNDQWlPZ0F3SUJBZ0lVYzQxa3BFOXdLK05IZ1JHdkJJZ3c4U0Nhei84d0RRWUpLb1pJaHZjTkFRRUwKQlFBd0xURVZNQk1HQTFVRUNnd01aWGhoYlhCc1pTQkpibU11TVJRd0VnWURWUVFEREF0bGVHRnRjR3hsTG1OdgpiVEFlRncweU5EQXhNall5TXpFMU16RmFGdzB5TlRBeE1qVXlNekUxTXpGYU1DMHhGVEFUQmdOVkJBb01ER1Y0CllXMXdiR1VnU1c1akxqRVVNQklHQTFVRUF3d0xaWGhoYlhCc1pTNWpiMjB3Z2dFaU1BMEdDU3FHU0liM0RRRUIKQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURDTGhaNURuQ1ZFNUpKOTd5T29jcFJ3Y2xibDBVd1gzY0krMVpaTmx0bApXNmpSZ3kxR3VONlZyN0NCbUkvbVB0Z0dzOVQ3RE5STWw1Z0pKa05IU1pvbUk2R2p1UDFLVWh1dmxmYlpQV05vCnA0NVQyMzVaODJHZzhPUkpIVDVtbjFRUksrYno5cnVKZnlsZE1NbGljVUp2L1lmdDZ6TlVSeFE3QlU5Y2lHZTEKdE0rVU1TeGtvcDNkb3ZWcHRFTG5rVERKU3d0NWRuK25qNmovR3I5NXo5MC9lMmdqZlZUdG1BckFHM3hoLzJCMQovRDZOWGh3UE16WXJwbG5NM2xPcHh6ZmxPVmdqTVVsb0wxb0k3c202YysyQTE0TmVCclcvb2ZCOVJEN0RXQkhkCjc2aitoY0FXRnN4WW1zSG81T3gvdEZlVGs3R1Jka0hFRUxMV0ZCdllHMEJUQWdNQkFBR2pVekJSTUIwR0ExVWQKRGdRV0JCU3JMYmNRUHBFeCtEdCtoWUUveXJqdDZyT1Y2VEFmQmdOVkhTTUVHREFXZ0JTckxiY1FQcEV4K0R0KwpoWUUveXJqdDZyT1Y2VEFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUNGCjRqbHRxeFZhS1phVk1MN0hOUVN3ZWd5K2daMXhhbHltTU5vN0lwYzh6T3lVVUk0N3dlRWYvcCtua3E4b3hpL20KbUxab2VNU2RYZytnZWJZTU1jVVJndGw5UWZ1RjBhWUNCM0FsQ3hscGRINExrM3VYTlRMUVhKaUxRUlROc0J1LwpMSjZVWXZMRktQd29kdlJLTDhLV0tFZ0xWSm1yVGUzZzhpTDNTU253MDBoV2lldUNkU3N4TmwvNDdUaGdZWHJnCnUxUFJCVXQ1ZytYb1dwVVNPQ01PRldsQkpxd0pZS2ZSQTNFNmZmNDRJVUpzYjdxVUhIQWUxd2ExWURmdUQrVDUKQXQ5L20rTTdHeVc5b0ViU1FzUFRHZllxUDU5UUUrMWllaTZxaUcrN2tuNGlSeEpxaGdtNU41bzg2UVNrME1hegpDejRqVEVLZE52WFlWRmZoNlpxcgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM0RENDQWNnQ0FRQXdEUVlKS29aSWh2Y05BUUVMQlFBd0xURVZNQk1HQTFVRUNnd01aWGhoYlhCc1pTQkoKYm1NdU1SUXdFZ1lEVlFRRERBdGxlR0Z0Y0d4bExtTnZiVEFlRncweU5EQXhNall5TXpFMU16RmFGdzB5TlRBeApNalV5TXpFMU16RmFNRDh4R1RBWEJnTlZCQU1NRUdWa1oyVXVaWGhoYlhCc1pTNWpiMjB4SWpBZ0JnTlZCQW9NCkdXVmtaMlVnWlhoaGJYQnNaU0J2Y21kaGJtbDZZWFJwYjI0d2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUIKRHdBd2dnRUtBb0lCQVFDNzdodkFQQWVGUm5xL3RwR1ZkSk5lY2Fhaks2a1F5Q2pZNXIvcFh4TkJhOXZXVlFIVQpuQ1dWT3lscEVkaDZPZlltR2dvSmF0TVRUWUFYK1ZpdkxTOVhwSDhuUENZYVpvQmRpMlA0MWRrbmsyUnpGWm1sCi9YUjVIWnREWmplRE8zd3ZCSm9ubStNeFA3Qms1TGdlOWhGSFJ3akViTGNZN3crN3pxOEJEQXlJSHY3T0ozYTcKeDkvalgyUlpGdTdPNXI1eWZFUTZGc0tjelREb29DeGRVa05JZ3RwVkNvRExLdmJMNjFuZE51bGUzL21EbS92MgpTeVRIdWQxUzVkcXNwOGtKZHU4WFVSZmMyWUVsRktXdkJ0bmpoL2pyTE1YRmNhaFYvb3hKckNIdXQvUENMYkJUCkFqVGV1U0RhdVM3T0hiSlJES3dtSDdvVnZ5SUNhSXlhWWNaTkFnTUJBQUV3RFFZSktvWklodmNOQVFFTEJRQUQKZ2dFQkFHeW5yNGNPMWFZbjRNQk90aVJ2WHFJdllHNnpxZXNrNGpQbU96TjdiUTdyRzdNUngzSVQ2SW4zVFI4RApHbFAxVE54TTg5cXZRcXp4VERsdER3bXluTlV1SEdEUW4yV1Z1OFEyK0RqRnFoc3B1WHp0NnhVK2RoVVBxUnV1Ckt6c1l4TDNpMVlWZ2pDQWtBUmp4SGhMWHYwdkFUWUVRMlJ6Uko5c2ZGcWVCMHVxSk5WL0lHamJFSzQ2eTQ5QU0KNzU4TUY4T0R6cVR2Q3hMRjJYd3BScjdjSDFuZ2J4eUJ6cEdlbkpsVTI2Q2hJT1BMZUV1NTUyUVJYVGwrU2JlQQpXUzNpS01Pb3F5NGV0b0ExNWFueW43Zm01YnpINEcyZ3Yxd1pWYlBkT1dNQWRZU2I5NDIvR09CSWUzSnIyVHo3CjRJdDRROWFERnF1aG9iOTVQMUhHQkxSQ2Y5QT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= + tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQzc3aHZBUEFlRlJucS8KdHBHVmRKTmVjYWFqSzZrUXlDalk1ci9wWHhOQmE5dldWUUhVbkNXVk95bHBFZGg2T2ZZbUdnb0phdE1UVFlBWAorVml2TFM5WHBIOG5QQ1lhWm9CZGkyUDQxZGtuazJSekZabWwvWFI1SFp0RFpqZURPM3d2Qkpvbm0rTXhQN0JrCjVMZ2U5aEZIUndqRWJMY1k3dys3enE4QkRBeUlIdjdPSjNhN3g5L2pYMlJaRnU3TzVyNXlmRVE2RnNLY3pURG8Kb0N4ZFVrTklndHBWQ29ETEt2Ykw2MW5kTnVsZTMvbURtL3YyU3lUSHVkMVM1ZHFzcDhrSmR1OFhVUmZjMllFbApGS1d2QnRuamgvanJMTVhGY2FoVi9veEpyQ0h1dC9QQ0xiQlRBalRldVNEYXVTN09IYkpSREt3bUg3b1Z2eUlDCmFJeWFZY1pOQWdNQkFBRUNnZ0VBSG1McVd4NHZCbk9ybHFLMGVNLzM5c1lLOEVpTTlra0c5eHRJWGVSTGxCWnIKM2dTeUNSTStXRzk2ZGZkaFkxSDFPa1ZDUGpJOFNEQzRkMzA2Ymw0Ris2RW93TXFrUytjcTlrcDYzYTg3aE5TbQpOMGdxSnl3TGV5YzRXdll2ZFA2c25scnd6MXE3Vk5QbXpQUXJ6b1hIQVc2N2tpeHA1cFF3OG1oVzVQcHlidkp5Clo2TERCZGRSZkVma2ZXVnZUUk5YWUVDUEllUStST05jR3JvVzZ5RXRrbk1BWUJjdjRlNUhCQkkrcHdyYmsrOVMKY2FQYUVjdm4vS0lyT3NpVW1FT2wwb3JXVnhkbjRmMy9MNmlFZFgyZHhIdXlwYkFiL0Qwak1MSzBwb3kyaXYyTApyOGI5VUQrRVZFNmFTVnp0MFRHbVpJYUdRVVZDQnVDTDhodlYwSU9PV1FLQmdRRGplL3JXdmk4Rndia3BRNDA0CnFQcitBaEFwaG1pV3l1a1B1VmJLN2Q5ZkdURzRHOW9Bd2wzYlFoRGVUNHhjMzd0cjlkcCtpamJuWnpKWHczL1cKcm5xTDlGWkZsVXZCYXN6c05VK1lRNmJVOE9zTXl6cURSdGJaaytVWEowUEx6QzZKWHFkNTFZdVVDM3NwL2lmNwpqWEZrME55aHcrdkY3VU51N0ZFSzVuWEUwd0tCZ1FEVGZOT0RLYmZyalNkZEhkV05iOHhkN2pGMlZSY3hTTnRUCit0L0FmbkRjZG8zK1NBUnJaRi9TM0hZWUxxL0l4dmZ5ZHdIblUxdC9INkxDZjBnQ2RXS2NXL1hway93ZUo1QXYKWmdaZjBPTXZsOXF0THJhTU44OG1HblV4K2IxdHZLWm4xQVcySFNuYXd2Z0kvMWVjSldNRUJiYkREbkx4cUpMegowTHJhT2pYVVh3S0JnRGlBbE44OXdjUTJSOTFkNy9mQTBRYkNVRzFmK3g1cEs5WkIvTExPdm9xS1lYVVBSZWltClhsV1ZaVWN5anZTS2hhemRGZllVTW1ycmtPK0htWHNqUDBELzRXWExIVlBmU1NMcVl1aTQ5UGt6RmM3SnM3RGoKcVgzRlpFT0o5eWJwZ2kyUW14eUIwL2RqbXFYbGdOelVWdlBwaE1PUlBFQ2ZHLzZ6SjdZRFpBRU5Bb0dBSElVcQo2UGRKVEVTKzJEbmJ3TFVnOUZIWTdjSlAzRitjNUZoaXNFemMzMzVGYTlNK2RWVVY3eE80QVU3YWVkTUxRUEYzCm1rQ05pRGsxODlEQ1gwS0JSK0RHNnZiLyt2a080clY1aXBaYTdPSW5wVTgxWXZkcndoR3pXRWY3bWI3bEdmOW4KdmNWMURZRlpmYTBoblhjVlFVZWIrL1lJM2pvRGgwblF5UGtzcFRVQ2dZRUF0NERNajdZbStRS2J2bTJXaWNlcAo1Q2s3YWFMSUxuVHZqbGRLMkdjM2loOGVGRlE2Vy9pcUc1UUEzeHMwem8xVnhlUkhPWGkrK01xWjVWTVZMZFRWCjMxWXZOeUdPbVByTitZemVINmlTYXd5VXo2dW1UN1ZkMXRuUEJ1SmdPMFM3RnRlb01BckE3TGtDcUVhMDc4bS8KRXNxNzZjYW1WdW5kRXFTRWhGMllYNkU9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-invalid-settings.out.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-invalid-settings.out.yaml new file mode 100644 index 00000000000..37f77d731a1 --- /dev/null +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-invalid-settings.out.yaml @@ -0,0 +1,512 @@ +clientTrafficPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: ClientTrafficPolicy + metadata: + creationTimestamp: null + name: target-gateway-1 + namespace: default + spec: + headers: + xForwardedClientCert: + certDetailsToAdd: + - Cert + mode: Sanitize + targetRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + tls: + clientValidation: + caCertificateRefs: + - group: null + kind: null + name: tls-secret-1 + namespace: default + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: default + conditions: + - lastTransitionTime: null + message: |- + TLS: caCertificateRef not found in secret tls-secret-1 + TLS: caCertificateRef not found in secret tls-secret-1. + reason: Invalid + status: "False" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-1 + namespace: default + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: Same + name: http-1 + port: 443 + protocol: HTTPS + tls: + certificateRefs: + - group: null + kind: null + name: tls-secret-1 + namespace: default + mode: Terminate + - allowedRoutes: + namespaces: + from: Same + name: http-2 + port: 8080 + protocol: HTTP + - allowedRoutes: + namespaces: + from: Same + name: tcp-1 + port: 8443 + protocol: TLS + tls: + certificateRefs: + - group: null + kind: null + name: tls-secret-1 + namespace: default + mode: Terminate + - allowedRoutes: + namespaces: + from: Same + name: tcp-2 + port: 5000 + protocol: TCP + status: + listeners: + - attachedRoutes: 2 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http-1 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http-2 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: tcp-1 + supportedKinds: + - group: gateway.networking.k8s.io + kind: TCPRoute + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: tcp-2 + supportedKinds: + - group: gateway.networking.k8s.io + kind: TCPRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-1 + namespace: default + spec: + parentRefs: + - name: gateway-1 + namespace: default + sectionName: http-1 + rules: + - backendRefs: + - name: service-1 + port: 8080 + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: default + sectionName: http-1 +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-2 + namespace: default + spec: + parentRefs: + - name: gateway-1 + namespace: default + sectionName: http-1 + rules: + - backendRefs: + - name: service-1 + port: 8080 + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: default + sectionName: http-1 +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-3 + namespace: default + spec: + parentRefs: + - name: gateway-1 + namespace: default + sectionName: http-2 + rules: + - backendRefs: + - name: service-1 + port: 8080 + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: default + sectionName: http-2 +infraIR: + default/gateway-1: + proxy: + listeners: + - address: null + name: default/gateway-1/http-1 + ports: + - containerPort: 10443 + name: https-443 + protocol: HTTPS + servicePort: 443 + - address: null + name: default/gateway-1/http-2 + ports: + - containerPort: 8080 + name: http-8080 + protocol: HTTP + servicePort: 8080 + - address: null + name: default/gateway-1/tcp-1 + ports: + - containerPort: 8443 + name: tls-8443 + protocol: TLS + servicePort: 8443 + - address: null + name: default/gateway-1/tcp-2 + ports: + - containerPort: 5000 + name: tcp-5000 + protocol: TCP + servicePort: 5000 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: default + name: default/gateway-1 +tcpRoutes: +- apiVersion: gateway.networking.k8s.io/v1alpha2 + kind: TCPRoute + metadata: + creationTimestamp: null + name: tcp-route-1 + namespace: default + spec: + parentRefs: + - name: gateway-1 + namespace: default + sectionName: tcp-1 + rules: + - backendRefs: + - name: service-1 + port: 8080 + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: default + sectionName: tcp-1 +- apiVersion: gateway.networking.k8s.io/v1alpha2 + kind: TCPRoute + metadata: + creationTimestamp: null + name: tcp-route-1 + namespace: default + spec: + parentRefs: + - name: gateway-1 + namespace: default + sectionName: tcp-2 + rules: + - backendRefs: + - name: service-1 + port: 8080 + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: default + sectionName: tcp-2 +xdsIR: + default/gateway-1: + accessLog: + text: + - path: /dev/stdout + http: + - address: 0.0.0.0 + headers: + withUnderscoresAction: RejectRequest + xForwardedClientCert: + mode: Sanitize + hostnames: + - '*' + isHTTP2: false + metadata: + kind: Gateway + name: gateway-1 + namespace: default + sectionName: http-1 + name: default/gateway-1/http-1 + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10443 + routes: + - destination: + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + directResponse: + statusCode: 500 + hostname: '*' + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0/match/-1/* + - destination: + name: httproute/default/httproute-2/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + directResponse: + statusCode: 500 + hostname: '*' + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-2 + namespace: default + name: httproute/default/httproute-2/rule/0/match/-1/* + tls: + alpnProtocols: null + certificates: + - name: default/tls-secret-1 + privateKey: '[redacted]' + serverCertificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM0RENDQWNnQ0FRQXdEUVlKS29aSWh2Y05BUUVMQlFBd0xURVZNQk1HQTFVRUNnd01aWGhoYlhCc1pTQkoKYm1NdU1SUXdFZ1lEVlFRRERBdGxlR0Z0Y0d4bExtTnZiVEFlRncweU5EQXhNall5TXpFMU16RmFGdzB5TlRBeApNalV5TXpFMU16RmFNRDh4R1RBWEJnTlZCQU1NRUdWa1oyVXVaWGhoYlhCc1pTNWpiMjB4SWpBZ0JnTlZCQW9NCkdXVmtaMlVnWlhoaGJYQnNaU0J2Y21kaGJtbDZZWFJwYjI0d2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUIKRHdBd2dnRUtBb0lCQVFDNzdodkFQQWVGUm5xL3RwR1ZkSk5lY2Fhaks2a1F5Q2pZNXIvcFh4TkJhOXZXVlFIVQpuQ1dWT3lscEVkaDZPZlltR2dvSmF0TVRUWUFYK1ZpdkxTOVhwSDhuUENZYVpvQmRpMlA0MWRrbmsyUnpGWm1sCi9YUjVIWnREWmplRE8zd3ZCSm9ubStNeFA3Qms1TGdlOWhGSFJ3akViTGNZN3crN3pxOEJEQXlJSHY3T0ozYTcKeDkvalgyUlpGdTdPNXI1eWZFUTZGc0tjelREb29DeGRVa05JZ3RwVkNvRExLdmJMNjFuZE51bGUzL21EbS92MgpTeVRIdWQxUzVkcXNwOGtKZHU4WFVSZmMyWUVsRktXdkJ0bmpoL2pyTE1YRmNhaFYvb3hKckNIdXQvUENMYkJUCkFqVGV1U0RhdVM3T0hiSlJES3dtSDdvVnZ5SUNhSXlhWWNaTkFnTUJBQUV3RFFZSktvWklodmNOQVFFTEJRQUQKZ2dFQkFHeW5yNGNPMWFZbjRNQk90aVJ2WHFJdllHNnpxZXNrNGpQbU96TjdiUTdyRzdNUngzSVQ2SW4zVFI4RApHbFAxVE54TTg5cXZRcXp4VERsdER3bXluTlV1SEdEUW4yV1Z1OFEyK0RqRnFoc3B1WHp0NnhVK2RoVVBxUnV1Ckt6c1l4TDNpMVlWZ2pDQWtBUmp4SGhMWHYwdkFUWUVRMlJ6Uko5c2ZGcWVCMHVxSk5WL0lHamJFSzQ2eTQ5QU0KNzU4TUY4T0R6cVR2Q3hMRjJYd3BScjdjSDFuZ2J4eUJ6cEdlbkpsVTI2Q2hJT1BMZUV1NTUyUVJYVGwrU2JlQQpXUzNpS01Pb3F5NGV0b0ExNWFueW43Zm01YnpINEcyZ3Yxd1pWYlBkT1dNQWRZU2I5NDIvR09CSWUzSnIyVHo3CjRJdDRROWFERnF1aG9iOTVQMUhHQkxSQ2Y5QT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= + maxVersion: "1.3" + minVersion: "1.2" + - address: 0.0.0.0 + headers: + withUnderscoresAction: RejectRequest + xForwardedClientCert: + mode: Sanitize + hostnames: + - '*' + isHTTP2: false + metadata: + kind: Gateway + name: gateway-1 + namespace: default + sectionName: http-2 + name: default/gateway-1/http-2 + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 8080 + routes: + - destination: + name: httproute/default/httproute-3/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + hostname: '*' + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-3 + namespace: default + name: httproute/default/httproute-3/rule/0/match/-1/* + tcp: + - address: 0.0.0.0 + name: default/gateway-1/tcp-1 + port: 8443 + tls: + alpnProtocols: [] + certificates: + - name: default/tls-secret-1 + privateKey: '[redacted]' + serverCertificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM0RENDQWNnQ0FRQXdEUVlKS29aSWh2Y05BUUVMQlFBd0xURVZNQk1HQTFVRUNnd01aWGhoYlhCc1pTQkoKYm1NdU1SUXdFZ1lEVlFRRERBdGxlR0Z0Y0d4bExtTnZiVEFlRncweU5EQXhNall5TXpFMU16RmFGdzB5TlRBeApNalV5TXpFMU16RmFNRDh4R1RBWEJnTlZCQU1NRUdWa1oyVXVaWGhoYlhCc1pTNWpiMjB4SWpBZ0JnTlZCQW9NCkdXVmtaMlVnWlhoaGJYQnNaU0J2Y21kaGJtbDZZWFJwYjI0d2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUIKRHdBd2dnRUtBb0lCQVFDNzdodkFQQWVGUm5xL3RwR1ZkSk5lY2Fhaks2a1F5Q2pZNXIvcFh4TkJhOXZXVlFIVQpuQ1dWT3lscEVkaDZPZlltR2dvSmF0TVRUWUFYK1ZpdkxTOVhwSDhuUENZYVpvQmRpMlA0MWRrbmsyUnpGWm1sCi9YUjVIWnREWmplRE8zd3ZCSm9ubStNeFA3Qms1TGdlOWhGSFJ3akViTGNZN3crN3pxOEJEQXlJSHY3T0ozYTcKeDkvalgyUlpGdTdPNXI1eWZFUTZGc0tjelREb29DeGRVa05JZ3RwVkNvRExLdmJMNjFuZE51bGUzL21EbS92MgpTeVRIdWQxUzVkcXNwOGtKZHU4WFVSZmMyWUVsRktXdkJ0bmpoL2pyTE1YRmNhaFYvb3hKckNIdXQvUENMYkJUCkFqVGV1U0RhdVM3T0hiSlJES3dtSDdvVnZ5SUNhSXlhWWNaTkFnTUJBQUV3RFFZSktvWklodmNOQVFFTEJRQUQKZ2dFQkFHeW5yNGNPMWFZbjRNQk90aVJ2WHFJdllHNnpxZXNrNGpQbU96TjdiUTdyRzdNUngzSVQ2SW4zVFI4RApHbFAxVE54TTg5cXZRcXp4VERsdER3bXluTlV1SEdEUW4yV1Z1OFEyK0RqRnFoc3B1WHp0NnhVK2RoVVBxUnV1Ckt6c1l4TDNpMVlWZ2pDQWtBUmp4SGhMWHYwdkFUWUVRMlJ6Uko5c2ZGcWVCMHVxSk5WL0lHamJFSzQ2eTQ5QU0KNzU4TUY4T0R6cVR2Q3hMRjJYd3BScjdjSDFuZ2J4eUJ6cEdlbkpsVTI2Q2hJT1BMZUV1NTUyUVJYVGwrU2JlQQpXUzNpS01Pb3F5NGV0b0ExNWFueW43Zm01YnpINEcyZ3Yxd1pWYlBkT1dNQWRZU2I5NDIvR09CSWUzSnIyVHo3CjRJdDRROWFERnF1aG9iOTVQMUhHQkxSQ2Y5QT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= + maxVersion: "1.3" + minVersion: "1.2" + - address: 0.0.0.0 + name: default/gateway-1/tcp-2 + port: 5000 + routes: + - destination: + name: tcproute/default/tcp-route-1/rule/-1 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: TCP + weight: 1 + name: tcproute/default/tcp-route-1 diff --git a/internal/gatewayapi/testdata/grpcroute-with-backend.out.yaml b/internal/gatewayapi/testdata/grpcroute-with-backend.out.yaml index 1d7cb30742e..1f7f559aaf0 100644 --- a/internal/gatewayapi/testdata/grpcroute-with-backend.out.yaml +++ b/internal/gatewayapi/testdata/grpcroute-with-backend.out.yaml @@ -92,10 +92,9 @@ grpcRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Resource default/backend-ip of type Backend is not supported for - GRPCRoute routes - reason: UnsupportedValue - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -139,8 +138,15 @@ xdsIR: mergeSlashes: true port: 10080 routes: - - directResponse: - statusCode: 500 + - destination: + name: grpcroute/default/grpcroute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 1.1.1.1 + port: 3001 + protocol: GRPC + weight: 1 hostname: '*' isHTTP2: true metadata: @@ -153,8 +159,15 @@ xdsIR: distinct: false name: "" safeRegex: /com.[A-Z]+/[A-Za-z_][A-Za-z_0-9]* - - directResponse: - statusCode: 500 + - destination: + name: grpcroute/default/grpcroute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 1.1.1.1 + port: 3001 + protocol: GRPC + weight: 1 hostname: '*' isHTTP2: true metadata: diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-and-core-backendrefs.out.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-and-core-backendrefs.out.yaml index 484fe119154..e7ec462624c 100644 --- a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-and-core-backendrefs.out.yaml +++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-and-core-backendrefs.out.yaml @@ -224,6 +224,7 @@ xdsIR: endpoints: - host: 1.1.1.1 port: 3001 + protocol: HTTP weight: 1 - addressType: IP endpoints: @@ -255,6 +256,7 @@ xdsIR: endpoints: - host: primary.foo.com port: 3000 + protocol: HTTP weight: 1 - addressType: FQDN endpoints: diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref.out.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref.out.yaml index c252ac4d77f..709c48725c5 100644 --- a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref.out.yaml +++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref.out.yaml @@ -377,6 +377,7 @@ xdsIR: endpoints: - host: primary.foo.com port: 3000 + protocol: HTTP weight: 1 hostname: '*' isHTTP2: false @@ -396,6 +397,7 @@ xdsIR: endpoints: - host: 1.1.1.1 port: 3001 + protocol: HTTP weight: 1 hostname: '*' isHTTP2: false diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-diff-address-type.out.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-diff-address-type.out.yaml index 86255af66ce..deefbd7878e 100644 --- a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-diff-address-type.out.yaml +++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-diff-address-type.out.yaml @@ -329,11 +329,13 @@ xdsIR: endpoints: - host: 1.1.1.1 port: 3001 + protocol: HTTP weight: 1 - addressType: FQDN endpoints: - host: primary.foo.com port: 3000 + protocol: HTTP weight: 1 hostname: '*' isHTTP2: false diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-same-address-type.out.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-same-address-type.out.yaml index c16b8a064ca..a230922d110 100644 --- a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-same-address-type.out.yaml +++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-same-address-type.out.yaml @@ -325,11 +325,13 @@ xdsIR: endpoints: - host: 1.1.1.1 port: 3001 + protocol: HTTP weight: 1 - addressType: IP endpoints: - host: 2.2.2.2 port: 3001 + protocol: HTTP weight: 1 hostname: '*' isHTTP2: false @@ -349,11 +351,13 @@ xdsIR: endpoints: - host: primary.foo.com port: 3000 + protocol: HTTP weight: 1 - addressType: FQDN endpoints: - host: primary2.foo.com port: 3000 + protocol: HTTP weight: 1 hostname: '*' isHTTP2: false diff --git a/internal/gatewayapi/testdata/httproute-rule-with-non-service-backends-and-weights.out.yaml b/internal/gatewayapi/testdata/httproute-rule-with-non-service-backends-and-weights.out.yaml index d56407b0dd9..ee0ea6d639a 100644 --- a/internal/gatewayapi/testdata/httproute-rule-with-non-service-backends-and-weights.out.yaml +++ b/internal/gatewayapi/testdata/httproute-rule-with-non-service-backends-and-weights.out.yaml @@ -201,6 +201,7 @@ xdsIR: endpoints: - host: 10.244.0.28 port: 3000 + protocol: HTTP weight: 2 hostname: '*' isHTTP2: false @@ -220,6 +221,7 @@ xdsIR: endpoints: - host: primary.foo.com port: 3000 + protocol: HTTP weight: 1 hostname: '*' isHTTP2: false diff --git a/internal/gatewayapi/testdata/tcproute-with-backend.out.yaml b/internal/gatewayapi/testdata/tcproute-with-backend.out.yaml index 951d4c7529c..0565f5e2fc9 100644 --- a/internal/gatewayapi/testdata/tcproute-with-backend.out.yaml +++ b/internal/gatewayapi/testdata/tcproute-with-backend.out.yaml @@ -92,16 +92,14 @@ tcpRoutes: parents: - conditions: - lastTransitionTime: null - message: 'backend reference validation failed: backend is not supported for - route kind: TCPRoute' - reason: Failed to process the settings associated with the TCP route. - status: "False" + message: Route is accepted + reason: Accepted + status: "True" type: Accepted - lastTransitionTime: null - message: Resource default/backend-ip of type Backend is not supported for - TCPRoute routes - reason: UnsupportedValue - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -116,3 +114,14 @@ xdsIR: - address: 0.0.0.0 name: envoy-gateway/gateway-1/tcp port: 10090 + routes: + - destination: + name: tcproute/default/tcproute-1/rule/-1 + settings: + - addressType: IP + endpoints: + - host: 1.1.1.1 + port: 3001 + protocol: TCP + weight: 1 + name: tcproute/default/tcproute-1 diff --git a/internal/gatewayapi/testdata/tlsroute-with-backend.out.yaml b/internal/gatewayapi/testdata/tlsroute-with-backend.out.yaml index 97bce6d0acf..d5ddd669db7 100644 --- a/internal/gatewayapi/testdata/tlsroute-with-backend.out.yaml +++ b/internal/gatewayapi/testdata/tlsroute-with-backend.out.yaml @@ -125,6 +125,7 @@ xdsIR: endpoints: - host: 1.1.1.1 port: 3001 + protocol: HTTPS weight: 1 name: tlsroute/default/tlsroute-1 tls: diff --git a/internal/gatewayapi/testdata/udproute-with-backend.in.yaml b/internal/gatewayapi/testdata/udproute-with-backend.in.yaml new file mode 100644 index 00000000000..e23ec3beaa3 --- /dev/null +++ b/internal/gatewayapi/testdata/udproute-with-backend.in.yaml @@ -0,0 +1,41 @@ +gateways: + - apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: udp + protocol: UDP + port: 90 + allowedRoutes: + namespaces: + from: All +udpRoutes: + - apiVersion: gateway.networking.k8s.io/v1alpha2 + kind: UDPRoute + metadata: + namespace: default + name: udproute-1 + spec: + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + rules: + - backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-ip +backends: + - apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: Backend + metadata: + name: backend-ip + namespace: default + spec: + endpoints: + - ip: + address: 1.1.1.1 + port: 3001 diff --git a/internal/gatewayapi/testdata/udproute-with-backend.out.yaml b/internal/gatewayapi/testdata/udproute-with-backend.out.yaml new file mode 100644 index 00000000000..108d3949bb6 --- /dev/null +++ b/internal/gatewayapi/testdata/udproute-with-backend.out.yaml @@ -0,0 +1,127 @@ +backends: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: Backend + metadata: + creationTimestamp: null + name: backend-ip + namespace: default + spec: + endpoints: + - ip: + address: 1.1.1.1 + port: 3001 + status: + conditions: + - lastTransitionTime: null + message: The Backend was accepted + reason: Accepted + status: "True" + type: Accepted +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + name: udp + port: 90 + protocol: UDP + status: + listeners: + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: udp + supportedKinds: + - group: gateway.networking.k8s.io + kind: UDPRoute +infraIR: + envoy-gateway/gateway-1: + proxy: + listeners: + - address: null + name: envoy-gateway/gateway-1/udp + ports: + - containerPort: 10090 + name: udp-90 + protocol: UDP + servicePort: 90 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + name: envoy-gateway/gateway-1 +udpRoutes: +- apiVersion: gateway.networking.k8s.io/v1alpha2 + kind: UDPRoute + metadata: + creationTimestamp: null + name: udproute-1 + namespace: default + spec: + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + rules: + - backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-ip + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway +xdsIR: + envoy-gateway/gateway-1: + accessLog: + text: + - path: /dev/stdout + udp: + - address: 0.0.0.0 + name: envoy-gateway/gateway-1/udp + port: 10090 + route: + destination: + name: udproute/default/udproute-1/rule/-1 + settings: + - addressType: IP + endpoints: + - host: 1.1.1.1 + port: 3001 + protocol: UDP + weight: 1 + name: udproute/default/udproute-1 diff --git a/internal/gatewayapi/validate.go b/internal/gatewayapi/validate.go index 37a007444e2..3ca97bec9bc 100644 --- a/internal/gatewayapi/validate.go +++ b/internal/gatewayapi/validate.go @@ -70,7 +70,7 @@ func (t *Translator) validateBackendRef(backendRefContext BackendRefContext, par return fmt.Errorf("backend service import validation failed: %w", err) } case egv1a1.KindBackend: - if err := t.validateBackendRefBackend(backendRef, parentRef, resources, backendNamespace, route, routeKind); err != nil { + if err := t.validateBackendRefBackend(backendRef, parentRef, resources, backendNamespace, route); err != nil { return fmt.Errorf("backend reference validation failed: %w", err) } } @@ -273,7 +273,7 @@ func (t *Translator) validateBackendServiceImport(backendRef *gwapiv1a2.BackendR } func (t *Translator) validateBackendRefBackend(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, resources *resource.Resources, - backendNamespace string, route RouteContext, kind gwapiv1.Kind, + backendNamespace string, route RouteContext, ) error { routeStatus := GetRouteStatus(route) @@ -290,19 +290,6 @@ func (t *Translator) validateBackendRefBackend(backendRef *gwapiv1a2.BackendRef, return errors.New("backend is disabled in Envoy Gateway configuration") } - if kind != resource.KindHTTPRoute && kind != resource.KindTLSRoute { - status.SetRouteStatusCondition(routeStatus, - parentRef.routeParentStatusIdx, - route.GetGeneration(), - gwapiv1.RouteConditionResolvedRefs, - metav1.ConditionFalse, - gwapiv1.RouteReasonUnsupportedValue, - fmt.Sprintf("Resource %s/%s of type Backend is not supported for %s routes", NamespaceDerefOr(backendRef.Namespace, route.GetNamespace()), - string(backendRef.Name), kind), - ) - return fmt.Errorf("backend is not supported for route kind: %s", kind) - } - backend := resources.GetBackend(backendNamespace, string(backendRef.Name)) if backend == nil { status.SetRouteStatusCondition(routeStatus, diff --git a/internal/ir/xds.go b/internal/ir/xds.go index 9d8bad00042..821e6b608b3 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -1946,6 +1946,17 @@ type RateLimitRule struct { CIDRMatch *CIDRMatch `json:"cidrMatch,omitempty" yaml:"cidrMatch,omitempty"` // Limit holds the rate limit values. Limit RateLimitValue `json:"limit,omitempty" yaml:"limit,omitempty"` + // RequestCost specifies the cost of the request. + RequestCost *RateLimitCost `json:"requestCost,omitempty" yaml:"requestCost,omitempty"` + // ResponseCost specifies the cost of the response. + ResponseCost *RateLimitCost `json:"responseCost,omitempty" yaml:"responseCost,omitempty"` +} + +// RateLimitCost specifies the cost of the request or response. +// +k8s:deepcopy-gen=true +type RateLimitCost struct { + Number *uint64 `json:"number,omitempty" yaml:"number,omitempty"` + Format *string `json:"format,omitempty" yaml:"format,omitempty"` } type CIDRMatch struct { diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index 5b007124198..9f2aa016c73 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -2489,6 +2489,31 @@ func (in *RateLimit) DeepCopy() *RateLimit { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RateLimitCost) DeepCopyInto(out *RateLimitCost) { + *out = *in + if in.Number != nil { + in, out := &in.Number, &out.Number + *out = new(uint64) + **out = **in + } + if in.Format != nil { + in, out := &in.Format, &out.Format + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RateLimitCost. +func (in *RateLimitCost) DeepCopy() *RateLimitCost { + if in == nil { + return nil + } + out := new(RateLimitCost) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RateLimitRule) DeepCopyInto(out *RateLimitRule) { *out = *in @@ -2509,6 +2534,16 @@ func (in *RateLimitRule) DeepCopyInto(out *RateLimitRule) { **out = **in } out.Limit = in.Limit + if in.RequestCost != nil { + in, out := &in.RequestCost, &out.RequestCost + *out = new(RateLimitCost) + (*in).DeepCopyInto(*out) + } + if in.ResponseCost != nil { + in, out := &in.ResponseCost, &out.ResponseCost + *out = new(RateLimitCost) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RateLimitRule. diff --git a/internal/xds/translator/httpfilters.go b/internal/xds/translator/httpfilters.go index 0095c3573dc..60b4b8c5e03 100644 --- a/internal/xds/translator/httpfilters.go +++ b/internal/xds/translator/httpfilters.go @@ -299,8 +299,8 @@ func patchRouteWithPerRouteConfig( } // RateLimit filter is handled separately because it relies on the global - // rate limit server configuration. - if err := patchRouteWithRateLimit(route.GetRoute(), irRoute); err != nil { + // rate limit server configuration if costs are not provided. + if err := patchRouteWithRateLimit(route, irRoute); err != nil { return nil } diff --git a/internal/xds/translator/ratelimit.go b/internal/xds/translator/ratelimit.go index eb6a1c4a2cd..1bfb4a9230e 100644 --- a/internal/xds/translator/ratelimit.go +++ b/internal/xds/translator/ratelimit.go @@ -7,6 +7,7 @@ package translator import ( "bytes" + "fmt" "net/url" "strconv" "strings" @@ -26,6 +27,7 @@ import ( goyaml "gopkg.in/yaml.v3" // nolint: depguard "k8s.io/utils/ptr" + egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" "github.com/envoyproxy/gateway/internal/ir" "github.com/envoyproxy/gateway/internal/xds/types" ) @@ -118,7 +120,7 @@ func (t *Translator) buildRateLimitFilter(irListener *ir.HTTPListener) *hcmv3.Ht } rateLimitFilter := &hcmv3.HttpFilter{ - Name: wellknown.HTTPRateLimit, + Name: egv1a1.EnvoyFilterRateLimit.String(), ConfigType: &hcmv3.HttpFilter_TypedConfig{ TypedConfig: rateLimitFilterAny, }, @@ -127,20 +129,60 @@ func (t *Translator) buildRateLimitFilter(irListener *ir.HTTPListener) *hcmv3.Ht } // patchRouteWithRateLimit builds rate limit actions and appends to the route. -func patchRouteWithRateLimit(xdsRouteAction *routev3.RouteAction, irRoute *ir.HTTPRoute) error { //nolint:unparam +func patchRouteWithRateLimit(route *routev3.Route, irRoute *ir.HTTPRoute) error { //nolint:unparam // Return early if no rate limit config exists. + xdsRouteAction := route.GetRoute() if !routeContainsGlobalRateLimit(irRoute) || xdsRouteAction == nil { return nil } - - rateLimits := buildRouteRateLimits(irRoute.Name, irRoute.Traffic.RateLimit.Global) + global := irRoute.Traffic.RateLimit.Global + rateLimits, costSpecified := buildRouteRateLimits(irRoute.Name, global) + if costSpecified { + // PerRoute global rate limit configuration via typed_per_filter_config can have its own rate routev3.RateLimit that overrides the route level rate limits. + // Per-descriptor level hits_addend can only be configured there: https://github.com/envoyproxy/envoy/pull/37972 + // vs the "legacy" core route-embedded rate limits doesn't support the feature due to the "technical debt". + // + // This branch is only reached when the response cost is specified which allows us to assume that + // users are using Envoy >= v1.33.0 which also supports the typed_per_filter_config. + // + // https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ratelimit/v3/rate_limit.proto#extensions-filters-http-ratelimit-v3-ratelimitperroute + // + // Though this is not explicitly documented, the rate limit functionality is the same as the core route-embedded rate limits. + // Only code path different is in the following code which is identical for both core and typed_per_filter_config + // as we are not using virtual_host level rate limits except that when typed_per_filter_config is used, per-descriptor + // level hits_addend is correctly resolved. + // + // https://github.com/envoyproxy/envoy/blob/47f99c5aacdb582606a48c85c6c54904fd439179/source/extensions/filters/http/ratelimit/ratelimit.cc#L93-L114 + return patchRouteWithRateLimitOnTypedFilterConfig(route, rateLimits) + } xdsRouteAction.RateLimits = rateLimits return nil } -func buildRouteRateLimits(descriptorPrefix string, global *ir.GlobalRateLimit) []*routev3.RateLimit { - var rateLimits []*routev3.RateLimit +// patchRouteWithRateLimitOnTypedFilterConfig builds rate limit actions and appends to the route via +// the TypedPerFilterConfig field. +func patchRouteWithRateLimitOnTypedFilterConfig(route *routev3.Route, rateLimits []*routev3.RateLimit) error { //nolint:unparam + filterCfg := route.TypedPerFilterConfig + if filterCfg == nil { + filterCfg = make(map[string]*anypb.Any) + route.TypedPerFilterConfig = filterCfg + } + if _, ok := filterCfg[egv1a1.EnvoyFilterRateLimit.String()]; ok { + // This should not happen since this is the only place where the filter + // config is added in a route. + return fmt.Errorf( + "route already contains global rate limit filter config: %s", route.Name) + } + + g, err := anypb.New(&ratelimitfilterv3.RateLimitPerRoute{RateLimits: rateLimits}) + if err != nil { + return fmt.Errorf("failed to marshal per-route ratelimit filter config: %w", err) + } + filterCfg[egv1a1.EnvoyFilterRateLimit.String()] = g + return nil +} +func buildRouteRateLimits(descriptorPrefix string, global *ir.GlobalRateLimit) (rateLimits []*routev3.RateLimit, costSpecified bool) { // Route descriptor for each route rule action routeDescriptor := &routev3.RateLimit_Action{ ActionSpecifier: &routev3.RateLimit_Action_GenericKey_{ @@ -260,10 +302,32 @@ func buildRouteRateLimits(descriptorPrefix string, global *ir.GlobalRateLimit) [ } rateLimit := &routev3.RateLimit{Actions: rlActions} + if c := rule.RequestCost; c != nil { + rateLimit.HitsAddend = rateLimitCostToHitsAddend(c) + costSpecified = true + } rateLimits = append(rateLimits, rateLimit) + if c := rule.ResponseCost; c != nil { + // To apply the cost to the response, we need to set ApplyOnStreamDone to true which is per Rule option, + // so we need to create a new RateLimit for the response with the option set. + responseRule := &routev3.RateLimit{Actions: rlActions, ApplyOnStreamDone: true} + responseRule.HitsAddend = rateLimitCostToHitsAddend(c) + rateLimits = append(rateLimits, responseRule) + costSpecified = true + } } + return +} - return rateLimits +func rateLimitCostToHitsAddend(c *ir.RateLimitCost) *routev3.RateLimit_HitsAddend { + ret := &routev3.RateLimit_HitsAddend{} + if c.Number != nil { + ret.Number = &wrapperspb.UInt64Value{Value: *c.Number} + } + if c.Format != nil { + ret.Format = *c.Format + } + return ret } // GetRateLimitServiceConfigStr returns the PB string for the rate limit service configuration. diff --git a/internal/xds/translator/testdata/in/xds-ir/ratelimit.yaml b/internal/xds/translator/testdata/in/xds-ir/ratelimit.yaml index 7af166fca4d..f9eb434f6d2 100644 --- a/internal/xds/translator/testdata/in/xds-ir/ratelimit.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/ratelimit.yaml @@ -86,3 +86,69 @@ http: - endpoints: - host: "1.2.3.4" port: 50000 + - name: "req-and-resp-cost" + hostname: "*" + traffic: + rateLimit: + global: + rules: + - headerMatches: + - name: "x-user-id" + exact: "one" + limit: + requests: 5 + unit: second + requestCost: + number: 12345 + responseCost: + format: "%DYNAMIC_METADATA(something.com:key)%" + pathMatch: + exact: "foo/bar" + destination: + name: "first-route-dest" + settings: + - endpoints: + - host: "1.2.3.4" + port: 50000 + - name: "req-cost" + hostname: "*" + traffic: + rateLimit: + global: + rules: + - limit: + requests: 5 + unit: second + requestCost: + number: 12345 + pathMatch: + exact: "test" + destination: + name: "third-route-dest" + settings: + - endpoints: + - host: "1.2.3.4" + port: 50000 + - name: "res-cost" + hostname: "*" + traffic: + rateLimit: + global: + rules: + - headerMatches: + - name: "x-org-id" + exact: "admin" + invert: true + limit: + requests: 5 + unit: second + responseCost: + format: "%DYNAMIC_METADATA(something.com:key)%" + pathMatch: + exact: "foo/bar/login" + destination: + name: "fourth-route-dest" + settings: + - endpoints: + - host: "1.2.3.4" + port: 50000 diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit.routes.yaml index e6e83bc2bfb..ee127d9994d 100644 --- a/internal/xds/translator/testdata/out/xds-ir/ratelimit.routes.yaml +++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit.routes.yaml @@ -75,3 +75,101 @@ exact: admin upgradeConfigs: - upgradeType: websocket + - match: + path: foo/bar + name: req-and-resp-cost + route: + cluster: first-route-dest + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.ratelimit: + '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute + rateLimits: + - actions: + - genericKey: + descriptorKey: req-and-resp-cost + descriptorValue: req-and-resp-cost + - headerValueMatch: + descriptorKey: rule-0-match-0 + descriptorValue: rule-0-match-0 + expectMatch: true + headers: + - name: x-user-id + stringMatch: + exact: one + hitsAddend: + number: "12345" + - actions: + - genericKey: + descriptorKey: req-and-resp-cost + descriptorValue: req-and-resp-cost + - headerValueMatch: + descriptorKey: rule-0-match-0 + descriptorValue: rule-0-match-0 + expectMatch: true + headers: + - name: x-user-id + stringMatch: + exact: one + applyOnStreamDone: true + hitsAddend: + format: '%DYNAMIC_METADATA(something.com:key)%' + - match: + path: test + name: req-cost + route: + cluster: third-route-dest + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.ratelimit: + '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute + rateLimits: + - actions: + - genericKey: + descriptorKey: req-cost + descriptorValue: req-cost + - genericKey: + descriptorKey: rule-0-match--1 + descriptorValue: rule-0-match--1 + hitsAddend: + number: "12345" + - match: + path: foo/bar/login + name: res-cost + route: + cluster: fourth-route-dest + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.ratelimit: + '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute + rateLimits: + - actions: + - genericKey: + descriptorKey: res-cost + descriptorValue: res-cost + - headerValueMatch: + descriptorKey: rule-0-match-0 + descriptorValue: rule-0-match-0 + expectMatch: false + headers: + - name: x-org-id + stringMatch: + exact: admin + - actions: + - genericKey: + descriptorKey: res-cost + descriptorValue: res-cost + - headerValueMatch: + descriptorKey: rule-0-match-0 + descriptorValue: rule-0-match-0 + expectMatch: false + headers: + - name: x-org-id + stringMatch: + exact: admin + applyOnStreamDone: true + hitsAddend: + format: '%DYNAMIC_METADATA(something.com:key)%' diff --git a/release-notes/current.yaml b/release-notes/current.yaml index 801555af38f..0aeef6eeef5 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -8,6 +8,8 @@ breaking changes: | Outlier detection (passive health check) is now disabled by default. refer to https://gateway.envoyproxy.io/docs/api/extension_types/#backendtrafficpolicy for working with passive health checks. Envoy Gateway treats errors in calls to an extension service as fail-closed by default. Any error returned from the extension server will replace the affected resource with an "Internal Server Error" immediate response. The previous behavior can be enabled by setting the `failOpen` field to `true` in the extension service configuration. + Envoy Gateway now return a 500 response when a ClientTrafficPolicy translation fails for HTTP/GRPC routes, and forwards + client traffic to an empty cluster when a ClientTrafficPolicy translation fails for TCP routes. # Updates addressing vulnerabilities, security flaws, or compliance requirements. security updates: | @@ -21,9 +23,11 @@ new features: | Added support for defining rateLimitHpa in EnvoyGateway API Added support for preserving the user defined HTTPRoute match order in EnvoyProxy API Added support for response compression in the BackendTrafficPolicy API + Added support for cost specifier in the rate limit API. Added support for specifying dynamic metadata namespaces that External Processing services can access read from and write to in EnvoyExtensionPolicy API Added support for API Key Authentication in the SecurityPolicy API Added support for GEP-1731 (HTTPRoute Retries) + Added support for routing to Backend resources in the GRPCRoute, TCPRoute and UDPRoute APIs bug fixes: | Fixed the ability to overwrite control plane certs with the certgen command by using a new command arg (-o) diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index d7fdcb47798..19d79a73962 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -3458,6 +3458,8 @@ _Appears in:_ | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | +| `request` | _[RateLimitCostSpecifier](#ratelimitcostspecifier)_ | false | | Request specifies the number to reduce the rate limit counters
on the request path. If this is not specified, the default behavior
is to reduce the rate limit counters by 1.

When Envoy receives a request that matches the rule, it tries to reduce the
rate limit counters by the specified number. If the counter doesn't have
enough capacity, the request is rate limited. | +| `response` | _[RateLimitCostSpecifier](#ratelimitcostspecifier)_ | false | | Response specifies the number to reduce the rate limit counters
after the response is sent back to the client or the request stream is closed.

The cost is used to reduce the rate limit counters for the matching requests.
Since the reduction happens after the request stream is complete, the rate limit
won't be enforced for the current request, but for the subsequent matching requests.

This is optional and if not specified, the rate limit counters are not reduced
on the response path.

Currently, this is only supported for HTTP Global Rate Limits. | #### RateLimitCostFrom @@ -3503,6 +3505,8 @@ _Appears in:_ | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `from` | _[RateLimitCostFrom](#ratelimitcostfrom)_ | true | | From specifies where to get the rate limit cost. Currently, only "Number" and "Metadata" are supported. | +| `number` | _integer_ | false | | Number specifies the fixed usage number to reduce the rate limit counters.
Using zero can be used to only check the rate limit counters without reducing them. | +| `metadata` | _[RateLimitCostMetadata](#ratelimitcostmetadata)_ | false | | Refer to Kubernetes API documentation for fields of `metadata`. | #### RateLimitDatabaseBackend @@ -3594,6 +3598,7 @@ _Appears in:_ | --- | --- | --- | --- | --- | | `clientSelectors` | _[RateLimitSelectCondition](#ratelimitselectcondition) array_ | false | | ClientSelectors holds the list of select conditions to select
specific clients using attributes from the traffic flow.
All individual select conditions must hold True for this rule
and its limit to be applied.

If no client selectors are specified, the rule applies to all traffic of
the targeted Route.

If the policy targets a Gateway, the rule applies to each Route of the Gateway.
Please note that each Route has its own rate limit counters. For example,
if a Gateway has two Routes, and the policy has a rule with limit 10rps,
each Route will have its own 10rps limit. | | `limit` | _[RateLimitValue](#ratelimitvalue)_ | true | | Limit holds the rate limit values.
This limit is applied for traffic flows when the selectors
compute to True, causing the request to be counted towards the limit.
The limit is enforced and the request is ratelimited, i.e. a response with
429 HTTP status code is sent back to the client when
the selected requests have reached the limit. | +| `cost` | _[RateLimitCost](#ratelimitcost)_ | false | | Cost specifies the cost of requests and responses for the rule.

This is optional and if not specified, the default behavior is to reduce the rate limit counters by 1 on
the request path and do not reduce the rate limit counters on the response path. | #### RateLimitSelectCondition diff --git a/site/content/zh/latest/api/extension_types.md b/site/content/zh/latest/api/extension_types.md index d7fdcb47798..19d79a73962 100644 --- a/site/content/zh/latest/api/extension_types.md +++ b/site/content/zh/latest/api/extension_types.md @@ -3458,6 +3458,8 @@ _Appears in:_ | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | +| `request` | _[RateLimitCostSpecifier](#ratelimitcostspecifier)_ | false | | Request specifies the number to reduce the rate limit counters
on the request path. If this is not specified, the default behavior
is to reduce the rate limit counters by 1.

When Envoy receives a request that matches the rule, it tries to reduce the
rate limit counters by the specified number. If the counter doesn't have
enough capacity, the request is rate limited. | +| `response` | _[RateLimitCostSpecifier](#ratelimitcostspecifier)_ | false | | Response specifies the number to reduce the rate limit counters
after the response is sent back to the client or the request stream is closed.

The cost is used to reduce the rate limit counters for the matching requests.
Since the reduction happens after the request stream is complete, the rate limit
won't be enforced for the current request, but for the subsequent matching requests.

This is optional and if not specified, the rate limit counters are not reduced
on the response path.

Currently, this is only supported for HTTP Global Rate Limits. | #### RateLimitCostFrom @@ -3503,6 +3505,8 @@ _Appears in:_ | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `from` | _[RateLimitCostFrom](#ratelimitcostfrom)_ | true | | From specifies where to get the rate limit cost. Currently, only "Number" and "Metadata" are supported. | +| `number` | _integer_ | false | | Number specifies the fixed usage number to reduce the rate limit counters.
Using zero can be used to only check the rate limit counters without reducing them. | +| `metadata` | _[RateLimitCostMetadata](#ratelimitcostmetadata)_ | false | | Refer to Kubernetes API documentation for fields of `metadata`. | #### RateLimitDatabaseBackend @@ -3594,6 +3598,7 @@ _Appears in:_ | --- | --- | --- | --- | --- | | `clientSelectors` | _[RateLimitSelectCondition](#ratelimitselectcondition) array_ | false | | ClientSelectors holds the list of select conditions to select
specific clients using attributes from the traffic flow.
All individual select conditions must hold True for this rule
and its limit to be applied.

If no client selectors are specified, the rule applies to all traffic of
the targeted Route.

If the policy targets a Gateway, the rule applies to each Route of the Gateway.
Please note that each Route has its own rate limit counters. For example,
if a Gateway has two Routes, and the policy has a rule with limit 10rps,
each Route will have its own 10rps limit. | | `limit` | _[RateLimitValue](#ratelimitvalue)_ | true | | Limit holds the rate limit values.
This limit is applied for traffic flows when the selectors
compute to True, causing the request to be counted towards the limit.
The limit is enforced and the request is ratelimited, i.e. a response with
429 HTTP status code is sent back to the client when
the selected requests have reached the limit. | +| `cost` | _[RateLimitCost](#ratelimitcost)_ | false | | Cost specifies the cost of requests and responses for the rule.

This is optional and if not specified, the default behavior is to reduce the rate limit counters by 1 on
the request path and do not reduce the rate limit counters on the response path. | #### RateLimitSelectCondition diff --git a/test/e2e/testdata/authorization-client-ip-trusted-cidrs.yaml b/test/e2e/testdata/authorization-client-ip-trusted-cidrs.yaml index 5b56ddbab27..25aa2e9f7de 100644 --- a/test/e2e/testdata/authorization-client-ip-trusted-cidrs.yaml +++ b/test/e2e/testdata/authorization-client-ip-trusted-cidrs.yaml @@ -45,8 +45,9 @@ spec: clientIPDetection: xForwardedFor: trustedCIDRs: - - "172.16.0.0/12" - - "10.0.1.0/24" + - "172.0.0.0/8" + - "10.0.0.0/8" + - "::/0" # trust all IPv6 addresses for E2E targetRefs: - group: gateway.networking.k8s.io kind: Gateway diff --git a/test/e2e/testdata/grpcroute-to-backend-fqdn.yaml b/test/e2e/testdata/grpcroute-to-backend-fqdn.yaml new file mode 100644 index 00000000000..b7fdcbb1bf7 --- /dev/null +++ b/test/e2e/testdata/grpcroute-to-backend-fqdn.yaml @@ -0,0 +1,78 @@ +apiVersion: v1 +kind: Service +metadata: + name: grpc-infra-backend-v1 + namespace: gateway-conformance-infra +spec: + selector: + app: grpc-infra-backend-v1 + ports: + - protocol: TCP + port: 8080 + targetPort: 3000 + appProtocol: kubernetes.io/h2c +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grpc-infra-backend-v1 + namespace: gateway-conformance-infra + labels: + app: grpc-infra-backend-v1 +spec: + replicas: 2 + selector: + matchLabels: + app: grpc-infra-backend-v1 + template: + metadata: + labels: + app: grpc-infra-backend-v1 + spec: + containers: + - name: grpc-infra-backend-v1 + image: gcr.io/k8s-staging-gateway-api/echo-basic:v20240412-v1.0.0-394-g40c666fd + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: GRPC_ECHO_SERVER + value: "1" + resources: + requests: + cpu: 10m +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: GRPCRoute +metadata: + name: exact-matching + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + rules: + - matches: + - method: + service: gateway_api_conformance.echo_basic.grpcecho.GrpcEcho + method: Echo + backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-fqdn + port: 8080 +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: Backend +metadata: + name: backend-fqdn + namespace: gateway-conformance-infra +spec: + endpoints: + - fqdn: + hostname: grpc-infra-backend-v1.gateway-conformance-infra.svc.cluster.local + port: 8080 diff --git a/test/e2e/testdata/grpcroute-to-backend-ip.yaml b/test/e2e/testdata/grpcroute-to-backend-ip.yaml new file mode 100644 index 00000000000..d9e078b8dea --- /dev/null +++ b/test/e2e/testdata/grpcroute-to-backend-ip.yaml @@ -0,0 +1,67 @@ +apiVersion: v1 +kind: Service +metadata: + name: grpc-infra-backend-v1 + namespace: gateway-conformance-infra +spec: + selector: + app: grpc-infra-backend-v1 + ports: + - protocol: TCP + port: 8080 + targetPort: 3000 + appProtocol: kubernetes.io/h2c +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grpc-infra-backend-v1 + namespace: gateway-conformance-infra + labels: + app: grpc-infra-backend-v1 +spec: + replicas: 2 + selector: + matchLabels: + app: grpc-infra-backend-v1 + template: + metadata: + labels: + app: grpc-infra-backend-v1 + spec: + containers: + - name: grpc-infra-backend-v1 + image: gcr.io/k8s-staging-gateway-api/echo-basic:v20240412-v1.0.0-394-g40c666fd + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: GRPC_ECHO_SERVER + value: "1" + resources: + requests: + cpu: 10m +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: GRPCRoute +metadata: + name: exact-matching + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + rules: + - matches: + - method: + service: gateway_api_conformance.echo_basic.grpcecho.GrpcEcho + method: Echo + backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-ip + port: 8080 diff --git a/test/e2e/testdata/ratelimit-usage-ratelimit.yaml b/test/e2e/testdata/ratelimit-usage-ratelimit.yaml new file mode 100644 index 00000000000..94bc606df05 --- /dev/null +++ b/test/e2e/testdata/ratelimit-usage-ratelimit.yaml @@ -0,0 +1,102 @@ +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: BackendTrafficPolicy +metadata: + name: usage-rate-limit + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: usage-rate-limit + rateLimit: + type: Global + global: + rules: + - clientSelectors: + - headers: + - name: x-user-id + type: Exact + value: one + limit: + # 21 instead of 20 to test the zero request cost. + requests: 21 + unit: Hour + cost: + request: + from: Number + number: 0 + response: + from: Metadata + metadata: + namespace: io.envoyproxy.gateway.e2e + key: request_cost_set_by_ext_proc +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: usage-rate-limit + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + rules: + - matches: + - path: + type: PathPrefix + value: /get + backendRefs: + - name: infra-backend-v1 + port: 8080 +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyExtensionPolicy +metadata: + name: usage-rate-limit + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: usage-rate-limit + extProc: + - backendRefs: + - name: grpc-ext-proc + namespace: gateway-conformance-infra + port: 9002 + metadata: + writableNamespaces: + - io.envoyproxy.gateway.e2e + processingMode: + request: {} + response: {} +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: SecurityPolicy +metadata: + name: authorization-client-ip + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: usage-rate-limit + authorization: + defaultAction: Allow +--- +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: BackendTLSPolicy +metadata: + name: grpc-ext-proc-btls + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: '' + kind: Service + name: grpc-ext-proc + sectionName: grpc + validation: + caCertificateRefs: + - name: grpc-ext-proc-ca + group: '' + kind: ConfigMap + hostname: grpc-ext-proc.envoygateway diff --git a/test/e2e/testdata/tcproute-to-backend-fqdn.yaml b/test/e2e/testdata/tcproute-to-backend-fqdn.yaml new file mode 100644 index 00000000000..e61061be203 --- /dev/null +++ b/test/e2e/testdata/tcproute-to-backend-fqdn.yaml @@ -0,0 +1,47 @@ +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: Gateway +metadata: + name: my-tcp-gateway + namespace: gateway-conformance-infra +spec: + gatewayClassName: "{GATEWAY_CLASS_NAME}" + listeners: + - name: foo + protocol: TCP + port: 8080 + allowedRoutes: + kinds: + - kind: TCPRoute + - name: bar + protocol: TCP + port: 8090 + allowedRoutes: + kinds: + - kind: TCPRoute +--- +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: TCPRoute +metadata: + name: tcp-app-1 + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: my-tcp-gateway + sectionName: foo + rules: + - backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-fqdn + port: 8080 +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: Backend +metadata: + name: backend-fqdn + namespace: gateway-conformance-infra +spec: + endpoints: + - fqdn: + hostname: infra-backend-v1.gateway-conformance-infra.svc.cluster.local + port: 8080 diff --git a/test/e2e/testdata/tcproute-to-backend-ip.yaml b/test/e2e/testdata/tcproute-to-backend-ip.yaml new file mode 100644 index 00000000000..5d2764a2f60 --- /dev/null +++ b/test/e2e/testdata/tcproute-to-backend-ip.yaml @@ -0,0 +1,36 @@ +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: Gateway +metadata: + name: my-tcp-gateway + namespace: gateway-conformance-infra +spec: + gatewayClassName: "{GATEWAY_CLASS_NAME}" + listeners: + - name: foo + protocol: TCP + port: 8080 + allowedRoutes: + kinds: + - kind: TCPRoute + - name: bar + protocol: TCP + port: 8090 + allowedRoutes: + kinds: + - kind: TCPRoute +--- +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: TCPRoute +metadata: + name: tcp-app-1 + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: my-tcp-gateway + sectionName: foo + rules: + - backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-ip + port: 8080 diff --git a/test/e2e/testdata/tcp-route.yaml b/test/e2e/testdata/tcproute.yaml similarity index 100% rename from test/e2e/testdata/tcp-route.yaml rename to test/e2e/testdata/tcproute.yaml diff --git a/test/e2e/testdata/udproute-to-backend-fqdn.yaml b/test/e2e/testdata/udproute-to-backend-fqdn.yaml new file mode 100644 index 00000000000..8db8e12341e --- /dev/null +++ b/test/e2e/testdata/udproute-to-backend-fqdn.yaml @@ -0,0 +1,105 @@ +apiVersion: v1 +kind: Service +metadata: + name: coredns + namespace: gateway-conformance-infra + labels: + app: udp +spec: + ports: + - name: udp-dns + port: 53 + protocol: UDP + targetPort: 53 + selector: + app: udp +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: coredns + namespace: gateway-conformance-infra + labels: + app: udp +spec: + selector: + matchLabels: + app: udp + template: + metadata: + labels: + app: udp + spec: + containers: + - args: + - -conf + - /root/Corefile + image: coredns/coredns + name: coredns + volumeMounts: + - mountPath: /root + name: conf + volumes: + - configMap: + defaultMode: 420 + name: coredns + name: conf +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: coredns + namespace: gateway-conformance-infra +data: + Corefile: | + .:53 { + forward . 8.8.8.8 9.9.9.9 + log + errors + } + + foo.bar.com:53 { + whoami + } +--- +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: Gateway +metadata: + name: udp-gateway + namespace: gateway-conformance-infra +spec: + gatewayClassName: "{GATEWAY_CLASS_NAME}" + listeners: + - name: coredns + protocol: UDP + port: 5300 + allowedRoutes: + kinds: + - kind: UDPRoute +--- +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: UDPRoute +metadata: + name: udp-coredns + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: udp-gateway + sectionName: coredns + rules: + - backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-fqdn + port: 53 +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: Backend +metadata: + name: backend-fqdn + namespace: gateway-conformance-infra +spec: + endpoints: + - fqdn: + hostname: coredns.gateway-conformance-infra.svc.cluster.local + port: 53 diff --git a/test/e2e/testdata/udproute-to-backend-ip.yaml b/test/e2e/testdata/udproute-to-backend-ip.yaml new file mode 100644 index 00000000000..b75c35ae5b7 --- /dev/null +++ b/test/e2e/testdata/udproute-to-backend-ip.yaml @@ -0,0 +1,94 @@ +apiVersion: v1 +kind: Service +metadata: + name: coredns + namespace: gateway-conformance-infra + labels: + app: udp +spec: + ports: + - name: udp-dns + port: 53 + protocol: UDP + targetPort: 53 + selector: + app: udp +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: coredns + namespace: gateway-conformance-infra + labels: + app: udp +spec: + selector: + matchLabels: + app: udp + template: + metadata: + labels: + app: udp + spec: + containers: + - args: + - -conf + - /root/Corefile + image: coredns/coredns + name: coredns + volumeMounts: + - mountPath: /root + name: conf + volumes: + - configMap: + defaultMode: 420 + name: coredns + name: conf +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: coredns + namespace: gateway-conformance-infra +data: + Corefile: | + .:53 { + forward . 8.8.8.8 9.9.9.9 + log + errors + } + + foo.bar.com:53 { + whoami + } +--- +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: Gateway +metadata: + name: udp-gateway + namespace: gateway-conformance-infra +spec: + gatewayClassName: "{GATEWAY_CLASS_NAME}" + listeners: + - name: coredns + protocol: UDP + port: 5300 + allowedRoutes: + kinds: + - kind: UDPRoute +--- +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: UDPRoute +metadata: + name: udp-coredns + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: udp-gateway + sectionName: coredns + rules: + - backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-ip + port: 53 diff --git a/test/e2e/testdata/udproute.yaml b/test/e2e/testdata/udproute.yaml index 51abe821390..29ff6ed22ab 100644 --- a/test/e2e/testdata/udproute.yaml +++ b/test/e2e/testdata/udproute.yaml @@ -1,23 +1,16 @@ apiVersion: v1 -kind: Namespace -metadata: - name: gateway-conformance-udp - labels: - gateway-conformance: udp ---- -apiVersion: v1 kind: Service metadata: name: coredns - namespace: gateway-conformance-udp + namespace: gateway-conformance-infra labels: app: udp spec: ports: - - name: udp-dns - port: 53 - protocol: UDP - targetPort: 53 + - name: udp-dns + port: 53 + protocol: UDP + targetPort: 53 selector: app: udp --- @@ -25,7 +18,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: coredns - namespace: gateway-conformance-udp + namespace: gateway-conformance-infra labels: app: udp spec: @@ -38,25 +31,25 @@ spec: app: udp spec: containers: - - args: - - -conf - - /root/Corefile - image: coredns/coredns - name: coredns - volumeMounts: - - mountPath: /root - name: conf - volumes: - - configMap: - defaultMode: 420 + - args: + - -conf + - /root/Corefile + image: coredns/coredns name: coredns - name: conf + volumeMounts: + - mountPath: /root + name: conf + volumes: + - configMap: + defaultMode: 420 + name: coredns + name: conf --- apiVersion: v1 kind: ConfigMap metadata: name: coredns - namespace: gateway-conformance-udp + namespace: gateway-conformance-infra data: Corefile: | .:53 { @@ -73,27 +66,27 @@ apiVersion: gateway.networking.k8s.io/v1beta1 kind: Gateway metadata: name: udp-gateway - namespace: gateway-conformance-udp + namespace: gateway-conformance-infra spec: gatewayClassName: "{GATEWAY_CLASS_NAME}" listeners: - - name: coredns - protocol: UDP - port: 5300 - allowedRoutes: - kinds: - - kind: UDPRoute + - name: coredns + protocol: UDP + port: 5300 + allowedRoutes: + kinds: + - kind: UDPRoute --- apiVersion: gateway.networking.k8s.io/v1alpha2 kind: UDPRoute metadata: name: udp-coredns - namespace: gateway-conformance-udp + namespace: gateway-conformance-infra spec: parentRefs: - - name: udp-gateway - sectionName: coredns + - name: udp-gateway + sectionName: coredns rules: - - backendRefs: - - name: coredns - port: 53 + - backendRefs: + - name: coredns + port: 53 diff --git a/test/e2e/tests/grpcroute_with_backend.go b/test/e2e/tests/grpcroute_with_backend.go new file mode 100644 index 00000000000..8bbe13afa45 --- /dev/null +++ b/test/e2e/tests/grpcroute_with_backend.go @@ -0,0 +1,83 @@ +// Copyright Envoy Gateway Authors +// SPDX-License-Identifier: Apache-2.0 +// The full text of the Apache license is available in the LICENSE file at +// the root of the repo. + +// This file contains code derived from upstream gateway-api, it will be moved to upstream. + +//go:build e2e + +package tests + +import ( + "testing" + + "k8s.io/apimachinery/pkg/types" + gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" + "sigs.k8s.io/gateway-api/conformance/echo-basic/grpcechoserver" + "sigs.k8s.io/gateway-api/conformance/utils/grpc" + "sigs.k8s.io/gateway-api/conformance/utils/kubernetes" + "sigs.k8s.io/gateway-api/conformance/utils/suite" +) + +func init() { + ConformanceTests = append(ConformanceTests, GRPCRouteBackendFQDNTest) + ConformanceTests = append(ConformanceTests, GRPCRouteBackendIPTest) +} + +var GRPCRouteBackendFQDNTest = suite.ConformanceTest{ + ShortName: "GRPCRouteBackendFQDNTest", + Description: "GRPCRoutes with a backend ref to a FQDN Backend", + Manifests: []string{"testdata/grpcroute-to-backend-fqdn.yaml"}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + t.Run("grpc-route-1", func(t *testing.T) { + testGRPCRouteWithBackend(t, suite, "backend-fqdn") + }) + }, +} + +var GRPCRouteBackendIPTest = suite.ConformanceTest{ + ShortName: "GRPCRouteBackendIPTest", + Description: "GRPCRoutes with a backend ref to an IP Backend", + Manifests: []string{"testdata/grpcroute-to-backend-ip.yaml"}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + t.Run("grpc-route-1", func(t *testing.T) { + svcNN := types.NamespacedName{ + Name: "grpc-infra-backend-v1", + Namespace: "gateway-conformance-infra", + } + svc, err := GetService(suite.Client, svcNN) + if err != nil { + t.Fatalf("failed to get service %s: %v", svcNN, err) + } + + backendIPName := "backend-ip" + ns := "gateway-conformance-infra" + err = CreateBackend(suite.Client, types.NamespacedName{Name: backendIPName, Namespace: ns}, svc.Spec.ClusterIP, 8080) + if err != nil { + t.Fatalf("failed to create backend %s: %v", backendIPName, err) + } + t.Cleanup(func() { + if err := DeleteBackend(suite.Client, types.NamespacedName{Name: backendIPName, Namespace: ns}); err != nil { + t.Fatalf("failed to delete backend %s: %v", backendIPName, err) + } + }) + testGRPCRouteWithBackend(t, suite, backendIPName) + }) + }, +} + +func testGRPCRouteWithBackend(t *testing.T, suite *suite.ConformanceTestSuite, backendName string) { + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "exact-matching", Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &gwapiv1.GRPCRoute{}, routeNN) + BackendMustBeAccepted(t, suite.Client, types.NamespacedName{Name: backendName, Namespace: ns}) + OkResp := grpc.ExpectedResponse{ + EchoRequest: &grpcechoserver.EchoRequest{}, + Backend: "grpc-infra-backend-v1", + Namespace: ns, + } + + grpc.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.GRPCClient, suite.TimeoutConfig, gwAddr, OkResp) +} diff --git a/test/e2e/tests/ratelimit.go b/test/e2e/tests/ratelimit.go index 799b6bbece0..9e8e5d9d1cc 100644 --- a/test/e2e/tests/ratelimit.go +++ b/test/e2e/tests/ratelimit.go @@ -14,12 +14,18 @@ import ( "time" "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" + gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" + gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" "sigs.k8s.io/gateway-api/conformance/utils/http" "sigs.k8s.io/gateway-api/conformance/utils/kubernetes" "sigs.k8s.io/gateway-api/conformance/utils/roundtripper" "sigs.k8s.io/gateway-api/conformance/utils/suite" + + "github.com/envoyproxy/gateway/internal/gatewayapi" + "github.com/envoyproxy/gateway/internal/gatewayapi/resource" ) func init() { @@ -30,6 +36,7 @@ func init() { ConformanceTests = append(ConformanceTests, RateLimitBasedJwtClaimsTest) ConformanceTests = append(ConformanceTests, RateLimitMultipleListenersTest) ConformanceTests = append(ConformanceTests, RateLimitHeadersAndCIDRMatchTest) + ConformanceTests = append(ConformanceTests, UsageRateLimitTest) } var RateLimitCIDRMatchTest = suite.ConformanceTest{ @@ -662,6 +669,68 @@ var RateLimitHeadersAndCIDRMatchTest = suite.ConformanceTest{ }, } +var UsageRateLimitTest = suite.ConformanceTest{ + ShortName: "UsageRateLimit", + Description: "Perform usage-based rate limit based on response content", + Manifests: []string{"testdata/ext-proc-service.yaml", "testdata/ratelimit-usage-ratelimit.yaml"}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "usage-rate-limit", Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN) + + // Waiting for the extproc service to be ready. + ancestorRef := gwapiv1a2.ParentReference{ + Group: gatewayapi.GroupPtr(gwapiv1.GroupName), + Kind: gatewayapi.KindPtr(resource.KindGateway), + Namespace: gatewayapi.NamespacePtr(gwNN.Namespace), + Name: gwapiv1.ObjectName(gwNN.Name), + } + EnvoyExtensionPolicyMustBeAccepted(t, suite.Client, types.NamespacedName{Name: "usage-rate-limit", Namespace: ns}, suite.ControllerName, ancestorRef) + podReady := corev1.PodCondition{Type: corev1.PodReady, Status: corev1.ConditionTrue} + // Wait for the grpc ext auth service pod to be ready + WaitForPods(t, suite.Client, ns, map[string]string{"app": "grpc-ext-proc"}, corev1.PodRunning, podReady) + + requestHeaders := map[string]string{"x-user-id": "one"} + + ratelimitHeader := make(map[string]string) + expectOkResp := http.ExpectedResponse{ + Request: http.Request{ + Path: "/get", + Headers: requestHeaders, + }, + Response: http.Response{StatusCode: 200, Headers: ratelimitHeader}, + Namespace: ns, + } + expectOkResp.Response.Headers["X-Ratelimit-Limit"] = "21, 21;w=3600" + expectOkReq := http.MakeRequest(t, &expectOkResp, gwAddr, "HTTP", "http") + + expectLimitResp := http.ExpectedResponse{ + Request: http.Request{ + Path: "/get", + Headers: requestHeaders, + }, + Response: http.Response{ + StatusCode: 429, + }, + Namespace: ns, + } + expectLimitReq := http.MakeRequest(t, &expectLimitResp, gwAddr, "HTTP", "http") + + // Keep sending requests till get 200 first, that will cost 10 usage. + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, expectOkResp) + + // The next two request will be fine as the limit is set to 21. + if err := GotExactExpectedResponse(t, 2, suite.RoundTripper, expectOkReq, expectOkResp); err != nil { + t.Errorf("failed to get expected response for the first three requests: %v", err) + } + // At this point, the budget must be zero (21 -> 11 -> 1 -> 0), so the next request will be limited. + if err := GotExactExpectedResponse(t, 1, suite.RoundTripper, expectLimitReq, expectLimitResp); err != nil { + t.Errorf("failed to get expected response for the last (fourth) request: %v", err) + } + }, +} + func GotExactExpectedResponse(t *testing.T, n int, r roundtripper.RoundTripper, req roundtripper.Request, resp http.ExpectedResponse) error { for i := 0; i < n; i++ { cReq, cRes, err := r.CaptureRoundTrip(req) diff --git a/test/e2e/tests/tcp_route.go b/test/e2e/tests/tcproute.go similarity index 99% rename from test/e2e/tests/tcp_route.go rename to test/e2e/tests/tcproute.go index 5526327a68e..1902fb956e6 100644 --- a/test/e2e/tests/tcp_route.go +++ b/test/e2e/tests/tcproute.go @@ -38,7 +38,7 @@ func init() { var TCPRouteTest = suite.ConformanceTest{ ShortName: "TCPRoute", Description: "Testing TCP Route", - Manifests: []string{"testdata/tcp-route.yaml"}, + Manifests: []string{"testdata/tcproute.yaml"}, Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { t.Run("tcp-route-1", func(t *testing.T) { ns := "gateway-conformance-infra" diff --git a/test/e2e/tests/tcproute_with_backend.go b/test/e2e/tests/tcproute_with_backend.go new file mode 100644 index 00000000000..e78afe26d17 --- /dev/null +++ b/test/e2e/tests/tcproute_with_backend.go @@ -0,0 +1,85 @@ +// Copyright Envoy Gateway Authors +// SPDX-License-Identifier: Apache-2.0 +// The full text of the Apache license is available in the LICENSE file at +// the root of the repo. + +// This file contains code derived from upstream gateway-api, it will be moved to upstream. + +//go:build e2e + +package tests + +import ( + "testing" + + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/suite" +) + +func init() { + ConformanceTests = append(ConformanceTests, TCPRouteBackendFQDNTest) + ConformanceTests = append(ConformanceTests, TCPRouteBackendIPTest) +} + +var TCPRouteBackendFQDNTest = suite.ConformanceTest{ + ShortName: "TCPRouteBackendFQDNTest", + Description: "TCPRoutes with a backend ref to a FQDN Backend", + Manifests: []string{"testdata/tcproute-to-backend-fqdn.yaml"}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + t.Run("tcp-route-1", func(t *testing.T) { + testTCPRouteWithBackend(t, suite, "backend-fqdn") + }) + }, +} + +var TCPRouteBackendIPTest = suite.ConformanceTest{ + ShortName: "TCPRouteBackendIPTest", + Description: "TCPRoutes with a backend ref to an IP Backend", + Manifests: []string{"testdata/tcproute-to-backend-ip.yaml"}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + t.Run("tcp-route-1", func(t *testing.T) { + svcNN := types.NamespacedName{ + Name: "infra-backend-v1", + Namespace: "gateway-conformance-infra", + } + svc, err := GetService(suite.Client, svcNN) + if err != nil { + t.Fatalf("failed to get service %s: %v", svcNN, err) + } + + backendIPName := "backend-ip" + ns := "gateway-conformance-infra" + err = CreateBackend(suite.Client, types.NamespacedName{Name: backendIPName, Namespace: ns}, svc.Spec.ClusterIP, 8080) + if err != nil { + t.Fatalf("failed to create backend %s: %v", backendIPName, err) + } + t.Cleanup(func() { + if err := DeleteBackend(suite.Client, types.NamespacedName{Name: backendIPName, Namespace: ns}); err != nil { + t.Fatalf("failed to delete backend %s: %v", backendIPName, err) + } + }) + testTCPRouteWithBackend(t, suite, backendIPName) + }) + }, +} + +func testTCPRouteWithBackend(t *testing.T, suite *suite.ConformanceTestSuite, backendName string) { + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "tcp-app-1", Namespace: ns} + gwNN := types.NamespacedName{Name: "my-tcp-gateway", Namespace: ns} + gwAddr := GatewayAndTCPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, NewGatewayRef(gwNN), routeNN) + BackendMustBeAccepted(t, suite.Client, types.NamespacedName{Name: backendName, Namespace: ns}) + OkResp := http.ExpectedResponse{ + Request: http.Request{ + Path: "/", + }, + Response: http.Response{ + StatusCode: 200, + }, + Namespace: ns, + } + + // Send a request to an valid path and expect a successful response + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, OkResp) +} diff --git a/test/e2e/tests/udproute.go b/test/e2e/tests/udproute.go index 30211de759e..b2f3810582d 100644 --- a/test/e2e/tests/udproute.go +++ b/test/e2e/tests/udproute.go @@ -40,7 +40,7 @@ var UDPRouteTest = suite.ConformanceTest{ Manifests: []string{"testdata/udproute.yaml"}, Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { t.Run("Simple UDP request matching UDPRoute should reach coredns backend", func(t *testing.T) { - namespace := "gateway-conformance-udp" + namespace := "gateway-conformance-infra" domain := "foo.bar.com." routeNN := types.NamespacedName{Name: "udp-coredns", Namespace: namespace} gwNN := types.NamespacedName{Name: "udp-gateway", Namespace: namespace} diff --git a/test/e2e/tests/udproute_with_backend.go b/test/e2e/tests/udproute_with_backend.go new file mode 100644 index 00000000000..c7ccbbeb002 --- /dev/null +++ b/test/e2e/tests/udproute_with_backend.go @@ -0,0 +1,100 @@ +// Copyright Envoy Gateway Authors +// SPDX-License-Identifier: Apache-2.0 +// The full text of the Apache license is available in the LICENSE file at +// the root of the repo. + +// This file contains code derived from upstream gateway-api, it will be moved to upstream. + +//go:build e2e + +package tests + +import ( + "context" + "testing" + "time" + + "github.com/miekg/dns" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/conformance/utils/tlog" +) + +func init() { + ConformanceTests = append(ConformanceTests, UDPRouteBackendFQDNTest) + ConformanceTests = append(ConformanceTests, UDPRouteBackendIPTest) +} + +var UDPRouteBackendFQDNTest = suite.ConformanceTest{ + ShortName: "UDPRouteBackendFQDNTest", + Description: "UDPRoutes with a backend ref to a FQDN Backend", + Manifests: []string{ + "testdata/udproute-to-backend-fqdn.yaml", + }, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + t.Run("UDPRoute with a FQDN type Backend", func(t *testing.T) { + testUDPRouteWithBackend(t, suite, "backend-fqdn") + }) + }, +} + +var UDPRouteBackendIPTest = suite.ConformanceTest{ + ShortName: "UDPRouteBackendIP", + Description: "UDPRoutes with a backend ref to an IP Backend", + Manifests: []string{ + "testdata/udproute-to-backend-ip.yaml", + }, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + t.Run("UDPRoute with a IP type Backend", func(t *testing.T) { + svcNN := types.NamespacedName{ + Name: "coredns", + Namespace: "gateway-conformance-infra", + } + svc, err := GetService(suite.Client, svcNN) + if err != nil { + t.Fatalf("failed to get service %s: %v", svcNN, err) + } + + backendIPName := "backend-ip" + ns := "gateway-conformance-infra" + err = CreateBackend(suite.Client, types.NamespacedName{Name: backendIPName, Namespace: ns}, svc.Spec.ClusterIP, 53) + if err != nil { + t.Fatalf("failed to create backend %s: %v", backendIPName, err) + } + t.Cleanup(func() { + if err := DeleteBackend(suite.Client, types.NamespacedName{Name: backendIPName, Namespace: ns}); err != nil { + t.Fatalf("failed to delete backend %s: %v", backendIPName, err) + } + }) + testUDPRouteWithBackend(t, suite, backendIPName) + }) + }, +} + +func testUDPRouteWithBackend(t *testing.T, suite *suite.ConformanceTestSuite, backend string) { + namespace := "gateway-conformance-infra" + domain := "foo.bar.com." + routeNN := types.NamespacedName{Name: "udp-coredns", Namespace: namespace} + gwNN := types.NamespacedName{Name: "udp-gateway", Namespace: namespace} + gwAddr := GatewayAndUDPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, NewGatewayRef(gwNN), routeNN) + + BackendMustBeAccepted(t, suite.Client, types.NamespacedName{Name: backend, Namespace: namespace}) + + msg := new(dns.Msg) + msg.SetQuestion(domain, dns.TypeA) + + if err := wait.PollUntilContextTimeout(context.TODO(), time.Second, time.Minute, true, + func(_ context.Context) (done bool, err error) { + tlog.Logf(t, "performing DNS query %s on %s", domain, gwAddr) + r, err := dns.Exchange(msg, gwAddr) + if err != nil { + tlog.Logf(t, "failed to perform a UDP query: %v", err) + return false, nil + } + tlog.Logf(t, "got DNS response: %s", r.String()) + return true, nil + }); err != nil { + t.Errorf("failed to perform DNS query: %v", err) + } +} diff --git a/tools/src/buf/go.mod b/tools/src/buf/go.mod index c813a5f7d2e..fa8c49a1524 100644 --- a/tools/src/buf/go.mod +++ b/tools/src/buf/go.mod @@ -2,27 +2,27 @@ module local go 1.23.3 -require github.com/bufbuild/buf v1.48.0 +require github.com/bufbuild/buf v1.49.0 require ( - buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.0-20241031151143-70f632351282.1 // indirect - buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.0-20241127180247-a33202765966.1 // indirect - buf.build/gen/go/bufbuild/registry/connectrpc/go v1.17.0-20241210175624-28487aef65cd.1 // indirect - buf.build/gen/go/bufbuild/registry/protocolbuffers/go v1.36.0-20241210175624-28487aef65cd.1 // indirect - buf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.0-20241007202033-cf42259fcbfc.1 // indirect + buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.1-20241031151143-70f632351282.1 // indirect + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.1-20241127180247-a33202765966.1 // indirect + buf.build/gen/go/bufbuild/registry/connectrpc/go v1.17.0-20241227185654-946b6dd39b27.1 // indirect + buf.build/gen/go/bufbuild/registry/protocolbuffers/go v1.36.1-20241227185654-946b6dd39b27.1 // indirect + buf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.1-20241007202033-cf42259fcbfc.1 // indirect buf.build/go/bufplugin v0.6.0 // indirect buf.build/go/protoyaml v0.3.1 // indirect buf.build/go/spdx v0.2.0 // indirect cel.dev/expr v0.19.1 // indirect connectrpc.com/connect v1.17.0 // indirect connectrpc.com/otelconnect v0.7.1 // indirect - github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Microsoft/hcsshim v0.12.9 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/bufbuild/protocompile v0.14.1 // indirect github.com/bufbuild/protoplugin v0.0.0-20240911180120-7bb73e41a54a // indirect - github.com/bufbuild/protovalidate-go v0.8.0 // indirect + github.com/bufbuild/protovalidate-go v0.8.2 // indirect github.com/containerd/cgroups/v3 v3.0.5 // indirect github.com/containerd/containerd v1.7.24 // indirect github.com/containerd/continuity v0.4.5 // indirect @@ -31,7 +31,7 @@ require ( github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v0.2.1 // indirect github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect - github.com/containerd/ttrpc v1.2.6 // indirect + github.com/containerd/ttrpc v1.2.7 // indirect github.com/containerd/typeurl/v2 v2.2.3 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect github.com/distribution/reference v0.6.0 // indirect @@ -69,9 +69,9 @@ require ( github.com/moby/sys/sequential v0.6.0 // indirect github.com/moby/sys/user v0.3.0 // indirect github.com/moby/sys/userns v0.1.0 // indirect - github.com/moby/term v0.5.0 // indirect + github.com/moby/term v0.5.2 // indirect github.com/morikuni/aec v1.0.0 // indirect - github.com/onsi/ginkgo/v2 v2.22.0 // indirect + github.com/onsi/ginkgo/v2 v2.22.2 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/opencontainers/runtime-spec v1.2.0 // indirect @@ -106,7 +106,7 @@ require ( go.uber.org/zap v1.27.0 // indirect go.uber.org/zap/exp v0.3.0 // indirect golang.org/x/crypto v0.32.0 // indirect - golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect + golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 // indirect golang.org/x/mod v0.22.0 // indirect golang.org/x/net v0.34.0 // indirect golang.org/x/sync v0.10.0 // indirect @@ -114,10 +114,10 @@ require ( golang.org/x/term v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/tools v0.28.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect google.golang.org/grpc v1.69.2 // indirect - google.golang.org/protobuf v1.36.0 // indirect + google.golang.org/protobuf v1.36.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect pluginrpc.com/pluginrpc v0.5.0 // indirect ) diff --git a/tools/src/buf/go.sum b/tools/src/buf/go.sum index 7f957b8c8be..701915f9f7e 100644 --- a/tools/src/buf/go.sum +++ b/tools/src/buf/go.sum @@ -1,13 +1,13 @@ -buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.0-20241031151143-70f632351282.1 h1:FXEFgDFrBYuXjn3twNRo/t80qSbdKmkfZSgR2JGTuyk= -buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.0-20241031151143-70f632351282.1/go.mod h1:/bPD5uslGsdRKBeVavIK7D7yr+3ISI0OoyUOkokSJTA= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.0-20241127180247-a33202765966.1 h1:ntAj16eF7AtUyzOOAFk5gvbAO52QmUKPKk7GmsIEORo= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.0-20241127180247-a33202765966.1/go.mod h1:AxRT+qTj5PJCz2nyQzsR/qxAcveW5USRhJTt/edTO5w= -buf.build/gen/go/bufbuild/registry/connectrpc/go v1.17.0-20241210175624-28487aef65cd.1 h1:x8cCitPNXODGzWbfApZMFc4ALtRe5LZJmTdAkNqk62A= -buf.build/gen/go/bufbuild/registry/connectrpc/go v1.17.0-20241210175624-28487aef65cd.1/go.mod h1:kDOQd1sZ0wRp33hvCTQeaz9KprnHNfJ+a8dcIQ/6+0k= -buf.build/gen/go/bufbuild/registry/protocolbuffers/go v1.36.0-20241210175624-28487aef65cd.1 h1:NOuNS+nCp3xc4CALIC7sNz7irT63UMcYAfofrxurUfE= -buf.build/gen/go/bufbuild/registry/protocolbuffers/go v1.36.0-20241210175624-28487aef65cd.1/go.mod h1:NeX3YCZgM9E/wNp9e3g/9u5bu8/OPntr7K0ygUlgrDE= -buf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.0-20241007202033-cf42259fcbfc.1 h1:HuK77NuzllXrJNgB+lAtnG2dKrB7WAjd9QQ+n0zTQHc= -buf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.0-20241007202033-cf42259fcbfc.1/go.mod h1:BLQCnWbu3tZcKQfbU1f5ysbRk55FDFwOvjlyzN+uLXg= +buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.1-20241031151143-70f632351282.1 h1:DELauram5j4snPU5wB0/I7EIQiy7oRjngqbitbj4o6c= +buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.1-20241031151143-70f632351282.1/go.mod h1:VfQZo/3dl9O9Yg1nseI0gNGDXvLrNQfBRMMIhV9fyII= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.1-20241127180247-a33202765966.1 h1:v223wh/bhlSHSc0tU9PXRWXHhkw3UWMtth7TmYGfHAQ= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.1-20241127180247-a33202765966.1/go.mod h1:/zlFuuECgFgewxwW6qQKgvMJ07YZkWlVkcSxEhJprJw= +buf.build/gen/go/bufbuild/registry/connectrpc/go v1.17.0-20241227185654-946b6dd39b27.1 h1:410axzwOITvAHu1w8pN9Gwhmk1QxrWneq6I/gowLfH8= +buf.build/gen/go/bufbuild/registry/connectrpc/go v1.17.0-20241227185654-946b6dd39b27.1/go.mod h1:i4UUrB1UIqScCCj4d+OFXpUREDDz+p1gCl9WfjpYweY= +buf.build/gen/go/bufbuild/registry/protocolbuffers/go v1.36.1-20241227185654-946b6dd39b27.1 h1:5vU2X68XNaJtF/NGS9shI/0X0jze8/5XH4RmHbsZg5w= +buf.build/gen/go/bufbuild/registry/protocolbuffers/go v1.36.1-20241227185654-946b6dd39b27.1/go.mod h1:DgqZjUk2avpwh8jiMHBOoVXUyceQ3HxNwcRLEWWwNtQ= +buf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.1-20241007202033-cf42259fcbfc.1 h1:0Pi0EQh6z2zJigi4UonoqczBQjvOzZ0CFYUfwPRM41M= +buf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.1-20241007202033-cf42259fcbfc.1/go.mod h1:Uy8SKofLXIAUjswDmz6AIN8W+bGVTF4kNczZikMPHLM= buf.build/go/bufplugin v0.6.0 h1:3lhoh+0z+IUPS3ZajTPn/27LaLIkero2BDVnV7yXD1s= buf.build/go/bufplugin v0.6.0/go.mod h1:hWCjxxv24xdR6F5pNlQavZV2oo0J3uF4Ff1XEoyV6vU= buf.build/go/protoyaml v0.3.1 h1:ucyzE7DRnjX+mQ6AH4JzN0Kg50ByHHu+yrSKbgQn2D4= @@ -23,8 +23,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= @@ -32,14 +32,14 @@ github.com/Microsoft/hcsshim v0.12.9 h1:2zJy5KA+l0loz1HzEGqyNnjd3fyZA31ZBCGKacp6 github.com/Microsoft/hcsshim v0.12.9/go.mod h1:fJ0gkFAna6ukt0bLdKB8djt4XIJhF/vEPuoIWYVvZ8Y= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= -github.com/bufbuild/buf v1.48.0 h1:JiA1Ynz6DE/MBDcEsFvWNoaPhnjaSdLzKH00/5SWomg= -github.com/bufbuild/buf v1.48.0/go.mod h1:lHjK93s3FLn6GOec0f2uqFeREhfL0Qw5dvZ3eipclD8= +github.com/bufbuild/buf v1.49.0 h1:KFSyea50xgvfnqGfK7Z4UCPTYhoCoUYAK2IoRd8/oUA= +github.com/bufbuild/buf v1.49.0/go.mod h1:PssF/YByu7WU6K3FxRmoRxi4ZViugL7rjAaoVvxknso= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= github.com/bufbuild/protoplugin v0.0.0-20240911180120-7bb73e41a54a h1:l3RhVoG0RtC61h6TVWnkniGj4TgBebuyPQRdleFAmTg= github.com/bufbuild/protoplugin v0.0.0-20240911180120-7bb73e41a54a/go.mod h1:c5D8gWRIZ2HLWO3gXYTtUfw/hbJyD8xikv2ooPxnklQ= -github.com/bufbuild/protovalidate-go v0.8.0 h1:Xs3kCLCJ4tQiogJ0iOXm+ClKw/KviW3nLAryCGW2I3Y= -github.com/bufbuild/protovalidate-go v0.8.0/go.mod h1:JPWZInGm2y2NBg3vKDKdDIkvDjyLv31J3hLH5GIFc/Q= +github.com/bufbuild/protovalidate-go v0.8.2 h1:sgzXHkHYP6HnAsL2Rd3I1JxkYUyEQUv9awU1PduMxbM= +github.com/bufbuild/protovalidate-go v0.8.2/go.mod h1:K6w8iPNAXBoIivVueSELbUeUl+MmeTQfCDSug85pn3M= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -70,8 +70,8 @@ github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpS github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= github.com/containerd/stargz-snapshotter/estargz v0.16.3 h1:7evrXtoh1mSbGj/pfRccTampEyKpjpOnS3CyiV1Ebr8= github.com/containerd/stargz-snapshotter/estargz v0.16.3/go.mod h1:uyr4BfYfOj3G9WBVE8cOlQmXAbPN9VEQpBBeJIuOipU= -github.com/containerd/ttrpc v1.2.6 h1:zG+Kn5EZ6MUYCS1t2Hmt2J4tMVaLSFEJVOraDQwNPC4= -github.com/containerd/ttrpc v1.2.6/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o= +github.com/containerd/ttrpc v1.2.7 h1:qIrroQvuOL9HQ1X6KHe2ohc7p+HP/0VE6XPU7elJRqQ= +github.com/containerd/ttrpc v1.2.7/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o= github.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++dYSw40= github.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -201,14 +201,14 @@ github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= -github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= -github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= -github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= +github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= +github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= +github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= +github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -312,8 +312,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo= -golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 h1:9kj3STMvgqy3YA4VQXBrN7925ICMxD5wzMRcgA30588= +golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -379,10 +379,10 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb h1:B7GIB7sr443wZ/EAEl7VZjmh1V6qzkt5V+RYcUYtS1U= -google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:E5//3O5ZIG2l71Xnt+P/CYUY8Bxs8E7WMoZ9tlcMbAY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb h1:3oy2tynMOP1QbTC0MsNNAV+Se8M2Bd0A5+x1QHyw+pI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -399,8 +399,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ= -google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=