From 5e706e426007d1adcf35f2d57e630c75571ec3f2 Mon Sep 17 00:00:00 2001 From: Karol Szwaj Date: Mon, 9 Oct 2023 23:25:46 +0200 Subject: [PATCH 01/16] merge gateways support in translator Signed-off-by: Karol Szwaj --- internal/gatewayapi/address.go | 7 +- internal/gatewayapi/helpers.go | 6 + internal/gatewayapi/listener.go | 35 +++-- .../testdata/merge-multiple-gateways.in.yaml | 37 ++++++ .../testdata/merge-multiple-gateways.out.yaml | 117 +++++++++++++++++ .../testdata/multiple-gateways.in.yaml | 29 +++++ .../testdata/multiple-gateways.out.yaml | 123 ++++++++++++++++++ internal/gatewayapi/translator.go | 32 ++++- 8 files changed, 363 insertions(+), 23 deletions(-) create mode 100644 internal/gatewayapi/testdata/merge-multiple-gateways.in.yaml create mode 100644 internal/gatewayapi/testdata/merge-multiple-gateways.out.yaml create mode 100644 internal/gatewayapi/testdata/multiple-gateways.in.yaml create mode 100644 internal/gatewayapi/testdata/multiple-gateways.out.yaml diff --git a/internal/gatewayapi/address.go b/internal/gatewayapi/address.go index 998fbe248db..de9864b1c5a 100644 --- a/internal/gatewayapi/address.go +++ b/internal/gatewayapi/address.go @@ -18,7 +18,12 @@ type AddressesTranslator interface { func (t *Translator) ProcessAddresses(gateways []*GatewayContext, xdsIR XdsIRMap, infraIR InfraIRMap, resources *Resources) { for _, gateway := range gateways { // Infra IR already exist - irKey := irStringKey(gateway.Gateway.Namespace, gateway.Gateway.Name) + var irKey string + if resources.EnvoyProxy != nil && resources.EnvoyProxy.Spec.MergeGateways != nil && *resources.EnvoyProxy.Spec.MergeGateways { + irKey = string(t.GatewayClassName) + } else { + irKey = irStringKey(gateway.Gateway.Namespace, gateway.Gateway.Name) + } gwInfraIR := infraIR[irKey] var ipAddr []string diff --git a/internal/gatewayapi/helpers.go b/internal/gatewayapi/helpers.go index 685373cb8a7..f72d774fa47 100644 --- a/internal/gatewayapi/helpers.go +++ b/internal/gatewayapi/helpers.go @@ -283,6 +283,12 @@ func GatewayOwnerLabels(namespace, name string) map[string]string { } } +// GatewayClassOwnerLabel returns the GatewayCLass Owner label using +// the provided name as the value. +func GatewayClassOwnerLabel(name string) map[string]string { + return map[string]string{OwningGatewayClassLabel: name} +} + // servicePortToContainerPort translates a service port into an ephemeral // container port. func servicePortToContainerPort(servicePort int32) int32 { diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go index bee77dbdd6b..ab573c96406 100644 --- a/internal/gatewayapi/listener.go +++ b/internal/gatewayapi/listener.go @@ -32,26 +32,23 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap // and compute status for each, and add valid ones // to the Xds IR. for _, gateway := range gateways { - // init IR per gateway - irKey := irStringKey(gateway.Gateway.Namespace, gateway.Gateway.Name) - gwXdsIR := &ir.Xds{} - gwInfraIR := ir.NewInfra() - gwInfraIR.Proxy.Name = irKey - gwInfraIR.Proxy.GetProxyMetadata().Labels = GatewayOwnerLabels(gateway.Namespace, gateway.Name) - if resources.EnvoyProxy != nil { - gwInfraIR.Proxy.Config = resources.EnvoyProxy - } - - // save the IR references in the map before the translation starts - xdsIR[irKey] = gwXdsIR - infraIR[irKey] = gwInfraIR - // Infra IR proxy ports must be unique. var foundPorts []*protocolPort + var irKey string + + if resources.EnvoyProxy != nil && resources.EnvoyProxy.Spec.MergeGateways != nil && *resources.EnvoyProxy.Spec.MergeGateways { + irKey = string(t.GatewayClassName) + } else { + irKey = irStringKey(gateway.Gateway.Namespace, gateway.Gateway.Name) + } + + if resources.EnvoyProxy != nil { + infraIR[irKey].Proxy.Config = resources.EnvoyProxy + } - gwXdsIR.AccessLog = processAccessLog(gwInfraIR.Proxy.Config) - gwXdsIR.Tracing = processTracing(gateway.Gateway, gwInfraIR.Proxy.Config) - gwXdsIR.Metrics = processMetrics(gwInfraIR.Proxy.Config) + xdsIR[irKey].AccessLog = processAccessLog(infraIR[irKey].Proxy.Config) + xdsIR[irKey].Tracing = processTracing(gateway.Gateway, infraIR[irKey].Proxy.Config) + xdsIR[irKey].Metrics = processMetrics(infraIR[irKey].Proxy.Config) for _, listener := range gateway.listeners { // Process protocol & supported kinds @@ -119,7 +116,7 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap // see more https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/gwapiv1.Listener. irListener.Hostnames = append(irListener.Hostnames, "*") } - gwXdsIR.HTTP = append(gwXdsIR.HTTP, irListener) + xdsIR[irKey].HTTP = append(xdsIR[irKey].HTTP, irListener) } // Add the listener to the Infra IR. Infra IR ports must have a unique port number per layer-4 protocol @@ -146,7 +143,7 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap ContainerPort: containerPort, } // Only 1 listener is supported. - gwInfraIR.Proxy.Listeners[0].Ports = append(gwInfraIR.Proxy.Listeners[0].Ports, infraPort) + infraIR[irKey].Proxy.Listeners[0].Ports = append(infraIR[irKey].Proxy.Listeners[0].Ports, infraPort) } } } diff --git a/internal/gatewayapi/testdata/merge-multiple-gateways.in.yaml b/internal/gatewayapi/testdata/merge-multiple-gateways.in.yaml new file mode 100644 index 00000000000..ac62159762b --- /dev/null +++ b/internal/gatewayapi/testdata/merge-multiple-gateways.in.yaml @@ -0,0 +1,37 @@ +envoyproxy: + apiVersion: config.gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + namespace: envoy-gateway-system + name: test + spec: + mergeGateways: true +gateways: + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + name: gateway-2 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http-2 + port: 8888 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same diff --git a/internal/gatewayapi/testdata/merge-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-multiple-gateways.out.yaml new file mode 100644 index 00000000000..eaffe23d261 --- /dev/null +++ b/internal/gatewayapi/testdata/merge-multiple-gateways.out.yaml @@ -0,0 +1,117 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same + status: + listeners: + - attachedRoutes: 0 + name: http + 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 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +- apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-2 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http-2 + port: 8888 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same + status: + listeners: + - attachedRoutes: 0 + name: http-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 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +infraIR: + envoy-gateway-class: + proxy: + config: + apiVersion: config.gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + creationTimestamp: null + name: test + namespace: envoy-gateway-system + spec: + mergeGateways: true + listeners: + - address: "" + ports: + - containerPort: 10080 + name: http + protocol: HTTP + servicePort: 80 + - containerPort: 8888 + name: http-2 + protocol: HTTP + servicePort: 8888 + metadata: + labels: + gateway.envoyproxy.io/owning-gatewayclass: envoy-gateway-class + name: envoy-gateway-class +xdsIR: + envoy-gateway-class: + accessLog: + text: + - path: /dev/stdout + http: + - address: 0.0.0.0 + hostnames: + - '*' + isHTTP2: false + name: envoy-gateway/gateway-1/http + port: 10080 + - address: 0.0.0.0 + hostnames: + - '*' + isHTTP2: false + name: envoy-gateway/gateway-2/http-2 + port: 8888 + diff --git a/internal/gatewayapi/testdata/multiple-gateways.in.yaml b/internal/gatewayapi/testdata/multiple-gateways.in.yaml new file mode 100644 index 00000000000..4602b9bfe2f --- /dev/null +++ b/internal/gatewayapi/testdata/multiple-gateways.in.yaml @@ -0,0 +1,29 @@ +gateways: + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + name: gateway-2 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http-2 + port: 8888 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same \ No newline at end of file diff --git a/internal/gatewayapi/testdata/multiple-gateways.out.yaml b/internal/gatewayapi/testdata/multiple-gateways.out.yaml new file mode 100644 index 00000000000..ffc4d9306f7 --- /dev/null +++ b/internal/gatewayapi/testdata/multiple-gateways.out.yaml @@ -0,0 +1,123 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same + status: + listeners: + - attachedRoutes: 0 + name: http + 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 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +- apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-2 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http-2 + port: 8888 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same + status: + listeners: + - attachedRoutes: 0 + name: http-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 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +infraIR: + envoy-gateway/gateway-1: + proxy: + listeners: + - address: "" + ports: + - containerPort: 10080 + name: http + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + name: envoy-gateway/gateway-1 + envoy-gateway/gateway-2: + proxy: + listeners: + - address: "" + ports: + - containerPort: 8888 + name: http-2 + protocol: HTTP + servicePort: 8888 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-2 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + name: envoy-gateway/gateway-2 +xdsIR: + envoy-gateway/gateway-1: + accessLog: + text: + - path: /dev/stdout + http: + - address: 0.0.0.0 + hostnames: + - '*' + isHTTP2: false + name: envoy-gateway/gateway-1/http + port: 10080 + envoy-gateway/gateway-2: + accessLog: + text: + - path: /dev/stdout + http: + - address: 0.0.0.0 + hostnames: + - '*' + isHTTP2: false + name: envoy-gateway/gateway-2/http-2 + port: 8888 \ No newline at end of file diff --git a/internal/gatewayapi/translator.go b/internal/gatewayapi/translator.go index c449321c548..039a9469ce3 100644 --- a/internal/gatewayapi/translator.go +++ b/internal/gatewayapi/translator.go @@ -6,6 +6,7 @@ package gatewayapi import ( + "github.com/envoyproxy/gateway/internal/ir" "k8s.io/apimachinery/pkg/runtime/schema" gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" @@ -31,6 +32,7 @@ const ( // The value should be the namespace of the accepted Envoy Gateway. OwningGatewayNamespaceLabel = "gateway.envoyproxy.io/owning-gateway-namespace" + OwningGatewayClassLabel = "gateway.envoyproxy.io/owning-gatewayclass" // OwningGatewayNameLabel is the owner reference label used for managed infra. // The value should be the name of the accepted Envoy Gateway. OwningGatewayNameLabel = "gateway.envoyproxy.io/owning-gateway-name" @@ -123,12 +125,12 @@ func newTranslateResult(gateways []*GatewayContext, } func (t *Translator) Translate(resources *Resources) *TranslateResult { - xdsIR := make(XdsIRMap) - infraIR := make(InfraIRMap) - // Get Gateways belonging to our GatewayClass. gateways := t.GetRelevantGateways(resources.Gateways) + // Build IR maps. + xdsIR, infraIR := t.InitIRs(gateways, resources) + // Process all Listeners for all relevant Gateways. t.ProcessListeners(gateways, xdsIR, infraIR, resources) @@ -184,3 +186,27 @@ func (t *Translator) GetRelevantGateways(gateways []*gwapiv1.Gateway) []*Gateway return relevant } + +func (t *Translator) InitIRs(gateways []*GatewayContext, resources *Resources) (map[string]*ir.Xds, map[string]*ir.Infra) { + xdsIR := make(XdsIRMap) + infraIR := make(InfraIRMap) + + var irKey string + for _, gateway := range gateways { + gwXdsIR := &ir.Xds{} + gwInfraIR := ir.NewInfra() + if resources.EnvoyProxy != nil && resources.EnvoyProxy.Spec.MergeGateways != nil && *resources.EnvoyProxy.Spec.MergeGateways { + irKey = string(t.GatewayClassName) + gwInfraIR.Proxy.GetProxyMetadata().Labels = GatewayClassOwnerLabel(string(t.GatewayClassName)) + } else { + irKey = irStringKey(gateway.Gateway.Namespace, gateway.Gateway.Name) + gwInfraIR.Proxy.GetProxyMetadata().Labels = GatewayOwnerLabels(gateway.Namespace, gateway.Name) + } + + // save the IR references in the map before the translation starts + xdsIR[irKey] = gwXdsIR + infraIR[irKey] = gwInfraIR + } + + return xdsIR, infraIR +} From dc3395bbdfae2a8d8277f336975f13a606b57f2b Mon Sep 17 00:00:00 2001 From: Karol Szwaj Date: Tue, 10 Oct 2023 14:54:53 +0200 Subject: [PATCH 02/16] linter fix Signed-off-by: Karol Szwaj --- .../testdata/merge-multiple-gateways.in.yaml | 24 +++++++++---------- .../testdata/merge-multiple-gateways.out.yaml | 9 ++++--- .../testdata/multiple-gateways.in.yaml | 24 +++++++++---------- .../testdata/multiple-gateways.out.yaml | 10 ++++---- internal/gatewayapi/translator.go | 2 +- 5 files changed, 34 insertions(+), 35 deletions(-) diff --git a/internal/gatewayapi/testdata/merge-multiple-gateways.in.yaml b/internal/gatewayapi/testdata/merge-multiple-gateways.in.yaml index ac62159762b..dce42c49250 100644 --- a/internal/gatewayapi/testdata/merge-multiple-gateways.in.yaml +++ b/internal/gatewayapi/testdata/merge-multiple-gateways.in.yaml @@ -15,12 +15,12 @@ gateways: spec: gatewayClassName: envoy-gateway-class listeners: - - name: http - port: 80 - protocol: HTTP - allowedRoutes: - namespaces: - from: Same + - name: http + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same - apiVersion: gateway.networking.k8s.io/v1beta1 kind: Gateway metadata: @@ -29,9 +29,9 @@ gateways: spec: gatewayClassName: envoy-gateway-class listeners: - - name: http-2 - port: 8888 - protocol: HTTP - allowedRoutes: - namespaces: - from: Same + - name: http-2 + port: 8888 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same diff --git a/internal/gatewayapi/testdata/merge-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-multiple-gateways.out.yaml index eaffe23d261..2c056e054ed 100644 --- a/internal/gatewayapi/testdata/merge-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-multiple-gateways.out.yaml @@ -48,7 +48,7 @@ gateways: protocol: HTTP allowedRoutes: namespaces: - from: Same + from: Same status: listeners: - attachedRoutes: 0 @@ -63,7 +63,7 @@ gateways: message: Listener has been successfully translated reason: Accepted status: "True" - type: Accepted + type: Accepted supportedKinds: - group: gateway.networking.k8s.io kind: HTTPRoute @@ -80,7 +80,7 @@ infraIR: name: test namespace: envoy-gateway-system spec: - mergeGateways: true + mergeGateways: true listeners: - address: "" ports: @@ -107,11 +107,10 @@ xdsIR: - '*' isHTTP2: false name: envoy-gateway/gateway-1/http - port: 10080 + port: 10080 - address: 0.0.0.0 hostnames: - '*' isHTTP2: false name: envoy-gateway/gateway-2/http-2 port: 8888 - diff --git a/internal/gatewayapi/testdata/multiple-gateways.in.yaml b/internal/gatewayapi/testdata/multiple-gateways.in.yaml index 4602b9bfe2f..b066477dce6 100644 --- a/internal/gatewayapi/testdata/multiple-gateways.in.yaml +++ b/internal/gatewayapi/testdata/multiple-gateways.in.yaml @@ -7,12 +7,12 @@ gateways: spec: gatewayClassName: envoy-gateway-class listeners: - - name: http - port: 80 - protocol: HTTP - allowedRoutes: - namespaces: - from: Same + - name: http + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same - apiVersion: gateway.networking.k8s.io/v1beta1 kind: Gateway metadata: @@ -21,9 +21,9 @@ gateways: spec: gatewayClassName: envoy-gateway-class listeners: - - name: http-2 - port: 8888 - protocol: HTTP - allowedRoutes: - namespaces: - from: Same \ No newline at end of file + - name: http-2 + port: 8888 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same diff --git a/internal/gatewayapi/testdata/multiple-gateways.out.yaml b/internal/gatewayapi/testdata/multiple-gateways.out.yaml index ffc4d9306f7..f8edb3be696 100644 --- a/internal/gatewayapi/testdata/multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/multiple-gateways.out.yaml @@ -48,7 +48,7 @@ gateways: protocol: HTTP allowedRoutes: namespaces: - from: Same + from: Same status: listeners: - attachedRoutes: 0 @@ -63,12 +63,12 @@ gateways: message: Listener has been successfully translated reason: Accepted status: "True" - type: Accepted + type: Accepted supportedKinds: - group: gateway.networking.k8s.io kind: HTTPRoute - group: gateway.networking.k8s.io - kind: GRPCRoute + kind: GRPCRoute infraIR: envoy-gateway/gateway-1: proxy: @@ -97,7 +97,7 @@ infraIR: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-2 gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway - name: envoy-gateway/gateway-2 + name: envoy-gateway/gateway-2 xdsIR: envoy-gateway/gateway-1: accessLog: @@ -120,4 +120,4 @@ xdsIR: - '*' isHTTP2: false name: envoy-gateway/gateway-2/http-2 - port: 8888 \ No newline at end of file + port: 8888 diff --git a/internal/gatewayapi/translator.go b/internal/gatewayapi/translator.go index 039a9469ce3..012cbf312ae 100644 --- a/internal/gatewayapi/translator.go +++ b/internal/gatewayapi/translator.go @@ -6,11 +6,11 @@ package gatewayapi import ( - "github.com/envoyproxy/gateway/internal/ir" "k8s.io/apimachinery/pkg/runtime/schema" gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" + "github.com/envoyproxy/gateway/internal/ir" ) const ( From cb61708b5fb3153e180d9a557e087269472ed74d Mon Sep 17 00:00:00 2001 From: Karol Szwaj Date: Tue, 10 Oct 2023 15:19:37 +0200 Subject: [PATCH 03/16] gen-check Signed-off-by: Karol Szwaj --- .../testdata/merge-multiple-gateways.out.yaml | 23 +++++++++++-------- .../testdata/multiple-gateways.out.yaml | 20 ++++++++-------- internal/gatewayapi/translator.go | 1 + 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/internal/gatewayapi/testdata/merge-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-multiple-gateways.out.yaml index 2c056e054ed..446caa9fd15 100644 --- a/internal/gatewayapi/testdata/merge-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-multiple-gateways.out.yaml @@ -8,16 +8,15 @@ gateways: spec: gatewayClassName: envoy-gateway-class listeners: - - name: http - port: 80 - protocol: HTTP - allowedRoutes: + - allowedRoutes: namespaces: from: Same + name: http + port: 80 + protocol: HTTP status: listeners: - attachedRoutes: 0 - name: http conditions: - lastTransitionTime: null message: Sending translated listener configuration to the data plane @@ -29,6 +28,7 @@ gateways: reason: Accepted status: "True" type: Accepted + name: http supportedKinds: - group: gateway.networking.k8s.io kind: HTTPRoute @@ -43,16 +43,15 @@ gateways: spec: gatewayClassName: envoy-gateway-class listeners: - - name: http-2 - port: 8888 - protocol: HTTP - allowedRoutes: + - allowedRoutes: namespaces: from: Same + name: http-2 + port: 8888 + protocol: HTTP status: listeners: - attachedRoutes: 0 - name: http-2 conditions: - lastTransitionTime: null message: Sending translated listener configuration to the data plane @@ -64,6 +63,7 @@ gateways: reason: Accepted status: "True" type: Accepted + name: http-2 supportedKinds: - group: gateway.networking.k8s.io kind: HTTPRoute @@ -80,7 +80,10 @@ infraIR: name: test namespace: envoy-gateway-system spec: + logging: {} mergeGateways: true + telemetry: {} + status: {} listeners: - address: "" ports: diff --git a/internal/gatewayapi/testdata/multiple-gateways.out.yaml b/internal/gatewayapi/testdata/multiple-gateways.out.yaml index f8edb3be696..5b068902609 100644 --- a/internal/gatewayapi/testdata/multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/multiple-gateways.out.yaml @@ -8,16 +8,15 @@ gateways: spec: gatewayClassName: envoy-gateway-class listeners: - - name: http - port: 80 - protocol: HTTP - allowedRoutes: + - allowedRoutes: namespaces: from: Same + name: http + port: 80 + protocol: HTTP status: listeners: - attachedRoutes: 0 - name: http conditions: - lastTransitionTime: null message: Sending translated listener configuration to the data plane @@ -29,6 +28,7 @@ gateways: reason: Accepted status: "True" type: Accepted + name: http supportedKinds: - group: gateway.networking.k8s.io kind: HTTPRoute @@ -43,16 +43,15 @@ gateways: spec: gatewayClassName: envoy-gateway-class listeners: - - name: http-2 - port: 8888 - protocol: HTTP - allowedRoutes: + - allowedRoutes: namespaces: from: Same + name: http-2 + port: 8888 + protocol: HTTP status: listeners: - attachedRoutes: 0 - name: http-2 conditions: - lastTransitionTime: null message: Sending translated listener configuration to the data plane @@ -64,6 +63,7 @@ gateways: reason: Accepted status: "True" type: Accepted + name: http-2 supportedKinds: - group: gateway.networking.k8s.io kind: HTTPRoute diff --git a/internal/gatewayapi/translator.go b/internal/gatewayapi/translator.go index 012cbf312ae..a5c70bc8ebd 100644 --- a/internal/gatewayapi/translator.go +++ b/internal/gatewayapi/translator.go @@ -203,6 +203,7 @@ func (t *Translator) InitIRs(gateways []*GatewayContext, resources *Resources) ( gwInfraIR.Proxy.GetProxyMetadata().Labels = GatewayOwnerLabels(gateway.Namespace, gateway.Name) } + gwInfraIR.Proxy.Name = irKey // save the IR references in the map before the translation starts xdsIR[irKey] = gwXdsIR infraIR[irKey] = gwInfraIR From bf062c47a8a7b19f2e096c99bc59b068bf4d7bee Mon Sep 17 00:00:00 2001 From: Karol Szwaj Date: Wed, 11 Oct 2023 16:34:32 +0200 Subject: [PATCH 04/16] validate unique merged listeners Signed-off-by: Karol Szwaj --- internal/gatewayapi/address.go | 3 +- internal/gatewayapi/helpers.go | 7 + internal/gatewayapi/listener.go | 16 +- internal/gatewayapi/route.go | 39 +++- ...> merge-invalid-multiple-gateways.in.yaml} | 13 +- ... merge-invalid-multiple-gateways.out.yaml} | 55 +++--- .../merge-valid-multiple-gateways.in.yaml | 54 ++++++ .../merge-valid-multiple-gateways.out.yaml | 166 ++++++++++++++++++ internal/gatewayapi/translator.go | 2 +- internal/gatewayapi/validate.go | 23 +++ 10 files changed, 335 insertions(+), 43 deletions(-) rename internal/gatewayapi/testdata/{merge-multiple-gateways.in.yaml => merge-invalid-multiple-gateways.in.yaml} (78%) rename internal/gatewayapi/testdata/{merge-multiple-gateways.out.yaml => merge-invalid-multiple-gateways.out.yaml} (76%) mode change 100644 => 100755 create mode 100644 internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml create mode 100755 internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml diff --git a/internal/gatewayapi/address.go b/internal/gatewayapi/address.go index de9864b1c5a..dfd28491b34 100644 --- a/internal/gatewayapi/address.go +++ b/internal/gatewayapi/address.go @@ -19,11 +19,12 @@ func (t *Translator) ProcessAddresses(gateways []*GatewayContext, xdsIR XdsIRMap for _, gateway := range gateways { // Infra IR already exist var irKey string - if resources.EnvoyProxy != nil && resources.EnvoyProxy.Spec.MergeGateways != nil && *resources.EnvoyProxy.Spec.MergeGateways { + if isMergeGatewaysEnabled(resources) { irKey = string(t.GatewayClassName) } else { irKey = irStringKey(gateway.Gateway.Namespace, gateway.Gateway.Name) } + gwInfraIR := infraIR[irKey] var ipAddr []string diff --git a/internal/gatewayapi/helpers.go b/internal/gatewayapi/helpers.go index f72d774fa47..2e70de1241f 100644 --- a/internal/gatewayapi/helpers.go +++ b/internal/gatewayapi/helpers.go @@ -406,6 +406,10 @@ func irStringKey(gatewayNs, gatewayName string) string { return fmt.Sprintf("%s/%s", gatewayNs, gatewayName) } +func irInfraPortName(listener *ListenerContext) string { + return fmt.Sprintf("%s/%s/%s", listener.gateway.Namespace, listener.Name, listener.gateway.Name) +} + func irHTTPListenerName(listener *ListenerContext) string { return fmt.Sprintf("%s/%s/%s", listener.gateway.Namespace, listener.gateway.Name, listener.Name) } @@ -449,6 +453,9 @@ func irTLSConfigs(tlsSecrets []*v1.Secret) []*ir.TLSListenerConfig { func irTLSListenerConfigName(secret *v1.Secret) string { return fmt.Sprintf("%s-%s", secret.Namespace, secret.Name) } +func isMergeGatewaysEnabled(resources *Resources) bool { + return resources.EnvoyProxy != nil && resources.EnvoyProxy.Spec.MergeGateways != nil && *resources.EnvoyProxy.Spec.MergeGateways +} func protocolSliceToStringSlice(protocols []gwapiv1.ProtocolType) []string { var protocolStrings []string diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go index ab573c96406..508a64746eb 100644 --- a/internal/gatewayapi/listener.go +++ b/internal/gatewayapi/listener.go @@ -27,6 +27,9 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap t.validateConflictedLayer7Listeners(gateways) t.validateConflictedLayer4Listeners(gateways, gwapiv1.TCPProtocolType, gwapiv1.TLSProtocolType) t.validateConflictedLayer4Listeners(gateways, gwapiv1.UDPProtocolType) + if isMergeGatewaysEnabled(resources) { + t.validateConflictedMergedListeners(gateways) + } // Iterate through all listeners to validate spec // and compute status for each, and add valid ones @@ -36,7 +39,8 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap var foundPorts []*protocolPort var irKey string - if resources.EnvoyProxy != nil && resources.EnvoyProxy.Spec.MergeGateways != nil && *resources.EnvoyProxy.Spec.MergeGateways { + if isMergeGatewaysEnabled(resources) { + t.validateConflictedMergedListeners(gateways) irKey = string(t.GatewayClassName) } else { irKey = irStringKey(gateway.Gateway.Namespace, gateway.Gateway.Name) @@ -136,8 +140,16 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap case gwapiv1.UDPProtocolType: proto = ir.UDPProtocolType } + + var infraPortName string + if isMergeGatewaysEnabled(resources) { + infraPortName = irInfraPortName(listener) + } else { + infraPortName = string(listener.Name) + } + infraPort := ir.ListenerPort{ - Name: string(listener.Name), + Name: infraPortName, Protocol: proto, ServicePort: servicePort.port, ContainerPort: containerPort, diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index 3a019499c72..438cc5bd7db 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -113,7 +113,7 @@ func (t *Translator) processHTTPRouteParentRefs(httpRoute *HTTPRouteContext, res continue } - var hasHostnameIntersection = t.processHTTPRouteParentRefListener(httpRoute, routeRoutes, parentRef, xdsIR) + var hasHostnameIntersection = t.processHTTPRouteParentRefListener(httpRoute, routeRoutes, parentRef, xdsIR, resources) if !hasHostnameIntersection { parentRef.SetCondition(httpRoute, gwapiv1.RouteConditionAccepted, @@ -348,7 +348,7 @@ func (t *Translator) processGRPCRouteParentRefs(grpcRoute *GRPCRouteContext, res if parentRef.HasCondition(grpcRoute, gwapiv1.RouteConditionAccepted, metav1.ConditionFalse) { continue } - var hasHostnameIntersection = t.processHTTPRouteParentRefListener(grpcRoute, routeRoutes, parentRef, xdsIR) + var hasHostnameIntersection = t.processHTTPRouteParentRefListener(grpcRoute, routeRoutes, parentRef, xdsIR, resources) if !hasHostnameIntersection { parentRef.SetCondition(grpcRoute, gwapiv1.RouteConditionAccepted, @@ -512,7 +512,7 @@ func (t *Translator) processGRPCRouteMethodRegularExpression(method *gwapiv1a1.G } } -func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, routeRoutes []*ir.HTTPRoute, parentRef *RouteParentContext, xdsIR XdsIRMap) bool { +func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, routeRoutes []*ir.HTTPRoute, parentRef *RouteParentContext, xdsIR XdsIRMap, resources *Resources) bool { var hasHostnameIntersection bool for _, listener := range parentRef.listeners { @@ -572,8 +572,13 @@ func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, route perHostRoutes = append(perHostRoutes, hostRoute) } } + var irKey string + if isMergeGatewaysEnabled(resources) { + irKey = string(t.GatewayClassName) + } else { + irKey = irStringKey(listener.gateway.Namespace, listener.gateway.Name) + } - irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name) irListener := xdsIR[irKey].GetHTTPListener(irHTTPListenerName(listener)) if irListener != nil { if GetRouteType(route) == KindGRPCRoute { @@ -669,7 +674,13 @@ func (t *Translator) processTLSRouteParentRefs(tlsRoute *TLSRouteContext, resour hasHostnameIntersection = true - irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name) + var irKey string + if isMergeGatewaysEnabled(resources) { + irKey = string(t.GatewayClassName) + } else { + irKey = irStringKey(listener.gateway.Namespace, listener.gateway.Name) + } + containerPort := servicePortToContainerPort(int32(listener.Port)) // Create the TCP Listener while parsing the TLSRoute since // the listener directly links to a routeDestination. @@ -807,7 +818,14 @@ func (t *Translator) processUDPRouteParentRefs(udpRoute *UDPRouteContext, resour continue } accepted = true - irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name) + + var irKey string + if isMergeGatewaysEnabled(resources) { + irKey = string(t.GatewayClassName) + } else { + irKey = irStringKey(listener.gateway.Namespace, listener.gateway.Name) + } + containerPort := servicePortToContainerPort(int32(listener.Port)) // Create the UDP Listener while parsing the UDPRoute since // the listener directly links to a routeDestination. @@ -942,7 +960,14 @@ func (t *Translator) processTCPRouteParentRefs(tcpRoute *TCPRouteContext, resour continue } accepted = true - irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name) + + var irKey string + if isMergeGatewaysEnabled(resources) { + irKey = string(t.GatewayClassName) + } else { + irKey = irStringKey(listener.gateway.Namespace, listener.gateway.Name) + } + containerPort := servicePortToContainerPort(int32(listener.Port)) // Create the TCP Listener while parsing the TCPRoute since // the listener directly links to a routeDestination. diff --git a/internal/gatewayapi/testdata/merge-multiple-gateways.in.yaml b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.in.yaml similarity index 78% rename from internal/gatewayapi/testdata/merge-multiple-gateways.in.yaml rename to internal/gatewayapi/testdata/merge-invalid-multiple-gateways.in.yaml index dce42c49250..b7cb018ca2e 100644 --- a/internal/gatewayapi/testdata/merge-multiple-gateways.in.yaml +++ b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.in.yaml @@ -18,9 +18,6 @@ gateways: - name: http port: 80 protocol: HTTP - allowedRoutes: - namespaces: - from: Same - apiVersion: gateway.networking.k8s.io/v1beta1 kind: Gateway metadata: @@ -29,9 +26,9 @@ gateways: spec: gatewayClassName: envoy-gateway-class listeners: - - name: http-2 - port: 8888 + - name: http + port: 80 protocol: HTTP - allowedRoutes: - namespaces: - from: Same + - name: udp + port: 80 + protocol: UDP diff --git a/internal/gatewayapi/testdata/merge-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml old mode 100644 new mode 100755 similarity index 76% rename from internal/gatewayapi/testdata/merge-multiple-gateways.out.yaml rename to internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml index 446caa9fd15..cece157c4d7 --- a/internal/gatewayapi/testdata/merge-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml @@ -8,10 +8,7 @@ gateways: spec: gatewayClassName: envoy-gateway-class listeners: - - allowedRoutes: - namespaces: - from: Same - name: http + - name: http port: 80 protocol: HTTP status: @@ -43,14 +40,32 @@ gateways: spec: gatewayClassName: envoy-gateway-class listeners: - - allowedRoutes: - namespaces: - from: Same - name: http-2 - port: 8888 + - name: http + port: 80 protocol: HTTP + - name: udp + port: 80 + protocol: UDP status: listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Port, protocol and hostname tuple must be unique for every listener + reason: HostnameConflict + status: "True" + type: Conflicted + - lastTransitionTime: null + message: Listener is invalid, see other Conditions for details. + reason: Invalid + status: "False" + type: Programmed + name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute - attachedRoutes: 0 conditions: - lastTransitionTime: null @@ -63,12 +78,10 @@ gateways: reason: Accepted status: "True" type: Accepted - name: http-2 + name: udp supportedKinds: - group: gateway.networking.k8s.io - kind: HTTPRoute - - group: gateway.networking.k8s.io - kind: GRPCRoute + kind: UDPRoute infraIR: envoy-gateway-class: proxy: @@ -88,13 +101,13 @@ infraIR: - address: "" ports: - containerPort: 10080 - name: http + name: envoy-gateway/http/gateway-1 protocol: HTTP servicePort: 80 - - containerPort: 8888 - name: http-2 - protocol: HTTP - servicePort: 8888 + - containerPort: 10080 + name: envoy-gateway/udp/gateway-2 + protocol: UDP + servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gatewayclass: envoy-gateway-class @@ -111,9 +124,3 @@ xdsIR: isHTTP2: false name: envoy-gateway/gateway-1/http port: 10080 - - address: 0.0.0.0 - hostnames: - - '*' - isHTTP2: false - name: envoy-gateway/gateway-2/http-2 - port: 8888 diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml new file mode 100644 index 00000000000..55b5b552995 --- /dev/null +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml @@ -0,0 +1,54 @@ +envoyproxy: + apiVersion: config.gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + namespace: envoy-gateway-system + name: test + spec: + mergeGateways: true +gateways: + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + name: gateway-2 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http-2 + port: 8888 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same +httpRoutes: + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: HTTPRoute + metadata: + namespace: envoy-gateway + name: httproute-1 + spec: + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + rules: + - matches: + - path: + value: "/" + backendRefs: + - name: service-1 + port: 8080 diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml new file mode 100755 index 00000000000..8dc3552d0c7 --- /dev/null +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml @@ -0,0 +1,166 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: Same + name: http + port: 80 + protocol: HTTP + 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 + name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +- apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-2 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: Same + name: http-2 + port: 8888 + protocol: HTTP + status: + listeners: + - attachedRoutes: 0 + 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 + name: http-2 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1beta1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-1 + namespace: envoy-gateway + spec: + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + value: / + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Service envoy-gateway/service-1 not found + reason: BackendNotFound + status: "False" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway +infraIR: + envoy-gateway-class: + proxy: + config: + apiVersion: config.gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + creationTimestamp: null + name: test + namespace: envoy-gateway-system + spec: + logging: {} + mergeGateways: true + telemetry: {} + status: {} + listeners: + - address: "" + ports: + - containerPort: 10080 + name: envoy-gateway/http/gateway-1 + protocol: HTTP + servicePort: 80 + - containerPort: 8888 + name: envoy-gateway/http-2/gateway-2 + protocol: HTTP + servicePort: 8888 + metadata: + labels: + gateway.envoyproxy.io/owning-gatewayclass: envoy-gateway-class + name: envoy-gateway-class +xdsIR: + envoy-gateway-class: + accessLog: + text: + - path: /dev/stdout + http: + - address: 0.0.0.0 + hostnames: + - '*' + isHTTP2: false + name: envoy-gateway/gateway-1/http + port: 10080 + routes: + - backendWeights: + invalid: 1 + valid: 0 + directResponse: + statusCode: 500 + hostname: '*' + name: httproute/envoy-gateway/httproute-1/rule/0/match/0/* + pathMatch: + distinct: false + name: "" + prefix: / + - address: 0.0.0.0 + hostnames: + - '*' + isHTTP2: false + name: envoy-gateway/gateway-2/http-2 + port: 8888 diff --git a/internal/gatewayapi/translator.go b/internal/gatewayapi/translator.go index a5c70bc8ebd..842de692a7f 100644 --- a/internal/gatewayapi/translator.go +++ b/internal/gatewayapi/translator.go @@ -195,7 +195,7 @@ func (t *Translator) InitIRs(gateways []*GatewayContext, resources *Resources) ( for _, gateway := range gateways { gwXdsIR := &ir.Xds{} gwInfraIR := ir.NewInfra() - if resources.EnvoyProxy != nil && resources.EnvoyProxy.Spec.MergeGateways != nil && *resources.EnvoyProxy.Spec.MergeGateways { + if isMergeGatewaysEnabled(resources) { irKey = string(t.GatewayClassName) gwInfraIR.Proxy.GetProxyMetadata().Labels = GatewayClassOwnerLabel(string(t.GatewayClassName)) } else { diff --git a/internal/gatewayapi/validate.go b/internal/gatewayapi/validate.go index a6d18487e76..16200c2b7b0 100644 --- a/internal/gatewayapi/validate.go +++ b/internal/gatewayapi/validate.go @@ -533,6 +533,29 @@ type portListeners struct { hostnames map[string]int } +func (t *Translator) validateConflictedMergedListeners(gateways []*GatewayContext) { + listenerSets := sets.Set[string]{} + for _, gateway := range gateways { + for _, listener := range gateway.listeners { + var hostname string + if listener.Hostname != nil { + hostname = string(*listener.Hostname) + } + + portProtocolHostname := fmt.Sprintf("%s:%s:%d", listener.Protocol, hostname, listener.Port) + if listenerSets.Has(portProtocolHostname) { + listener.SetCondition( + v1beta1.ListenerConditionConflicted, + metav1.ConditionTrue, + v1beta1.ListenerReasonHostnameConflict, + "Port, protocol and hostname tuple must be unique for every listener", + ) + } + listenerSets.Insert(portProtocolHostname) + } + } +} + func (t *Translator) validateConflictedLayer7Listeners(gateways []*GatewayContext) { // Iterate through all layer-7 (HTTP, HTTPS, TLS) listeners and collect info about protocols // and hostnames per port. From 874844cc5513b0b1c9bbcca522c8b4f489fb5217 Mon Sep 17 00:00:00 2001 From: Karol Szwaj Date: Wed, 11 Oct 2023 17:16:38 +0200 Subject: [PATCH 05/16] Set mergeGateways to Translator receiver Signed-off-by: Karol Szwaj --- internal/gatewayapi/address.go | 6 ++---- internal/gatewayapi/listener.go | 9 +++------ internal/gatewayapi/route.go | 30 +++++++++++------------------- internal/gatewayapi/translator.go | 5 +++++ 4 files changed, 21 insertions(+), 29 deletions(-) diff --git a/internal/gatewayapi/address.go b/internal/gatewayapi/address.go index dfd28491b34..fe28319e505 100644 --- a/internal/gatewayapi/address.go +++ b/internal/gatewayapi/address.go @@ -18,11 +18,9 @@ type AddressesTranslator interface { func (t *Translator) ProcessAddresses(gateways []*GatewayContext, xdsIR XdsIRMap, infraIR InfraIRMap, resources *Resources) { for _, gateway := range gateways { // Infra IR already exist - var irKey string - if isMergeGatewaysEnabled(resources) { + irKey := irStringKey(gateway.Gateway.Namespace, gateway.Gateway.Name) + if t.MergeGateways { irKey = string(t.GatewayClassName) - } else { - irKey = irStringKey(gateway.Gateway.Namespace, gateway.Gateway.Name) } gwInfraIR := infraIR[irKey] diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go index 508a64746eb..7deea73e0d4 100644 --- a/internal/gatewayapi/listener.go +++ b/internal/gatewayapi/listener.go @@ -27,7 +27,7 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap t.validateConflictedLayer7Listeners(gateways) t.validateConflictedLayer4Listeners(gateways, gwapiv1.TCPProtocolType, gwapiv1.TLSProtocolType) t.validateConflictedLayer4Listeners(gateways, gwapiv1.UDPProtocolType) - if isMergeGatewaysEnabled(resources) { + if t.MergeGateways { t.validateConflictedMergedListeners(gateways) } @@ -37,13 +37,10 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap for _, gateway := range gateways { // Infra IR proxy ports must be unique. var foundPorts []*protocolPort - var irKey string - if isMergeGatewaysEnabled(resources) { - t.validateConflictedMergedListeners(gateways) + irKey := irStringKey(gateway.Gateway.Namespace, gateway.Gateway.Name) + if t.MergeGateways { irKey = string(t.GatewayClassName) - } else { - irKey = irStringKey(gateway.Gateway.Namespace, gateway.Gateway.Name) } if resources.EnvoyProxy != nil { diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index 438cc5bd7db..1769495f7fc 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -113,7 +113,7 @@ func (t *Translator) processHTTPRouteParentRefs(httpRoute *HTTPRouteContext, res continue } - var hasHostnameIntersection = t.processHTTPRouteParentRefListener(httpRoute, routeRoutes, parentRef, xdsIR, resources) + var hasHostnameIntersection = t.processHTTPRouteParentRefListener(httpRoute, routeRoutes, parentRef, xdsIR) if !hasHostnameIntersection { parentRef.SetCondition(httpRoute, gwapiv1.RouteConditionAccepted, @@ -348,7 +348,7 @@ func (t *Translator) processGRPCRouteParentRefs(grpcRoute *GRPCRouteContext, res if parentRef.HasCondition(grpcRoute, gwapiv1.RouteConditionAccepted, metav1.ConditionFalse) { continue } - var hasHostnameIntersection = t.processHTTPRouteParentRefListener(grpcRoute, routeRoutes, parentRef, xdsIR, resources) + var hasHostnameIntersection = t.processHTTPRouteParentRefListener(grpcRoute, routeRoutes, parentRef, xdsIR) if !hasHostnameIntersection { parentRef.SetCondition(grpcRoute, gwapiv1.RouteConditionAccepted, @@ -512,7 +512,7 @@ func (t *Translator) processGRPCRouteMethodRegularExpression(method *gwapiv1a1.G } } -func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, routeRoutes []*ir.HTTPRoute, parentRef *RouteParentContext, xdsIR XdsIRMap, resources *Resources) bool { +func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, routeRoutes []*ir.HTTPRoute, parentRef *RouteParentContext, xdsIR XdsIRMap) bool { var hasHostnameIntersection bool for _, listener := range parentRef.listeners { @@ -572,11 +572,9 @@ func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, route perHostRoutes = append(perHostRoutes, hostRoute) } } - var irKey string - if isMergeGatewaysEnabled(resources) { + irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name) + if t.MergeGateways { irKey = string(t.GatewayClassName) - } else { - irKey = irStringKey(listener.gateway.Namespace, listener.gateway.Name) } irListener := xdsIR[irKey].GetHTTPListener(irHTTPListenerName(listener)) @@ -674,11 +672,9 @@ func (t *Translator) processTLSRouteParentRefs(tlsRoute *TLSRouteContext, resour hasHostnameIntersection = true - var irKey string - if isMergeGatewaysEnabled(resources) { + irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name) + if t.MergeGateways { irKey = string(t.GatewayClassName) - } else { - irKey = irStringKey(listener.gateway.Namespace, listener.gateway.Name) } containerPort := servicePortToContainerPort(int32(listener.Port)) @@ -819,11 +815,9 @@ func (t *Translator) processUDPRouteParentRefs(udpRoute *UDPRouteContext, resour } accepted = true - var irKey string - if isMergeGatewaysEnabled(resources) { + irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name) + if t.MergeGateways { irKey = string(t.GatewayClassName) - } else { - irKey = irStringKey(listener.gateway.Namespace, listener.gateway.Name) } containerPort := servicePortToContainerPort(int32(listener.Port)) @@ -961,11 +955,9 @@ func (t *Translator) processTCPRouteParentRefs(tcpRoute *TCPRouteContext, resour } accepted = true - var irKey string - if isMergeGatewaysEnabled(resources) { + irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name) + if t.MergeGateways { irKey = string(t.GatewayClassName) - } else { - irKey = irStringKey(listener.gateway.Namespace, listener.gateway.Name) } containerPort := servicePortToContainerPort(int32(listener.Port)) diff --git a/internal/gatewayapi/translator.go b/internal/gatewayapi/translator.go index 842de692a7f..4616101a843 100644 --- a/internal/gatewayapi/translator.go +++ b/internal/gatewayapi/translator.go @@ -75,6 +75,10 @@ type Translator struct { // instead. EndpointRoutingDisabled bool + // MergeGateways is true when all Gateway Listeners + // should be merged under the parent GatewayClass. + MergeGateways bool + // ExtensionGroupKinds stores the group/kind for all resources // introduced by an Extension so that the translator can // store referenced resources in the IR for later use. @@ -196,6 +200,7 @@ func (t *Translator) InitIRs(gateways []*GatewayContext, resources *Resources) ( gwXdsIR := &ir.Xds{} gwInfraIR := ir.NewInfra() if isMergeGatewaysEnabled(resources) { + t.MergeGateways = true irKey = string(t.GatewayClassName) gwInfraIR.Proxy.GetProxyMetadata().Labels = GatewayClassOwnerLabel(string(t.GatewayClassName)) } else { From 4bbb54419f9bc67d9209618a548d2286d1621598 Mon Sep 17 00:00:00 2001 From: Karol Szwaj Date: Wed, 11 Oct 2023 17:20:23 +0200 Subject: [PATCH 06/16] add infraport name Signed-off-by: Karol Szwaj --- internal/gatewayapi/listener.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go index 7deea73e0d4..18e690a1164 100644 --- a/internal/gatewayapi/listener.go +++ b/internal/gatewayapi/listener.go @@ -138,11 +138,9 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap proto = ir.UDPProtocolType } - var infraPortName string - if isMergeGatewaysEnabled(resources) { + infraPortName := string(listener.Name) + if t.MergeGateways { infraPortName = irInfraPortName(listener) - } else { - infraPortName = string(listener.Name) } infraPort := ir.ListenerPort{ From 4f7537d2a2d717f10ea364e59738761072207bdc Mon Sep 17 00:00:00 2001 From: Karol Szwaj Date: Wed, 11 Oct 2023 18:30:39 +0200 Subject: [PATCH 07/16] use gateway.envoyproxy.io group Signed-off-by: Karol Szwaj --- .../gatewayapi/testdata/merge-invalid-multiple-gateways.in.yaml | 2 +- .../testdata/merge-invalid-multiple-gateways.out.yaml | 2 +- .../gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml | 2 +- .../gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.in.yaml b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.in.yaml index b7cb018ca2e..a109f785281 100644 --- a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.in.yaml +++ b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.in.yaml @@ -1,5 +1,5 @@ envoyproxy: - apiVersion: config.gateway.envoyproxy.io/v1alpha1 + apiVersion: gateway.envoyproxy.io/v1alpha1 kind: EnvoyProxy metadata: namespace: envoy-gateway-system diff --git a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml index cece157c4d7..a5ae0b5798a 100755 --- a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml @@ -86,7 +86,7 @@ infraIR: envoy-gateway-class: proxy: config: - apiVersion: config.gateway.envoyproxy.io/v1alpha1 + apiVersion: gateway.envoyproxy.io/v1alpha1 kind: EnvoyProxy metadata: creationTimestamp: null diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml index 55b5b552995..2d391861bae 100644 --- a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml @@ -1,5 +1,5 @@ envoyproxy: - apiVersion: config.gateway.envoyproxy.io/v1alpha1 + apiVersion: gateway.envoyproxy.io/v1alpha1 kind: EnvoyProxy metadata: namespace: envoy-gateway-system diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml index 8dc3552d0c7..3446cd15815 100755 --- a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml @@ -108,7 +108,7 @@ infraIR: envoy-gateway-class: proxy: config: - apiVersion: config.gateway.envoyproxy.io/v1alpha1 + apiVersion: gateway.envoyproxy.io/v1alpha1 kind: EnvoyProxy metadata: creationTimestamp: null From b0b06e04ae73b17f6875e783314f427642c46f81 Mon Sep 17 00:00:00 2001 From: Karol Szwaj Date: Wed, 11 Oct 2023 22:50:15 +0200 Subject: [PATCH 08/16] adjust envoy deployments Signed-off-by: Karol Szwaj --- internal/gatewayapi/helpers.go | 4 +- internal/gatewayapi/listener.go | 2 +- .../merge-invalid-multiple-gateways.out.yaml | 4 +- .../merge-valid-multiple-gateways.in.yaml | 17 ------ .../merge-valid-multiple-gateways.out.yaml | 53 ++----------------- .../kubernetes/proxy/resource.go | 14 ++++- .../kubernetes/proxy/resource_provider.go | 8 +-- internal/provider/utils/utils.go | 12 +++-- 8 files changed, 32 insertions(+), 82 deletions(-) diff --git a/internal/gatewayapi/helpers.go b/internal/gatewayapi/helpers.go index 2e70de1241f..218ce032126 100644 --- a/internal/gatewayapi/helpers.go +++ b/internal/gatewayapi/helpers.go @@ -406,8 +406,8 @@ func irStringKey(gatewayNs, gatewayName string) string { return fmt.Sprintf("%s/%s", gatewayNs, gatewayName) } -func irInfraPortName(listener *ListenerContext) string { - return fmt.Sprintf("%s/%s/%s", listener.gateway.Namespace, listener.Name, listener.gateway.Name) +func irMergedInfraPortName(listener *ListenerContext) string { + return fmt.Sprintf("%s-%s-%s", listener.Name, listener.gateway.Namespace, listener.gateway.Name) } func irHTTPListenerName(listener *ListenerContext) string { diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go index 18e690a1164..938fb10313a 100644 --- a/internal/gatewayapi/listener.go +++ b/internal/gatewayapi/listener.go @@ -140,7 +140,7 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap infraPortName := string(listener.Name) if t.MergeGateways { - infraPortName = irInfraPortName(listener) + infraPortName = irMergedInfraPortName(listener) } infraPort := ir.ListenerPort{ diff --git a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml index a5ae0b5798a..67f52c83c43 100755 --- a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml @@ -101,11 +101,11 @@ infraIR: - address: "" ports: - containerPort: 10080 - name: envoy-gateway/http/gateway-1 + name: http-envoy-gateway-gateway-1 protocol: HTTP servicePort: 80 - containerPort: 10080 - name: envoy-gateway/udp/gateway-2 + name: udp-envoy-gateway-gateway-2 protocol: UDP servicePort: 80 metadata: diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml index 2d391861bae..fb98a3fa81f 100644 --- a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml @@ -35,20 +35,3 @@ gateways: allowedRoutes: namespaces: from: Same -httpRoutes: - - apiVersion: gateway.networking.k8s.io/v1beta1 - kind: HTTPRoute - metadata: - namespace: envoy-gateway - name: httproute-1 - spec: - parentRefs: - - namespace: envoy-gateway - name: gateway-1 - rules: - - matches: - - path: - value: "/" - backendRefs: - - name: service-1 - port: 8080 diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml index 3446cd15815..9f68963a4fb 100755 --- a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml @@ -16,7 +16,7 @@ gateways: protocol: HTTP status: listeners: - - attachedRoutes: 1 + - attachedRoutes: 0 conditions: - lastTransitionTime: null message: Sending translated listener configuration to the data plane @@ -69,41 +69,6 @@ gateways: kind: HTTPRoute - group: gateway.networking.k8s.io kind: GRPCRoute -httpRoutes: -- apiVersion: gateway.networking.k8s.io/v1beta1 - kind: HTTPRoute - metadata: - creationTimestamp: null - name: httproute-1 - namespace: envoy-gateway - spec: - parentRefs: - - name: gateway-1 - namespace: envoy-gateway - rules: - - backendRefs: - - name: service-1 - port: 8080 - matches: - - path: - value: / - status: - parents: - - conditions: - - lastTransitionTime: null - message: Route is accepted - reason: Accepted - status: "True" - type: Accepted - - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found - reason: BackendNotFound - status: "False" - type: ResolvedRefs - controllerName: gateway.envoyproxy.io/gatewayclass-controller - parentRef: - name: gateway-1 - namespace: envoy-gateway infraIR: envoy-gateway-class: proxy: @@ -123,11 +88,11 @@ infraIR: - address: "" ports: - containerPort: 10080 - name: envoy-gateway/http/gateway-1 + name: http-envoy-gateway-gateway-1 protocol: HTTP servicePort: 80 - containerPort: 8888 - name: envoy-gateway/http-2/gateway-2 + name: http-2-envoy-gateway-gateway-2 protocol: HTTP servicePort: 8888 metadata: @@ -146,18 +111,6 @@ xdsIR: isHTTP2: false name: envoy-gateway/gateway-1/http port: 10080 - routes: - - backendWeights: - invalid: 1 - valid: 0 - directResponse: - statusCode: 500 - hostname: '*' - name: httproute/envoy-gateway/httproute-1/rule/0/match/0/* - pathMatch: - distinct: false - name: "" - prefix: / - address: 0.0.0.0 hostnames: - '*' diff --git a/internal/infrastructure/kubernetes/proxy/resource.go b/internal/infrastructure/kubernetes/proxy/resource.go index 6f9b451432c..454b4dde29e 100644 --- a/internal/infrastructure/kubernetes/proxy/resource.go +++ b/internal/infrastructure/kubernetes/proxy/resource.go @@ -7,6 +7,7 @@ package proxy import ( "fmt" + "strings" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -56,6 +57,17 @@ func ExpectedResourceHashedName(name string) string { return fmt.Sprintf("%s-%s", config.EnvoyPrefix, hashedName) } +// ExpectedServiceHashedName returns expected service name with max length of 15 characters. +func ExpectedServiceHashedName(name string) string { + if len(name) > 15 { + hashedName := providerutils.HashString(name) + listenerName := strings.Split(name, "-") + + return fmt.Sprintf("%s-%s", listenerName[0], hashedName[0:14-len(listenerName)]) + } + return name +} + // EnvoyAppLabel returns the labels used for all Envoy resources. func EnvoyAppLabel() map[string]string { return map[string]string{ @@ -102,7 +114,7 @@ func expectedProxyContainers(infra *ir.ProxyInfra, deploymentConfig *egv1a1.Kube return nil, fmt.Errorf("invalid protocol %q", p.Protocol) } port := corev1.ContainerPort{ - Name: p.Name, + Name: ExpectedServiceHashedName(p.Name), ContainerPort: p.ContainerPort, Protocol: protocol, } diff --git a/internal/infrastructure/kubernetes/proxy/resource_provider.go b/internal/infrastructure/kubernetes/proxy/resource_provider.go index 8dab7122855..a15527c48c5 100644 --- a/internal/infrastructure/kubernetes/proxy/resource_provider.go +++ b/internal/infrastructure/kubernetes/proxy/resource_provider.go @@ -45,7 +45,7 @@ func (r *ResourceRender) Name() string { func (r *ResourceRender) ServiceAccount() (*corev1.ServiceAccount, error) { // Set the labels based on the owning gateway name. labels := envoyLabels(r.infra.GetProxyMetadata().Labels) - if len(labels[gatewayapi.OwningGatewayNamespaceLabel]) == 0 || len(labels[gatewayapi.OwningGatewayNameLabel]) == 0 { + if (len(labels[gatewayapi.OwningGatewayNameLabel]) == 0 || len(labels[gatewayapi.OwningGatewayNamespaceLabel]) == 0) && len(labels[gatewayapi.OwningGatewayClassLabel]) == 0 { return nil, fmt.Errorf("missing owning gateway labels") } @@ -84,7 +84,7 @@ func (r *ResourceRender) Service() (*corev1.Service, error) { // Set the labels based on the owning gatewayclass name. labels := envoyLabels(r.infra.GetProxyMetadata().Labels) - if len(labels[gatewayapi.OwningGatewayNamespaceLabel]) == 0 || len(labels[gatewayapi.OwningGatewayNameLabel]) == 0 { + if (len(labels[gatewayapi.OwningGatewayNameLabel]) == 0 || len(labels[gatewayapi.OwningGatewayNamespaceLabel]) == 0) && len(labels[gatewayapi.OwningGatewayClassLabel]) == 0 { return nil, fmt.Errorf("missing owning gateway labels") } @@ -123,7 +123,7 @@ func (r *ResourceRender) Service() (*corev1.Service, error) { func (r *ResourceRender) ConfigMap() (*corev1.ConfigMap, error) { // Set the labels based on the owning gateway name. labels := envoyLabels(r.infra.GetProxyMetadata().Labels) - if len(labels[gatewayapi.OwningGatewayNamespaceLabel]) == 0 || len(labels[gatewayapi.OwningGatewayNameLabel]) == 0 { + if (len(labels[gatewayapi.OwningGatewayNameLabel]) == 0 || len(labels[gatewayapi.OwningGatewayNamespaceLabel]) == 0) && len(labels[gatewayapi.OwningGatewayClassLabel]) == 0 { return nil, fmt.Errorf("missing owning gateway labels") } @@ -169,7 +169,7 @@ func (r *ResourceRender) Deployment() (*appsv1.Deployment, error) { // Set the labels based on the owning gateway name. labels := r.infra.GetProxyMetadata().Labels dpLabels := envoyLabels(labels) - if len(dpLabels[gatewayapi.OwningGatewayNamespaceLabel]) == 0 || len(dpLabels[gatewayapi.OwningGatewayNameLabel]) == 0 { + if (len(dpLabels[gatewayapi.OwningGatewayNameLabel]) == 0 || len(dpLabels[gatewayapi.OwningGatewayNamespaceLabel]) == 0) && len(dpLabels[gatewayapi.OwningGatewayClassLabel]) == 0 { return nil, fmt.Errorf("missing owning gateway labels") } diff --git a/internal/provider/utils/utils.go b/internal/provider/utils/utils.go index 984a4e90d01..725285011bf 100644 --- a/internal/provider/utils/utils.go +++ b/internal/provider/utils/utils.go @@ -25,11 +25,7 @@ func NamespacedName(obj client.Object) types.NamespacedName { // GetHashedName returns a partially hashed name for the string including up to 48 characters of the original name before the hash. // Input `nsName` should be formatted as `{Namespace}/{ResourceName}`. func GetHashedName(nsName string) string { - - h := sha256.New() // Using sha256 instead of sha1 due to Blocklisted import crypto/sha1: weak cryptographic primitive (gosec) - h.Write([]byte(nsName)) - hashedName := strings.ToLower(fmt.Sprintf("%x", h.Sum(nil))) - + hashedName := HashString(nsName) // replace `/` with `-` to create a valid K8s resource name resourceName := strings.ReplaceAll(nsName, "/", "-") @@ -38,3 +34,9 @@ func GetHashedName(nsName string) string { } return fmt.Sprintf("%s-%s", resourceName, hashedName[0:8]) } + +func HashString(str string) string { + h := sha256.New() // Using sha256 instead of sha1 due to Blocklisted import crypto/sha1: weak cryptographic primitive (gosec) + h.Write([]byte(str)) + return strings.ToLower(fmt.Sprintf("%x", h.Sum(nil))) +} From b6123d237370cc3698b9b4fdb2b7b0430e5b78f8 Mon Sep 17 00:00:00 2001 From: Karol Szwaj Date: Thu, 12 Oct 2023 19:04:47 +0200 Subject: [PATCH 09/16] temp reconcile merged service and deployment Signed-off-by: Karol Szwaj --- .../kubernetes/proxy/resource.go | 6 +-- internal/provider/kubernetes/controller.go | 10 ++-- internal/provider/kubernetes/helpers.go | 12 ++++- internal/provider/kubernetes/predicates.go | 47 +++++++++++++++++-- .../provider/kubernetes/predicates_test.go | 2 +- 5 files changed, 63 insertions(+), 14 deletions(-) diff --git a/internal/infrastructure/kubernetes/proxy/resource.go b/internal/infrastructure/kubernetes/proxy/resource.go index 454b4dde29e..de1d3fae858 100644 --- a/internal/infrastructure/kubernetes/proxy/resource.go +++ b/internal/infrastructure/kubernetes/proxy/resource.go @@ -57,8 +57,8 @@ func ExpectedResourceHashedName(name string) string { return fmt.Sprintf("%s-%s", config.EnvoyPrefix, hashedName) } -// ExpectedServiceHashedName returns expected service name with max length of 15 characters. -func ExpectedServiceHashedName(name string) string { +// ExpectedContainerPortHashedName returns expected service name with max length of 15 characters. +func ExpectedContainerPortHashedName(name string) string { if len(name) > 15 { hashedName := providerutils.HashString(name) listenerName := strings.Split(name, "-") @@ -114,7 +114,7 @@ func expectedProxyContainers(infra *ir.ProxyInfra, deploymentConfig *egv1a1.Kube return nil, fmt.Errorf("invalid protocol %q", p.Protocol) } port := corev1.ContainerPort{ - Name: ExpectedServiceHashedName(p.Name), + Name: ExpectedContainerPortHashedName(p.Name), ContainerPort: p.ContainerPort, Protocol: protocol, } diff --git a/internal/provider/kubernetes/controller.go b/internal/provider/kubernetes/controller.go index 4517f1e7522..7bee0e914b6 100644 --- a/internal/provider/kubernetes/controller.go +++ b/internal/provider/kubernetes/controller.go @@ -407,16 +407,20 @@ func (r *gatewayAPIReconciler) statusUpdateForGateway(ctx context.Context, gtw * if r.statusUpdater == nil { return } - + var merged bool + res, _ := r.resources.GatewayAPIResources.Load(string(gtw.Spec.GatewayClassName)) + if res.EnvoyProxy != nil && res.EnvoyProxy.Spec.MergeGateways != nil && *res.EnvoyProxy.Spec.MergeGateways { + merged = true + } // Get deployment - deploy, err := r.envoyDeploymentForGateway(ctx, gtw) + deploy, err := r.envoyDeploymentForGateway(ctx, gtw, merged) if err != nil { r.log.Info("failed to get Deployment for gateway", "namespace", gtw.Namespace, "name", gtw.Name) } // Get service - svc, err := r.envoyServiceForGateway(ctx, gtw) + svc, err := r.envoyServiceForGateway(ctx, gtw, merged) if err != nil { r.log.Info("failed to get Service for gateway", "namespace", gtw.Namespace, "name", gtw.Name) diff --git a/internal/provider/kubernetes/helpers.go b/internal/provider/kubernetes/helpers.go index 40bcc964536..f533af24002 100644 --- a/internal/provider/kubernetes/helpers.go +++ b/internal/provider/kubernetes/helpers.go @@ -197,12 +197,20 @@ func refsSecret(ref *gwapiv1.SecretObjectReference) bool { (ref.Kind == nil || *ref.Kind == gatewayapi.KindSecret) } -func infraServiceName(gateway *gwapiv1.Gateway) string { +func infraServiceName(gateway *gwapiv1b1.Gateway, merged bool) string { + if merged { + infraName := utils.GetHashedName(string(gateway.Spec.GatewayClassName)) + return fmt.Sprintf("%s-%s", config.EnvoyPrefix, infraName) + } infraName := utils.GetHashedName(fmt.Sprintf("%s/%s", gateway.Namespace, gateway.Name)) return fmt.Sprintf("%s-%s", config.EnvoyPrefix, infraName) } -func infraDeploymentName(gateway *gwapiv1.Gateway) string { +func infraDeploymentName(gateway *gwapiv1b1.Gateway, merged bool) string { + if merged { + infraName := utils.GetHashedName(string(gateway.Spec.GatewayClassName)) + return fmt.Sprintf("%s-%s", config.EnvoyPrefix, infraName) + } infraName := utils.GetHashedName(fmt.Sprintf("%s/%s", gateway.Namespace, gateway.Name)) return fmt.Sprintf("%s-%s", config.EnvoyPrefix, infraName) } diff --git a/internal/provider/kubernetes/predicates.go b/internal/provider/kubernetes/predicates.go index 6ef95122ecf..54d67d11628 100644 --- a/internal/provider/kubernetes/predicates.go +++ b/internal/provider/kubernetes/predicates.go @@ -168,7 +168,20 @@ func (r *gatewayAPIReconciler) validateServiceForReconcile(obj client.Object) bo r.log.Info("unexpected object type, bypassing reconciliation", "object", obj) return false } + labels := svc.GetLabels() + gclass, ok := labels[gatewayapi.OwningGatewayClassLabel] + if ok { + gtw := r.findGateways(ctx, gclass) + if len(gtw.Items) != 0 { + for _, gw := range gtw.Items { + gw := gw + r.statusUpdateForGateway(ctx, &gw) + } + } + nsName := utils.NamespacedName(svc) + return r.isRouteReferencingBackend(&nsName) + } // Check if the Service belongs to a Gateway, if so, update the Gateway status. gtw := r.findOwningGateway(ctx, svc.GetLabels()) if gtw != nil { @@ -180,6 +193,19 @@ func (r *gatewayAPIReconciler) validateServiceForReconcile(obj client.Object) bo return r.isRouteReferencingBackend(&nsName) } +// findGateways attempts finds a GatewayList using accepted GatewayClass name. +func (r *gatewayAPIReconciler) findGateways(ctx context.Context, class string) *gwapiv1b1.GatewayList { + gatewayList := &gwapiv1b1.GatewayList{} + if err := r.client.List(ctx, gatewayList, &client.ListOptions{ + FieldSelector: fields.OneTermEqualSelector(classGatewayIndex, class), + }); err != nil { + r.log.Info("no associated Gateways found for GatewayClass", "name", class) + return nil + } + + return gatewayList +} + // validateServiceImportForReconcile tries finding the owning Gateway of the ServiceImport // if it exists, finds the Gateway's Deployment, and further updates the Gateway // status Ready condition. All Services are pushed for reconciliation. @@ -286,7 +312,18 @@ func (r *gatewayAPIReconciler) validateDeploymentForReconcile(obj client.Object) r.log.Info("unexpected object type, bypassing reconciliation", "object", obj) return false } - + labels := deployment.GetLabels() + gclass, ok := labels[gatewayapi.OwningGatewayClassLabel] + if ok { + gtw := r.findGateways(ctx, gclass) + if len(gtw.Items) != 0 { + for _, gw := range gtw.Items { + gw := gw + r.statusUpdateForGateway(ctx, &gw) + } + } + return false + } // Only deployments in the configured namespace should be reconciled. if deployment.Namespace == r.namespace { // Check if the deployment belongs to a Gateway, if so, update the Gateway status. @@ -374,10 +411,10 @@ func (r *gatewayAPIReconciler) filterHTTPRoutesByNamespaceLabels(httpRoutes []gw } // envoyDeploymentForGateway returns the Envoy Deployment, returning nil if the Deployment doesn't exist. -func (r *gatewayAPIReconciler) envoyDeploymentForGateway(ctx context.Context, gateway *gwapiv1.Gateway) (*appsv1.Deployment, error) { +func (r *gatewayAPIReconciler) envoyDeploymentForGateway(ctx context.Context, gateway *gwapiv1b1.Gateway, merged bool) (*appsv1.Deployment, error) { key := types.NamespacedName{ Namespace: r.namespace, - Name: infraDeploymentName(gateway), + Name: infraDeploymentName(gateway, merged), } deployment := new(appsv1.Deployment) if err := r.client.Get(ctx, key, deployment); err != nil { @@ -390,10 +427,10 @@ func (r *gatewayAPIReconciler) envoyDeploymentForGateway(ctx context.Context, ga } // envoyServiceForGateway returns the Envoy service, returning nil if the service doesn't exist. -func (r *gatewayAPIReconciler) envoyServiceForGateway(ctx context.Context, gateway *gwapiv1.Gateway) (*corev1.Service, error) { +func (r *gatewayAPIReconciler) envoyServiceForGateway(ctx context.Context, gateway *gwapiv1b1.Gateway, merged bool) (*corev1.Service, error) { key := types.NamespacedName{ Namespace: r.namespace, - Name: infraServiceName(gateway), + Name: infraServiceName(gateway, merged), } svc := new(corev1.Service) if err := r.client.Get(ctx, key, svc); err != nil { diff --git a/internal/provider/kubernetes/predicates_test.go b/internal/provider/kubernetes/predicates_test.go index 71d9dfd60c2..1a67937e6e0 100644 --- a/internal/provider/kubernetes/predicates_test.go +++ b/internal/provider/kubernetes/predicates_test.go @@ -334,7 +334,7 @@ func TestValidateServiceForReconcile(t *testing.T) { configs: []client.Object{ test.GetGatewayClass("test-gc", v1alpha1.GatewayControllerName), sampleGateway, - test.GetGatewayDeployment(types.NamespacedName{Name: infraDeploymentName(sampleGateway)}, nil), + test.GetGatewayDeployment(types.NamespacedName{Name: infraDeploymentName(sampleGateway, false)}, nil), }, service: test.GetService(types.NamespacedName{Name: "service"}, map[string]string{ gatewayapi.OwningGatewayNameLabel: "scheduled-status-test", From e2f33429ed0c5c1a41e3715f0e0a2a4454ab71aa Mon Sep 17 00:00:00 2001 From: Karol Szwaj Date: Fri, 13 Oct 2023 18:00:04 +0200 Subject: [PATCH 10/16] Reconcile merged service and deployment Signed-off-by: Karol Szwaj --- .../merge-invalid-multiple-gateways.out.yaml | 15 +++++++++++++++ .../merge-valid-multiple-gateways.out.yaml | 10 ++++++++++ .../testdata/multiple-gateways.out.yaml | 10 ++++++++++ internal/provider/kubernetes/predicates.go | 8 ++++---- 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml index 67f52c83c43..5f3918bda17 100755 --- a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml @@ -25,6 +25,11 @@ gateways: reason: Accepted status: "True" type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs name: http supportedKinds: - group: gateway.networking.k8s.io @@ -60,6 +65,11 @@ gateways: reason: Invalid status: "False" type: Programmed + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs name: http supportedKinds: - group: gateway.networking.k8s.io @@ -78,6 +88,11 @@ gateways: 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 diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml index 9f68963a4fb..57521ce77dd 100755 --- a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml @@ -28,6 +28,11 @@ gateways: reason: Accepted status: "True" type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs name: http supportedKinds: - group: gateway.networking.k8s.io @@ -63,6 +68,11 @@ gateways: 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 diff --git a/internal/gatewayapi/testdata/multiple-gateways.out.yaml b/internal/gatewayapi/testdata/multiple-gateways.out.yaml index 5b068902609..62d0bde4d55 100644 --- a/internal/gatewayapi/testdata/multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/multiple-gateways.out.yaml @@ -28,6 +28,11 @@ gateways: reason: Accepted status: "True" type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs name: http supportedKinds: - group: gateway.networking.k8s.io @@ -63,6 +68,11 @@ gateways: 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 diff --git a/internal/provider/kubernetes/predicates.go b/internal/provider/kubernetes/predicates.go index 54d67d11628..b3a7a5582df 100644 --- a/internal/provider/kubernetes/predicates.go +++ b/internal/provider/kubernetes/predicates.go @@ -411,10 +411,10 @@ func (r *gatewayAPIReconciler) filterHTTPRoutesByNamespaceLabels(httpRoutes []gw } // envoyDeploymentForGateway returns the Envoy Deployment, returning nil if the Deployment doesn't exist. -func (r *gatewayAPIReconciler) envoyDeploymentForGateway(ctx context.Context, gateway *gwapiv1b1.Gateway, merged bool) (*appsv1.Deployment, error) { +func (r *gatewayAPIReconciler) envoyDeploymentForGateway(ctx context.Context, gateway *gwapiv1b1.Gateway) (*appsv1.Deployment, error) { key := types.NamespacedName{ Namespace: r.namespace, - Name: infraDeploymentName(gateway, merged), + Name: infraDeploymentName(gateway, r.mergeGateways), } deployment := new(appsv1.Deployment) if err := r.client.Get(ctx, key, deployment); err != nil { @@ -427,10 +427,10 @@ func (r *gatewayAPIReconciler) envoyDeploymentForGateway(ctx context.Context, ga } // envoyServiceForGateway returns the Envoy service, returning nil if the service doesn't exist. -func (r *gatewayAPIReconciler) envoyServiceForGateway(ctx context.Context, gateway *gwapiv1b1.Gateway, merged bool) (*corev1.Service, error) { +func (r *gatewayAPIReconciler) envoyServiceForGateway(ctx context.Context, gateway *gwapiv1b1.Gateway) (*corev1.Service, error) { key := types.NamespacedName{ Namespace: r.namespace, - Name: infraServiceName(gateway, merged), + Name: infraServiceName(gateway, r.mergeGateways), } svc := new(corev1.Service) if err := r.client.Get(ctx, key, svc); err != nil { From 512bd4b1f02c112c91e00369e8bea1e29c2ce351 Mon Sep 17 00:00:00 2001 From: Karol Szwaj Date: Tue, 17 Oct 2023 17:57:23 +0200 Subject: [PATCH 11/16] review update Signed-off-by: Karol Szwaj --- internal/gatewayapi/address.go | 6 +- internal/gatewayapi/helpers.go | 2 +- internal/gatewayapi/listener.go | 6 +- internal/gatewayapi/route.go | 22 +-- .../merge-invalid-multiple-gateways.out.yaml | 4 +- .../merge-valid-multiple-gateways.in.yaml | 3 + .../merge-valid-multiple-gateways.out.yaml | 50 ++++--- .../testdata/multiple-gateways.in.yaml | 29 ---- .../testdata/multiple-gateways.out.yaml | 133 ------------------ internal/gatewayapi/translator.go | 9 ++ .../kubernetes/proxy/resource.go | 14 +- internal/provider/kubernetes/helpers.go | 21 +-- internal/provider/kubernetes/predicates.go | 47 ++----- .../provider/kubernetes/predicates_test.go | 2 +- internal/provider/utils/utils.go | 12 ++ 15 files changed, 88 insertions(+), 272 deletions(-) delete mode 100644 internal/gatewayapi/testdata/multiple-gateways.in.yaml delete mode 100644 internal/gatewayapi/testdata/multiple-gateways.out.yaml diff --git a/internal/gatewayapi/address.go b/internal/gatewayapi/address.go index fe28319e505..54907df0b12 100644 --- a/internal/gatewayapi/address.go +++ b/internal/gatewayapi/address.go @@ -18,11 +18,7 @@ type AddressesTranslator interface { func (t *Translator) ProcessAddresses(gateways []*GatewayContext, xdsIR XdsIRMap, infraIR InfraIRMap, resources *Resources) { for _, gateway := range gateways { // Infra IR already exist - irKey := irStringKey(gateway.Gateway.Namespace, gateway.Gateway.Name) - if t.MergeGateways { - irKey = string(t.GatewayClassName) - } - + irKey := t.getIRKey(gateway.Gateway) gwInfraIR := infraIR[irKey] var ipAddr []string diff --git a/internal/gatewayapi/helpers.go b/internal/gatewayapi/helpers.go index 218ce032126..8f57decd340 100644 --- a/internal/gatewayapi/helpers.go +++ b/internal/gatewayapi/helpers.go @@ -407,7 +407,7 @@ func irStringKey(gatewayNs, gatewayName string) string { } func irMergedInfraPortName(listener *ListenerContext) string { - return fmt.Sprintf("%s-%s-%s", listener.Name, listener.gateway.Namespace, listener.gateway.Name) + return fmt.Sprintf("%s/%s/%s", listener.Name, listener.gateway.Namespace, listener.gateway.Name) } func irHTTPListenerName(listener *ListenerContext) string { diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go index 938fb10313a..97df5657022 100644 --- a/internal/gatewayapi/listener.go +++ b/internal/gatewayapi/listener.go @@ -37,11 +37,7 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap for _, gateway := range gateways { // Infra IR proxy ports must be unique. var foundPorts []*protocolPort - - irKey := irStringKey(gateway.Gateway.Namespace, gateway.Gateway.Name) - if t.MergeGateways { - irKey = string(t.GatewayClassName) - } + irKey := t.getIRKey(gateway.Gateway) if resources.EnvoyProxy != nil { infraIR[irKey].Proxy.Config = resources.EnvoyProxy diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index 1769495f7fc..fe0ec085def 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -572,11 +572,7 @@ func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, route perHostRoutes = append(perHostRoutes, hostRoute) } } - irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name) - if t.MergeGateways { - irKey = string(t.GatewayClassName) - } - + irKey := t.getIRKey(listener.gateway) irListener := xdsIR[irKey].GetHTTPListener(irHTTPListenerName(listener)) if irListener != nil { if GetRouteType(route) == KindGRPCRoute { @@ -672,10 +668,7 @@ func (t *Translator) processTLSRouteParentRefs(tlsRoute *TLSRouteContext, resour hasHostnameIntersection = true - irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name) - if t.MergeGateways { - irKey = string(t.GatewayClassName) - } + irKey := t.getIRKey(listener.gateway) containerPort := servicePortToContainerPort(int32(listener.Port)) // Create the TCP Listener while parsing the TLSRoute since @@ -815,10 +808,7 @@ func (t *Translator) processUDPRouteParentRefs(udpRoute *UDPRouteContext, resour } accepted = true - irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name) - if t.MergeGateways { - irKey = string(t.GatewayClassName) - } + irKey := t.getIRKey(listener.gateway) containerPort := servicePortToContainerPort(int32(listener.Port)) // Create the UDP Listener while parsing the UDPRoute since @@ -954,11 +944,7 @@ func (t *Translator) processTCPRouteParentRefs(tcpRoute *TCPRouteContext, resour continue } accepted = true - - irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name) - if t.MergeGateways { - irKey = string(t.GatewayClassName) - } + irKey := t.getIRKey(listener.gateway) containerPort := servicePortToContainerPort(int32(listener.Port)) // Create the TCP Listener while parsing the TCPRoute since diff --git a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml index 5f3918bda17..cc4c154aae5 100755 --- a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml @@ -116,11 +116,11 @@ infraIR: - address: "" ports: - containerPort: 10080 - name: http-envoy-gateway-gateway-1 + name: http/envoy-gateway/gateway-1 protocol: HTTP servicePort: 80 - containerPort: 10080 - name: udp-envoy-gateway-gateway-2 + name: udp/envoy-gateway/gateway-2 protocol: UDP servicePort: 80 metadata: diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml index fb98a3fa81f..47a258666fe 100644 --- a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml @@ -35,3 +35,6 @@ gateways: allowedRoutes: namespaces: from: Same + - name: http-3 + port: 8888 + protocol: HTTP diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml index 57521ce77dd..9ac1206f665 100755 --- a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml @@ -54,26 +54,52 @@ gateways: name: http-2 port: 8888 protocol: HTTP + - name: http-3 + port: 8888 + protocol: HTTP status: listeners: - attachedRoutes: 0 conditions: - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict status: "True" + type: Conflicted + - lastTransitionTime: null + message: Listener is invalid, see other Conditions for details. + reason: Invalid + status: "False" type: Programmed - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted + message: Listener references have been resolved + reason: ResolvedRefs status: "True" - type: Accepted + type: ResolvedRefs + name: http-2 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Port, protocol and hostname tuple must be unique for every listener + reason: HostnameConflict + status: "True" + type: Conflicted + - lastTransitionTime: null + message: Listener is invalid, see other Conditions for details. + reason: Invalid + status: "False" + type: Programmed - lastTransitionTime: null message: Listener references have been resolved reason: ResolvedRefs status: "True" type: ResolvedRefs - name: http-2 + name: http-3 supportedKinds: - group: gateway.networking.k8s.io kind: HTTPRoute @@ -98,13 +124,9 @@ infraIR: - address: "" ports: - containerPort: 10080 - name: http-envoy-gateway-gateway-1 + name: http/envoy-gateway/gateway-1 protocol: HTTP servicePort: 80 - - containerPort: 8888 - name: http-2-envoy-gateway-gateway-2 - protocol: HTTP - servicePort: 8888 metadata: labels: gateway.envoyproxy.io/owning-gatewayclass: envoy-gateway-class @@ -121,9 +143,3 @@ xdsIR: isHTTP2: false name: envoy-gateway/gateway-1/http port: 10080 - - address: 0.0.0.0 - hostnames: - - '*' - isHTTP2: false - name: envoy-gateway/gateway-2/http-2 - port: 8888 diff --git a/internal/gatewayapi/testdata/multiple-gateways.in.yaml b/internal/gatewayapi/testdata/multiple-gateways.in.yaml deleted file mode 100644 index b066477dce6..00000000000 --- a/internal/gatewayapi/testdata/multiple-gateways.in.yaml +++ /dev/null @@ -1,29 +0,0 @@ -gateways: - - apiVersion: gateway.networking.k8s.io/v1beta1 - kind: Gateway - metadata: - name: gateway-1 - namespace: envoy-gateway - spec: - gatewayClassName: envoy-gateway-class - listeners: - - name: http - port: 80 - protocol: HTTP - allowedRoutes: - namespaces: - from: Same - - apiVersion: gateway.networking.k8s.io/v1beta1 - kind: Gateway - metadata: - name: gateway-2 - namespace: envoy-gateway - spec: - gatewayClassName: envoy-gateway-class - listeners: - - name: http-2 - port: 8888 - protocol: HTTP - allowedRoutes: - namespaces: - from: Same diff --git a/internal/gatewayapi/testdata/multiple-gateways.out.yaml b/internal/gatewayapi/testdata/multiple-gateways.out.yaml deleted file mode 100644 index 62d0bde4d55..00000000000 --- a/internal/gatewayapi/testdata/multiple-gateways.out.yaml +++ /dev/null @@ -1,133 +0,0 @@ -gateways: -- apiVersion: gateway.networking.k8s.io/v1beta1 - kind: Gateway - metadata: - creationTimestamp: null - name: gateway-1 - namespace: envoy-gateway - spec: - gatewayClassName: envoy-gateway-class - listeners: - - allowedRoutes: - namespaces: - from: Same - name: http - port: 80 - protocol: HTTP - status: - listeners: - - attachedRoutes: 0 - 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 - supportedKinds: - - group: gateway.networking.k8s.io - kind: HTTPRoute - - group: gateway.networking.k8s.io - kind: GRPCRoute -- apiVersion: gateway.networking.k8s.io/v1beta1 - kind: Gateway - metadata: - creationTimestamp: null - name: gateway-2 - namespace: envoy-gateway - spec: - gatewayClassName: envoy-gateway-class - listeners: - - allowedRoutes: - namespaces: - from: Same - name: http-2 - port: 8888 - protocol: HTTP - status: - listeners: - - attachedRoutes: 0 - 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 -infraIR: - envoy-gateway/gateway-1: - proxy: - listeners: - - address: "" - ports: - - containerPort: 10080 - name: http - protocol: HTTP - servicePort: 80 - metadata: - labels: - gateway.envoyproxy.io/owning-gateway-name: gateway-1 - gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway - name: envoy-gateway/gateway-1 - envoy-gateway/gateway-2: - proxy: - listeners: - - address: "" - ports: - - containerPort: 8888 - name: http-2 - protocol: HTTP - servicePort: 8888 - metadata: - labels: - gateway.envoyproxy.io/owning-gateway-name: gateway-2 - gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway - name: envoy-gateway/gateway-2 -xdsIR: - envoy-gateway/gateway-1: - accessLog: - text: - - path: /dev/stdout - http: - - address: 0.0.0.0 - hostnames: - - '*' - isHTTP2: false - name: envoy-gateway/gateway-1/http - port: 10080 - envoy-gateway/gateway-2: - accessLog: - text: - - path: /dev/stdout - http: - - address: 0.0.0.0 - hostnames: - - '*' - isHTTP2: false - name: envoy-gateway/gateway-2/http-2 - port: 8888 diff --git a/internal/gatewayapi/translator.go b/internal/gatewayapi/translator.go index 4616101a843..cd71be691dd 100644 --- a/internal/gatewayapi/translator.go +++ b/internal/gatewayapi/translator.go @@ -216,3 +216,12 @@ func (t *Translator) InitIRs(gateways []*GatewayContext, resources *Resources) ( return xdsIR, infraIR } + +func (t *Translator) getIRKey(gateway *v1beta1.Gateway) string { + irKey := irStringKey(gateway.Namespace, gateway.Name) + if t.MergeGateways { + return string(t.GatewayClassName) + } + + return irKey +} diff --git a/internal/infrastructure/kubernetes/proxy/resource.go b/internal/infrastructure/kubernetes/proxy/resource.go index de1d3fae858..08106c458f3 100644 --- a/internal/infrastructure/kubernetes/proxy/resource.go +++ b/internal/infrastructure/kubernetes/proxy/resource.go @@ -7,7 +7,6 @@ package proxy import ( "fmt" - "strings" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -57,17 +56,6 @@ func ExpectedResourceHashedName(name string) string { return fmt.Sprintf("%s-%s", config.EnvoyPrefix, hashedName) } -// ExpectedContainerPortHashedName returns expected service name with max length of 15 characters. -func ExpectedContainerPortHashedName(name string) string { - if len(name) > 15 { - hashedName := providerutils.HashString(name) - listenerName := strings.Split(name, "-") - - return fmt.Sprintf("%s-%s", listenerName[0], hashedName[0:14-len(listenerName)]) - } - return name -} - // EnvoyAppLabel returns the labels used for all Envoy resources. func EnvoyAppLabel() map[string]string { return map[string]string{ @@ -114,7 +102,7 @@ func expectedProxyContainers(infra *ir.ProxyInfra, deploymentConfig *egv1a1.Kube return nil, fmt.Errorf("invalid protocol %q", p.Protocol) } port := corev1.ContainerPort{ - Name: ExpectedContainerPortHashedName(p.Name), + Name: providerutils.ExpectedContainerPortHashedName(p.Name), ContainerPort: p.ContainerPort, Protocol: protocol, } diff --git a/internal/provider/kubernetes/helpers.go b/internal/provider/kubernetes/helpers.go index f533af24002..e272f746827 100644 --- a/internal/provider/kubernetes/helpers.go +++ b/internal/provider/kubernetes/helpers.go @@ -17,9 +17,8 @@ import ( mcsapi "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1" egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1" - "github.com/envoyproxy/gateway/internal/envoygateway/config" "github.com/envoyproxy/gateway/internal/gatewayapi" - "github.com/envoyproxy/gateway/internal/provider/utils" + "github.com/envoyproxy/gateway/internal/infrastructure/kubernetes/proxy" ) const ( @@ -197,22 +196,12 @@ func refsSecret(ref *gwapiv1.SecretObjectReference) bool { (ref.Kind == nil || *ref.Kind == gatewayapi.KindSecret) } -func infraServiceName(gateway *gwapiv1b1.Gateway, merged bool) string { +func infraName(gateway *gwapiv1b1.Gateway, merged bool) string { if merged { - infraName := utils.GetHashedName(string(gateway.Spec.GatewayClassName)) - return fmt.Sprintf("%s-%s", config.EnvoyPrefix, infraName) + return proxy.ExpectedResourceHashedName(string(gateway.Spec.GatewayClassName)) } - infraName := utils.GetHashedName(fmt.Sprintf("%s/%s", gateway.Namespace, gateway.Name)) - return fmt.Sprintf("%s-%s", config.EnvoyPrefix, infraName) -} - -func infraDeploymentName(gateway *gwapiv1b1.Gateway, merged bool) string { - if merged { - infraName := utils.GetHashedName(string(gateway.Spec.GatewayClassName)) - return fmt.Sprintf("%s-%s", config.EnvoyPrefix, infraName) - } - infraName := utils.GetHashedName(fmt.Sprintf("%s/%s", gateway.Namespace, gateway.Name)) - return fmt.Sprintf("%s-%s", config.EnvoyPrefix, infraName) + infraName := fmt.Sprintf("%s/%s", gateway.Namespace, gateway.Name) + return proxy.ExpectedResourceHashedName(infraName) } // validateBackendRef validates that ref is a reference to a local Service. diff --git a/internal/provider/kubernetes/predicates.go b/internal/provider/kubernetes/predicates.go index b3a7a5582df..fe2bc7817a1 100644 --- a/internal/provider/kubernetes/predicates.go +++ b/internal/provider/kubernetes/predicates.go @@ -169,19 +169,16 @@ func (r *gatewayAPIReconciler) validateServiceForReconcile(obj client.Object) bo return false } labels := svc.GetLabels() - gclass, ok := labels[gatewayapi.OwningGatewayClassLabel] + gclass := labels[gatewayapi.OwningGatewayClassLabel] + res, ok := r.resources.GatewayAPIResources.Load(gclass) if ok { - gtw := r.findGateways(ctx, gclass) - if len(gtw.Items) != 0 { - for _, gw := range gtw.Items { - gw := gw - r.statusUpdateForGateway(ctx, &gw) - } + for _, gw := range res.Gateways { + gw := gw + r.statusUpdateForGateway(ctx, gw) } - - nsName := utils.NamespacedName(svc) - return r.isRouteReferencingBackend(&nsName) + return false } + // Check if the Service belongs to a Gateway, if so, update the Gateway status. gtw := r.findOwningGateway(ctx, svc.GetLabels()) if gtw != nil { @@ -193,19 +190,6 @@ func (r *gatewayAPIReconciler) validateServiceForReconcile(obj client.Object) bo return r.isRouteReferencingBackend(&nsName) } -// findGateways attempts finds a GatewayList using accepted GatewayClass name. -func (r *gatewayAPIReconciler) findGateways(ctx context.Context, class string) *gwapiv1b1.GatewayList { - gatewayList := &gwapiv1b1.GatewayList{} - if err := r.client.List(ctx, gatewayList, &client.ListOptions{ - FieldSelector: fields.OneTermEqualSelector(classGatewayIndex, class), - }); err != nil { - r.log.Info("no associated Gateways found for GatewayClass", "name", class) - return nil - } - - return gatewayList -} - // validateServiceImportForReconcile tries finding the owning Gateway of the ServiceImport // if it exists, finds the Gateway's Deployment, and further updates the Gateway // status Ready condition. All Services are pushed for reconciliation. @@ -313,17 +297,16 @@ func (r *gatewayAPIReconciler) validateDeploymentForReconcile(obj client.Object) return false } labels := deployment.GetLabels() - gclass, ok := labels[gatewayapi.OwningGatewayClassLabel] + gclass := labels[gatewayapi.OwningGatewayClassLabel] + res, ok := r.resources.GatewayAPIResources.Load(gclass) if ok { - gtw := r.findGateways(ctx, gclass) - if len(gtw.Items) != 0 { - for _, gw := range gtw.Items { - gw := gw - r.statusUpdateForGateway(ctx, &gw) - } + for _, gw := range res.Gateways { + gw := gw + r.statusUpdateForGateway(ctx, gw) } return false } + // Only deployments in the configured namespace should be reconciled. if deployment.Namespace == r.namespace { // Check if the deployment belongs to a Gateway, if so, update the Gateway status. @@ -414,7 +397,7 @@ func (r *gatewayAPIReconciler) filterHTTPRoutesByNamespaceLabels(httpRoutes []gw func (r *gatewayAPIReconciler) envoyDeploymentForGateway(ctx context.Context, gateway *gwapiv1b1.Gateway) (*appsv1.Deployment, error) { key := types.NamespacedName{ Namespace: r.namespace, - Name: infraDeploymentName(gateway, r.mergeGateways), + Name: infraName(gateway, r.mergeGateways), } deployment := new(appsv1.Deployment) if err := r.client.Get(ctx, key, deployment); err != nil { @@ -430,7 +413,7 @@ func (r *gatewayAPIReconciler) envoyDeploymentForGateway(ctx context.Context, ga func (r *gatewayAPIReconciler) envoyServiceForGateway(ctx context.Context, gateway *gwapiv1b1.Gateway) (*corev1.Service, error) { key := types.NamespacedName{ Namespace: r.namespace, - Name: infraServiceName(gateway, r.mergeGateways), + Name: infraName(gateway, r.mergeGateways), } svc := new(corev1.Service) if err := r.client.Get(ctx, key, svc); err != nil { diff --git a/internal/provider/kubernetes/predicates_test.go b/internal/provider/kubernetes/predicates_test.go index 1a67937e6e0..2bd311e95ee 100644 --- a/internal/provider/kubernetes/predicates_test.go +++ b/internal/provider/kubernetes/predicates_test.go @@ -334,7 +334,7 @@ func TestValidateServiceForReconcile(t *testing.T) { configs: []client.Object{ test.GetGatewayClass("test-gc", v1alpha1.GatewayControllerName), sampleGateway, - test.GetGatewayDeployment(types.NamespacedName{Name: infraDeploymentName(sampleGateway, false)}, nil), + test.GetGatewayDeployment(types.NamespacedName{Name: infraName(sampleGateway, false)}, nil), }, service: test.GetService(types.NamespacedName{Name: "service"}, map[string]string{ gatewayapi.OwningGatewayNameLabel: "scheduled-status-test", diff --git a/internal/provider/utils/utils.go b/internal/provider/utils/utils.go index 725285011bf..0d64ff46236 100644 --- a/internal/provider/utils/utils.go +++ b/internal/provider/utils/utils.go @@ -40,3 +40,15 @@ func HashString(str string) string { h.Write([]byte(str)) return strings.ToLower(fmt.Sprintf("%x", h.Sum(nil))) } + +// ExpectedContainerPortHashedName returns expected service name with max length of 15 characters. +func ExpectedContainerPortHashedName(name string) string { + if len(name) > 15 { + hashedName := HashString(name) + resourceName := strings.ReplaceAll(name, "/", "-") + listenerName := strings.Split(resourceName, "-") + + return fmt.Sprintf("%s-%s", listenerName[0], hashedName[0:14-len(listenerName)]) + } + return name +} From e3de00c98c11c84d004b3803e957c3ab63f4b521 Mon Sep 17 00:00:00 2001 From: Karol Szwaj Date: Tue, 17 Oct 2023 18:45:41 +0200 Subject: [PATCH 12/16] fix reconcile Signed-off-by: Karol Szwaj --- .../kubernetes/proxy/resource_provider.go | 4 ++- internal/provider/kubernetes/predicates.go | 36 ++++++++++--------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/internal/infrastructure/kubernetes/proxy/resource_provider.go b/internal/infrastructure/kubernetes/proxy/resource_provider.go index a15527c48c5..b0ea441aa71 100644 --- a/internal/infrastructure/kubernetes/proxy/resource_provider.go +++ b/internal/infrastructure/kubernetes/proxy/resource_provider.go @@ -8,6 +8,7 @@ package proxy import ( "fmt" "strconv" + "strings" "golang.org/x/exp/maps" appsv1 "k8s.io/api/apps/v1" @@ -72,8 +73,9 @@ func (r *ResourceRender) Service() (*corev1.Service, error) { if port.Protocol == ir.UDPProtocolType { protocol = corev1.ProtocolUDP } + name := strings.ReplaceAll(port.Name, "/", "-") p := corev1.ServicePort{ - Name: port.Name, + Name: name, Protocol: protocol, Port: port.ServicePort, TargetPort: target, diff --git a/internal/provider/kubernetes/predicates.go b/internal/provider/kubernetes/predicates.go index fe2bc7817a1..9df4a255910 100644 --- a/internal/provider/kubernetes/predicates.go +++ b/internal/provider/kubernetes/predicates.go @@ -169,6 +169,14 @@ func (r *gatewayAPIReconciler) validateServiceForReconcile(obj client.Object) bo return false } labels := svc.GetLabels() + + // Check if the Service belongs to a Gateway, if so, update the Gateway status. + gtw := r.findOwningGateway(ctx, labels) + if gtw != nil { + r.statusUpdateForGateway(ctx, gtw) + return false + } + gclass := labels[gatewayapi.OwningGatewayClassLabel] res, ok := r.resources.GatewayAPIResources.Load(gclass) if ok { @@ -179,13 +187,6 @@ func (r *gatewayAPIReconciler) validateServiceForReconcile(obj client.Object) bo return false } - // Check if the Service belongs to a Gateway, if so, update the Gateway status. - gtw := r.findOwningGateway(ctx, svc.GetLabels()) - if gtw != nil { - r.statusUpdateForGateway(ctx, gtw) - return false - } - nsName := utils.NamespacedName(svc) return r.isRouteReferencingBackend(&nsName) } @@ -297,26 +298,27 @@ func (r *gatewayAPIReconciler) validateDeploymentForReconcile(obj client.Object) return false } labels := deployment.GetLabels() - gclass := labels[gatewayapi.OwningGatewayClassLabel] - res, ok := r.resources.GatewayAPIResources.Load(gclass) - if ok { - for _, gw := range res.Gateways { - gw := gw - r.statusUpdateForGateway(ctx, gw) - } - return false - } // Only deployments in the configured namespace should be reconciled. if deployment.Namespace == r.namespace { // Check if the deployment belongs to a Gateway, if so, update the Gateway status. - gtw := r.findOwningGateway(ctx, deployment.GetLabels()) + gtw := r.findOwningGateway(ctx, labels) if gtw != nil { r.statusUpdateForGateway(ctx, gtw) return false } } + gclass := labels[gatewayapi.OwningGatewayClassLabel] + res, ok := r.resources.GatewayAPIResources.Load(gclass) + if ok { + for _, gw := range res.Gateways { + gw := gw + r.statusUpdateForGateway(ctx, gw) + } + return false + } + // There is no need to reconcile the Deployment any further. return false } From ce27ea7c3b5efa984c723da97677cabe3382860f Mon Sep 17 00:00:00 2001 From: Karol Szwaj Date: Tue, 17 Oct 2023 23:32:17 +0200 Subject: [PATCH 13/16] add comments Signed-off-by: Karol Szwaj --- internal/gatewayapi/helpers.go | 1 + internal/gatewayapi/translator.go | 2 ++ internal/gatewayapi/validate.go | 8 ++++---- .../kubernetes/proxy/resource_provider.go | 5 +++-- internal/provider/kubernetes/helpers.go | 3 +++ internal/provider/kubernetes/predicates.go | 16 +++++++++------- internal/provider/utils/utils.go | 3 ++- 7 files changed, 24 insertions(+), 14 deletions(-) diff --git a/internal/gatewayapi/helpers.go b/internal/gatewayapi/helpers.go index 8f57decd340..114dfa2e3c8 100644 --- a/internal/gatewayapi/helpers.go +++ b/internal/gatewayapi/helpers.go @@ -453,6 +453,7 @@ func irTLSConfigs(tlsSecrets []*v1.Secret) []*ir.TLSListenerConfig { func irTLSListenerConfigName(secret *v1.Secret) string { return fmt.Sprintf("%s-%s", secret.Namespace, secret.Name) } + func isMergeGatewaysEnabled(resources *Resources) bool { return resources.EnvoyProxy != nil && resources.EnvoyProxy.Spec.MergeGateways != nil && *resources.EnvoyProxy.Spec.MergeGateways } diff --git a/internal/gatewayapi/translator.go b/internal/gatewayapi/translator.go index cd71be691dd..4e925e9d424 100644 --- a/internal/gatewayapi/translator.go +++ b/internal/gatewayapi/translator.go @@ -191,6 +191,7 @@ func (t *Translator) GetRelevantGateways(gateways []*gwapiv1.Gateway) []*Gateway return relevant } +// InitIRs checks if mergeGateways is enabled in EnvoyProxy config and initializes XdsIR and InfraIR maps with adequate keys. func (t *Translator) InitIRs(gateways []*GatewayContext, resources *Resources) (map[string]*ir.Xds, map[string]*ir.Infra) { xdsIR := make(XdsIRMap) infraIR := make(InfraIRMap) @@ -217,6 +218,7 @@ func (t *Translator) InitIRs(gateways []*GatewayContext, resources *Resources) ( return xdsIR, infraIR } +// XdsIR and InfraIR map keys by default are {GatewayNamespace}/{GatewayName}, but if mergeGateways is set, they are merged under {GatewayClassName} key. func (t *Translator) getIRKey(gateway *v1beta1.Gateway) string { irKey := irStringKey(gateway.Namespace, gateway.Name) if t.MergeGateways { diff --git a/internal/gatewayapi/validate.go b/internal/gatewayapi/validate.go index 16200c2b7b0..8f8264d2aeb 100644 --- a/internal/gatewayapi/validate.go +++ b/internal/gatewayapi/validate.go @@ -533,16 +533,16 @@ type portListeners struct { hostnames map[string]int } +// Port, protocol and hostname tuple should be unique across all listeners on merged Gateways. func (t *Translator) validateConflictedMergedListeners(gateways []*GatewayContext) { listenerSets := sets.Set[string]{} for _, gateway := range gateways { for _, listener := range gateway.listeners { - var hostname string + hostname := new(v1beta1.Hostname) if listener.Hostname != nil { - hostname = string(*listener.Hostname) + hostname = listener.Hostname } - - portProtocolHostname := fmt.Sprintf("%s:%s:%d", listener.Protocol, hostname, listener.Port) + portProtocolHostname := fmt.Sprintf("%s:%s:%d", listener.Protocol, *hostname, listener.Port) if listenerSets.Has(portProtocolHostname) { listener.SetCondition( v1beta1.ListenerConditionConflicted, diff --git a/internal/infrastructure/kubernetes/proxy/resource_provider.go b/internal/infrastructure/kubernetes/proxy/resource_provider.go index b0ea441aa71..3ce736a6b37 100644 --- a/internal/infrastructure/kubernetes/proxy/resource_provider.go +++ b/internal/infrastructure/kubernetes/proxy/resource_provider.go @@ -73,9 +73,10 @@ func (r *ResourceRender) Service() (*corev1.Service, error) { if port.Protocol == ir.UDPProtocolType { protocol = corev1.ProtocolUDP } - name := strings.ReplaceAll(port.Name, "/", "-") + // Listeners on merged gateways will have a port name {ListenerName}/{GatewayNamespace}/{GatewayName}. + portName := strings.ReplaceAll(port.Name, "/", "-") p := corev1.ServicePort{ - Name: name, + Name: portName, Protocol: protocol, Port: port.ServicePort, TargetPort: target, diff --git a/internal/provider/kubernetes/helpers.go b/internal/provider/kubernetes/helpers.go index e272f746827..3b93f728ef2 100644 --- a/internal/provider/kubernetes/helpers.go +++ b/internal/provider/kubernetes/helpers.go @@ -196,6 +196,9 @@ func refsSecret(ref *gwapiv1.SecretObjectReference) bool { (ref.Kind == nil || *ref.Kind == gatewayapi.KindSecret) } +// infraName returns expected name for the EnvoyProxy infra resources. +// By default it returns hashed string from {GatewayNamespace}/{GatewayName}, +// but if mergeGateways is set, it will return hashed string of {GatewayClassName}. func infraName(gateway *gwapiv1b1.Gateway, merged bool) string { if merged { return proxy.ExpectedResourceHashedName(string(gateway.Spec.GatewayClassName)) diff --git a/internal/provider/kubernetes/predicates.go b/internal/provider/kubernetes/predicates.go index 9df4a255910..23f96bd4922 100644 --- a/internal/provider/kubernetes/predicates.go +++ b/internal/provider/kubernetes/predicates.go @@ -177,9 +177,10 @@ func (r *gatewayAPIReconciler) validateServiceForReconcile(obj client.Object) bo return false } - gclass := labels[gatewayapi.OwningGatewayClassLabel] - res, ok := r.resources.GatewayAPIResources.Load(gclass) + // Only merged gateways will have this label, update status of all Gateways under found GatewayClass. + gclass, ok := labels[gatewayapi.OwningGatewayClassLabel] if ok { + res, _ := r.resources.GatewayAPIResources.Load(gclass) for _, gw := range res.Gateways { gw := gw r.statusUpdateForGateway(ctx, gw) @@ -309,12 +310,13 @@ func (r *gatewayAPIReconciler) validateDeploymentForReconcile(obj client.Object) } } - gclass := labels[gatewayapi.OwningGatewayClassLabel] - res, ok := r.resources.GatewayAPIResources.Load(gclass) + // Only merged gateways will have this label, update status of all Gateways under found GatewayClass. + gclass, ok := labels[gatewayapi.OwningGatewayClassLabel] if ok { - for _, gw := range res.Gateways { - gw := gw - r.statusUpdateForGateway(ctx, gw) + res, _ := r.resources.GatewayAPIResources.Load(gclass) + for _, gtw := range res.Gateways { + gtw := gtw + r.statusUpdateForGateway(ctx, gtw) } return false } diff --git a/internal/provider/utils/utils.go b/internal/provider/utils/utils.go index 0d64ff46236..45915487469 100644 --- a/internal/provider/utils/utils.go +++ b/internal/provider/utils/utils.go @@ -41,7 +41,8 @@ func HashString(str string) string { return strings.ToLower(fmt.Sprintf("%x", h.Sum(nil))) } -// ExpectedContainerPortHashedName returns expected service name with max length of 15 characters. +// ExpectedContainerPortHashedName returns expected container port name with max length of 15 characters. +// If mergedGateways is enabled or listener port name is larger than 15 characters it will return partially hashed name. func ExpectedContainerPortHashedName(name string) string { if len(name) > 15 { hashedName := HashString(name) From 94ffc039904ce0a0f5bb1b64062ae2e606c24ffd Mon Sep 17 00:00:00 2001 From: Karol Szwaj Date: Wed, 18 Oct 2023 20:12:44 +0200 Subject: [PATCH 14/16] Rename infra port name Signed-off-by: Karol Szwaj --- internal/gatewayapi/helpers.go | 4 -- internal/gatewayapi/listener.go | 2 +- .../merge-invalid-multiple-gateways.out.yaml | 4 +- .../merge-valid-multiple-gateways.in.yaml | 1 + .../merge-valid-multiple-gateways.out.yaml | 49 +++++++++++++------ .../kubernetes/proxy/resource_provider.go | 2 +- internal/provider/utils/utils.go | 6 ++- 7 files changed, 42 insertions(+), 26 deletions(-) diff --git a/internal/gatewayapi/helpers.go b/internal/gatewayapi/helpers.go index 114dfa2e3c8..7a79002b29b 100644 --- a/internal/gatewayapi/helpers.go +++ b/internal/gatewayapi/helpers.go @@ -406,10 +406,6 @@ func irStringKey(gatewayNs, gatewayName string) string { return fmt.Sprintf("%s/%s", gatewayNs, gatewayName) } -func irMergedInfraPortName(listener *ListenerContext) string { - return fmt.Sprintf("%s/%s/%s", listener.Name, listener.gateway.Namespace, listener.gateway.Name) -} - func irHTTPListenerName(listener *ListenerContext) string { return fmt.Sprintf("%s/%s/%s", listener.gateway.Namespace, listener.gateway.Name, listener.Name) } diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go index 97df5657022..8549728f92d 100644 --- a/internal/gatewayapi/listener.go +++ b/internal/gatewayapi/listener.go @@ -136,7 +136,7 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap infraPortName := string(listener.Name) if t.MergeGateways { - infraPortName = irMergedInfraPortName(listener) + infraPortName = irHTTPListenerName(listener) } infraPort := ir.ListenerPort{ diff --git a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml index cc4c154aae5..f97cf5e4b11 100755 --- a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml @@ -116,11 +116,11 @@ infraIR: - address: "" ports: - containerPort: 10080 - name: http/envoy-gateway/gateway-1 + name: envoy-gateway/gateway-1/http protocol: HTTP servicePort: 80 - containerPort: 10080 - name: udp/envoy-gateway/gateway-2 + name: envoy-gateway/gateway-2/udp protocol: UDP servicePort: 80 metadata: diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml index 47a258666fe..aad24f222ea 100644 --- a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.in.yaml @@ -36,5 +36,6 @@ gateways: namespaces: from: Same - name: http-3 + hostname: example.com port: 8888 protocol: HTTP diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml index 9ac1206f665..48043d99bf7 100755 --- a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml @@ -54,7 +54,8 @@ gateways: name: http-2 port: 8888 protocol: HTTP - - name: http-3 + - hostname: example.com + name: http-3 port: 8888 protocol: HTTP status: @@ -62,15 +63,15 @@ gateways: - attachedRoutes: 0 conditions: - lastTransitionTime: null - message: All listeners for a given port must use a unique hostname - reason: HostnameConflict + message: Sending translated listener configuration to the data plane + reason: Programmed status: "True" - type: Conflicted - - lastTransitionTime: null - message: Listener is invalid, see other Conditions for details. - reason: Invalid - status: "False" 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 @@ -85,15 +86,15 @@ gateways: - attachedRoutes: 0 conditions: - lastTransitionTime: null - message: Port, protocol and hostname tuple must be unique for every listener - reason: HostnameConflict + message: Sending translated listener configuration to the data plane + reason: Programmed status: "True" - type: Conflicted - - lastTransitionTime: null - message: Listener is invalid, see other Conditions for details. - reason: Invalid - status: "False" 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 @@ -124,9 +125,13 @@ infraIR: - address: "" ports: - containerPort: 10080 - name: http/envoy-gateway/gateway-1 + name: envoy-gateway/gateway-1/http protocol: HTTP servicePort: 80 + - containerPort: 8888 + name: envoy-gateway/gateway-2/http-2 + protocol: HTTP + servicePort: 8888 metadata: labels: gateway.envoyproxy.io/owning-gatewayclass: envoy-gateway-class @@ -143,3 +148,15 @@ xdsIR: isHTTP2: false name: envoy-gateway/gateway-1/http port: 10080 + - address: 0.0.0.0 + hostnames: + - '*' + isHTTP2: false + name: envoy-gateway/gateway-2/http-2 + port: 8888 + - address: 0.0.0.0 + hostnames: + - example.com + isHTTP2: false + name: envoy-gateway/gateway-2/http-3 + port: 8888 diff --git a/internal/infrastructure/kubernetes/proxy/resource_provider.go b/internal/infrastructure/kubernetes/proxy/resource_provider.go index 3ce736a6b37..efcc1e6a1e1 100644 --- a/internal/infrastructure/kubernetes/proxy/resource_provider.go +++ b/internal/infrastructure/kubernetes/proxy/resource_provider.go @@ -73,7 +73,7 @@ func (r *ResourceRender) Service() (*corev1.Service, error) { if port.Protocol == ir.UDPProtocolType { protocol = corev1.ProtocolUDP } - // Listeners on merged gateways will have a port name {ListenerName}/{GatewayNamespace}/{GatewayName}. + // Listeners on merged gateways will have a port name {GatewayNamespace}/{GatewayName}/{ListenerName}. portName := strings.ReplaceAll(port.Name, "/", "-") p := corev1.ServicePort{ Name: portName, diff --git a/internal/provider/utils/utils.go b/internal/provider/utils/utils.go index 45915487469..0417b892cfa 100644 --- a/internal/provider/utils/utils.go +++ b/internal/provider/utils/utils.go @@ -43,13 +43,15 @@ func HashString(str string) string { // ExpectedContainerPortHashedName returns expected container port name with max length of 15 characters. // If mergedGateways is enabled or listener port name is larger than 15 characters it will return partially hashed name. +// Listeners on merged gateways have a infraIR port name {GatewayNamespace}/{GatewayName}/{ListenerName}. func ExpectedContainerPortHashedName(name string) string { if len(name) > 15 { hashedName := HashString(name) + // replace `/` with `-` to create a valid K8s resource name resourceName := strings.ReplaceAll(name, "/", "-") - listenerName := strings.Split(resourceName, "-") + listenerName := string(resourceName[2]) - return fmt.Sprintf("%s-%s", listenerName[0], hashedName[0:14-len(listenerName)]) + return fmt.Sprintf("%s-%s", listenerName, hashedName[0:14-len(listenerName)]) } return name } From 1d621ca4c5b6e54f563734a0d3608872d0c361ee Mon Sep 17 00:00:00 2001 From: Karol Szwaj Date: Thu, 19 Oct 2023 14:03:48 +0200 Subject: [PATCH 15/16] add testdata for merged gateways with routes Signed-off-by: Karol Szwaj --- ...-multiple-gateways-multiple-routes.in.yaml | 100 ++++++ ...multiple-gateways-multiple-routes.out.yaml | 287 ++++++++++++++++++ 2 files changed, 387 insertions(+) create mode 100644 internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.in.yaml create mode 100755 internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.out.yaml diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.in.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.in.yaml new file mode 100644 index 00000000000..b27cb048db7 --- /dev/null +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.in.yaml @@ -0,0 +1,100 @@ +envoyproxy: + apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + namespace: envoy-gateway-system + name: test + spec: + mergeGateways: true +gateways: +- apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + protocol: HTTP + port: 80 + hostname: "*.envoyproxy.io" + allowedRoutes: + namespaces: + from: All +- apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + name: gateway-2 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http-2 + port: 8888 + protocol: HTTP + - name: http-3 + hostname: example.com + port: 8888 + protocol: HTTP + allowedRoutes: + namespaces: + from: All +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1beta1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: http + rules: + - matches: + - path: + value: "/" + backendRefs: + - name: service-1 + port: 8080 + filters: + - type: ExtensionRef + extensionRef: + group: gateway.envoyproxy.io + kind: AuthenticationFilter + name: test +- apiVersion: gateway.networking.k8s.io/v1beta1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-2 + spec: + hostnames: + - example.com + parentRefs: + - namespace: envoy-gateway + name: gateway-2 + sectionName: http-3 + rules: + - matches: + - path: + value: "/" + backendRefs: + - name: service-2 + port: 8080 +authenticationFilters: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: AuthenticationFilter + metadata: + namespace: default + name: test + spec: + type: JWT + jwtProviders: + - name: test + issuer: https://www.test.local + remoteJWKS: + uri: https://test.local/jwt/public-key/jwks.json diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.out.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.out.yaml new file mode 100755 index 00000000000..1553eb03cae --- /dev/null +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.out.yaml @@ -0,0 +1,287 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + hostname: '*.envoyproxy.io' + name: http + port: 80 + protocol: HTTP + 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: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +- apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-2 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http-2 + port: 8888 + protocol: HTTP + - allowedRoutes: + namespaces: + from: All + hostname: example.com + name: http-3 + port: 8888 + protocol: HTTP + status: + listeners: + - attachedRoutes: 0 + 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: http-3 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1beta1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-1 + namespace: default + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - name: service-1 + port: 8080 + filters: + - extensionRef: + group: gateway.envoyproxy.io + kind: AuthenticationFilter + name: test + type: ExtensionRef + matches: + - path: + value: / + 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 + sectionName: http +- apiVersion: gateway.networking.k8s.io/v1beta1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-2 + namespace: default + spec: + hostnames: + - example.com + parentRefs: + - name: gateway-2 + namespace: envoy-gateway + sectionName: http-3 + rules: + - backendRefs: + - name: service-2 + port: 8080 + matches: + - path: + value: / + 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-2 + namespace: envoy-gateway + sectionName: http-3 +infraIR: + envoy-gateway-class: + proxy: + config: + apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + creationTimestamp: null + name: test + namespace: envoy-gateway-system + spec: + logging: {} + mergeGateways: true + telemetry: {} + status: {} + listeners: + - address: "" + ports: + - containerPort: 10080 + name: envoy-gateway/gateway-1/http + protocol: HTTP + servicePort: 80 + - containerPort: 8888 + name: envoy-gateway/gateway-2/http-2 + protocol: HTTP + servicePort: 8888 + metadata: + labels: + gateway.envoyproxy.io/owning-gatewayclass: envoy-gateway-class + name: envoy-gateway-class +xdsIR: + envoy-gateway-class: + accessLog: + text: + - path: /dev/stdout + http: + - address: 0.0.0.0 + hostnames: + - '*.envoyproxy.io' + isHTTP2: false + name: envoy-gateway/gateway-1/http + port: 10080 + routes: + - backendWeights: + invalid: 0 + valid: 0 + destination: + name: httproute/default/httproute-1/rule/0 + settings: + - endpoints: + - host: 7.7.7.7 + port: 8080 + weight: 1 + hostname: gateway.envoyproxy.io + name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io + pathMatch: + distinct: false + name: "" + prefix: / + requestAuthentication: + jwt: + providers: + - issuer: https://www.test.local + name: test + remoteJWKS: + uri: https://test.local/jwt/public-key/jwks.json + - address: 0.0.0.0 + hostnames: + - '*' + isHTTP2: false + name: envoy-gateway/gateway-2/http-2 + port: 8888 + - address: 0.0.0.0 + hostnames: + - example.com + isHTTP2: false + name: envoy-gateway/gateway-2/http-3 + port: 8888 + routes: + - backendWeights: + invalid: 0 + valid: 0 + destination: + name: httproute/default/httproute-2/rule/0 + settings: + - endpoints: + - host: 7.7.7.7 + port: 8080 + weight: 1 + hostname: example.com + name: httproute/default/httproute-2/rule/0/match/0/example_com + pathMatch: + distinct: false + name: "" + prefix: / From f593c80f9305465326301cc7a2b741206255c27f Mon Sep 17 00:00:00 2001 From: Karol Szwaj Date: Thu, 19 Oct 2023 14:18:04 +0200 Subject: [PATCH 16/16] move to gwv1api Signed-off-by: Karol Szwaj --- .../merge-invalid-multiple-gateways.out.yaml | 2 ++ ...-multiple-gateways-multiple-routes.in.yaml | 20 +++++++++---------- ...multiple-gateways-multiple-routes.out.yaml | 2 ++ .../merge-valid-multiple-gateways.out.yaml | 2 ++ internal/gatewayapi/translator.go | 2 +- internal/gatewayapi/validate.go | 6 +++--- internal/provider/kubernetes/controller.go | 15 +++++++------- internal/provider/kubernetes/helpers.go | 2 +- internal/provider/kubernetes/predicates.go | 4 ++-- 9 files changed, 31 insertions(+), 24 deletions(-) diff --git a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml index f97cf5e4b11..93775aaf5f7 100755 --- a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml @@ -7,6 +7,7 @@ gateways: namespace: envoy-gateway spec: gatewayClassName: envoy-gateway-class + infrastructure: {} listeners: - name: http port: 80 @@ -44,6 +45,7 @@ gateways: namespace: envoy-gateway spec: gatewayClassName: envoy-gateway-class + infrastructure: {} listeners: - name: http port: 80 diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.in.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.in.yaml index b27cb048db7..aeca411f058 100644 --- a/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.in.yaml +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.in.yaml @@ -30,16 +30,16 @@ gateways: spec: gatewayClassName: envoy-gateway-class listeners: - - name: http-2 - port: 8888 - protocol: HTTP - - name: http-3 - hostname: example.com - port: 8888 - protocol: HTTP - allowedRoutes: - namespaces: - from: All + - name: http-2 + port: 8888 + protocol: HTTP + - name: http-3 + hostname: example.com + port: 8888 + protocol: HTTP + allowedRoutes: + namespaces: + from: All httpRoutes: - apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.out.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.out.yaml index 1553eb03cae..aebb2aff709 100755 --- a/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.out.yaml +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways-multiple-routes.out.yaml @@ -7,6 +7,7 @@ gateways: namespace: envoy-gateway spec: gatewayClassName: envoy-gateway-class + infrastructure: {} listeners: - allowedRoutes: namespaces: @@ -48,6 +49,7 @@ gateways: namespace: envoy-gateway spec: gatewayClassName: envoy-gateway-class + infrastructure: {} listeners: - name: http-2 port: 8888 diff --git a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml index 48043d99bf7..bd4578160a6 100755 --- a/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-valid-multiple-gateways.out.yaml @@ -7,6 +7,7 @@ gateways: namespace: envoy-gateway spec: gatewayClassName: envoy-gateway-class + infrastructure: {} listeners: - allowedRoutes: namespaces: @@ -47,6 +48,7 @@ gateways: namespace: envoy-gateway spec: gatewayClassName: envoy-gateway-class + infrastructure: {} listeners: - allowedRoutes: namespaces: diff --git a/internal/gatewayapi/translator.go b/internal/gatewayapi/translator.go index 4e925e9d424..35bb6cc3fec 100644 --- a/internal/gatewayapi/translator.go +++ b/internal/gatewayapi/translator.go @@ -219,7 +219,7 @@ func (t *Translator) InitIRs(gateways []*GatewayContext, resources *Resources) ( } // XdsIR and InfraIR map keys by default are {GatewayNamespace}/{GatewayName}, but if mergeGateways is set, they are merged under {GatewayClassName} key. -func (t *Translator) getIRKey(gateway *v1beta1.Gateway) string { +func (t *Translator) getIRKey(gateway *gwapiv1.Gateway) string { irKey := irStringKey(gateway.Namespace, gateway.Name) if t.MergeGateways { return string(t.GatewayClassName) diff --git a/internal/gatewayapi/validate.go b/internal/gatewayapi/validate.go index 8f8264d2aeb..1ada34033a0 100644 --- a/internal/gatewayapi/validate.go +++ b/internal/gatewayapi/validate.go @@ -538,16 +538,16 @@ func (t *Translator) validateConflictedMergedListeners(gateways []*GatewayContex listenerSets := sets.Set[string]{} for _, gateway := range gateways { for _, listener := range gateway.listeners { - hostname := new(v1beta1.Hostname) + hostname := new(gwapiv1.Hostname) if listener.Hostname != nil { hostname = listener.Hostname } portProtocolHostname := fmt.Sprintf("%s:%s:%d", listener.Protocol, *hostname, listener.Port) if listenerSets.Has(portProtocolHostname) { listener.SetCondition( - v1beta1.ListenerConditionConflicted, + gwapiv1.ListenerConditionConflicted, metav1.ConditionTrue, - v1beta1.ListenerReasonHostnameConflict, + gwapiv1.ListenerReasonHostnameConflict, "Port, protocol and hostname tuple must be unique for every listener", ) } diff --git a/internal/provider/kubernetes/controller.go b/internal/provider/kubernetes/controller.go index 7bee0e914b6..6798aa026d6 100644 --- a/internal/provider/kubernetes/controller.go +++ b/internal/provider/kubernetes/controller.go @@ -70,6 +70,7 @@ type gatewayAPIReconciler struct { namespace string namespaceLabels []string envoyGateway *egv1a1.EnvoyGateway + mergeGateways bool resources *message.ProviderResources extGVKs []schema.GroupVersionKind @@ -334,6 +335,10 @@ func (r *gatewayAPIReconciler) Reconcile(ctx context.Context, _ reconcile.Reques } } + if resourceTree.EnvoyProxy != nil && resourceTree.EnvoyProxy.Spec.MergeGateways != nil { + r.mergeGateways = *resourceTree.EnvoyProxy.Spec.MergeGateways + } + if err := r.gatewayClassUpdater(ctx, acceptedGC, true, string(gwapiv1.GatewayClassReasonAccepted), status.MsgValidGatewayClass); err != nil { r.log.Error(err, "unable to update GatewayClass status") return reconcile.Result{}, err @@ -407,20 +412,16 @@ func (r *gatewayAPIReconciler) statusUpdateForGateway(ctx context.Context, gtw * if r.statusUpdater == nil { return } - var merged bool - res, _ := r.resources.GatewayAPIResources.Load(string(gtw.Spec.GatewayClassName)) - if res.EnvoyProxy != nil && res.EnvoyProxy.Spec.MergeGateways != nil && *res.EnvoyProxy.Spec.MergeGateways { - merged = true - } + // Get deployment - deploy, err := r.envoyDeploymentForGateway(ctx, gtw, merged) + deploy, err := r.envoyDeploymentForGateway(ctx, gtw) if err != nil { r.log.Info("failed to get Deployment for gateway", "namespace", gtw.Namespace, "name", gtw.Name) } // Get service - svc, err := r.envoyServiceForGateway(ctx, gtw, merged) + svc, err := r.envoyServiceForGateway(ctx, gtw) if err != nil { r.log.Info("failed to get Service for gateway", "namespace", gtw.Namespace, "name", gtw.Name) diff --git a/internal/provider/kubernetes/helpers.go b/internal/provider/kubernetes/helpers.go index 3b93f728ef2..04bf83fecba 100644 --- a/internal/provider/kubernetes/helpers.go +++ b/internal/provider/kubernetes/helpers.go @@ -199,7 +199,7 @@ func refsSecret(ref *gwapiv1.SecretObjectReference) bool { // infraName returns expected name for the EnvoyProxy infra resources. // By default it returns hashed string from {GatewayNamespace}/{GatewayName}, // but if mergeGateways is set, it will return hashed string of {GatewayClassName}. -func infraName(gateway *gwapiv1b1.Gateway, merged bool) string { +func infraName(gateway *gwapiv1.Gateway, merged bool) string { if merged { return proxy.ExpectedResourceHashedName(string(gateway.Spec.GatewayClassName)) } diff --git a/internal/provider/kubernetes/predicates.go b/internal/provider/kubernetes/predicates.go index 23f96bd4922..b24872447d4 100644 --- a/internal/provider/kubernetes/predicates.go +++ b/internal/provider/kubernetes/predicates.go @@ -398,7 +398,7 @@ func (r *gatewayAPIReconciler) filterHTTPRoutesByNamespaceLabels(httpRoutes []gw } // envoyDeploymentForGateway returns the Envoy Deployment, returning nil if the Deployment doesn't exist. -func (r *gatewayAPIReconciler) envoyDeploymentForGateway(ctx context.Context, gateway *gwapiv1b1.Gateway) (*appsv1.Deployment, error) { +func (r *gatewayAPIReconciler) envoyDeploymentForGateway(ctx context.Context, gateway *gwapiv1.Gateway) (*appsv1.Deployment, error) { key := types.NamespacedName{ Namespace: r.namespace, Name: infraName(gateway, r.mergeGateways), @@ -414,7 +414,7 @@ func (r *gatewayAPIReconciler) envoyDeploymentForGateway(ctx context.Context, ga } // envoyServiceForGateway returns the Envoy service, returning nil if the service doesn't exist. -func (r *gatewayAPIReconciler) envoyServiceForGateway(ctx context.Context, gateway *gwapiv1b1.Gateway) (*corev1.Service, error) { +func (r *gatewayAPIReconciler) envoyServiceForGateway(ctx context.Context, gateway *gwapiv1.Gateway) (*corev1.Service, error) { key := types.NamespacedName{ Namespace: r.namespace, Name: infraName(gateway, r.mergeGateways),