From e792359a1ce80722d38a16fdbfbe91c916edffc9 Mon Sep 17 00:00:00 2001 From: Steve Kriss Date: Tue, 10 Jan 2023 16:15:05 -0700 Subject: [PATCH] implement parent ref port matching when specified When port is specified in a parentRef, only select listeners if they have a matching port, and set conditions appropriately if not. Closes #784. Signed-off-by: Steve Kriss --- internal/gatewayapi/helpers.go | 2 +- internal/gatewayapi/route.go | 10 ++ ...ttaching-to-listener-matching-port.in.yaml | 34 +++++++ ...taching-to-listener-matching-port.out.yaml | 91 +++++++++++++++++++ ...hing-to-listener-non-matching-port.in.yaml | 34 +++++++ ...ing-to-listener-non-matching-port.out.yaml | 82 +++++++++++++++++ test/conformance/conformance_test.go | 2 + 7 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 internal/gatewayapi/testdata/httproute-attaching-to-listener-matching-port.in.yaml create mode 100644 internal/gatewayapi/testdata/httproute-attaching-to-listener-matching-port.out.yaml create mode 100644 internal/gatewayapi/testdata/httproute-not-attaching-to-listener-non-matching-port.in.yaml create mode 100644 internal/gatewayapi/testdata/httproute-not-attaching-to-listener-non-matching-port.out.yaml diff --git a/internal/gatewayapi/helpers.go b/internal/gatewayapi/helpers.go index d405899f6d..17a42d749c 100644 --- a/internal/gatewayapi/helpers.go +++ b/internal/gatewayapi/helpers.go @@ -159,7 +159,7 @@ func GetReferencedListeners(parentRef v1beta1.ParentReference, gateways []*Gatew // The parentRef may be to the entire Gateway, or to a specific listener. for _, listener := range gateway.listeners { - if parentRef.SectionName == nil || *parentRef.SectionName == listener.Name { + if (parentRef.SectionName == nil || *parentRef.SectionName == listener.Name) && (parentRef.Port == nil || *parentRef.Port == listener.Port) { referencedListeners = append(referencedListeners, listener) } } diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index 7f263567aa..45b5c691d6 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -714,6 +714,16 @@ func (t *Translator) processAllowedListenersForParentRefs(routeContext RouteCont // Reset conditions since they will be recomputed during translation parentRefCtx.ResetConditions(routeContext) + if len(selectedListeners) == 0 { + parentRefCtx.SetCondition(routeContext, + v1beta1.RouteConditionAccepted, + metav1.ConditionFalse, + v1beta1.RouteReasonNoMatchingParent, + "No listeners match this parent ref", + ) + continue + } + if !HasReadyListener(selectedListeners) { parentRefCtx.SetCondition(routeContext, v1beta1.RouteConditionAccepted, diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-matching-port.in.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-matching-port.in.yaml new file mode 100644 index 0000000000..b40ea29ee4 --- /dev/null +++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-matching-port.in.yaml @@ -0,0 +1,34 @@ +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 + allowedRoutes: + namespaces: + from: All +httpRoutes: + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: http + port: 80 + rules: + - matches: + - path: + value: "/" + backendRefs: + - name: service-1 + port: 8080 diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-matching-port.out.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-matching-port.out.yaml new file mode 100644 index 0000000000..fe01d51875 --- /dev/null +++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-matching-port.out.yaml @@ -0,0 +1,91 @@ +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 + allowedRoutes: + namespaces: + from: All + status: + listeners: + - name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + attachedRoutes: 1 + conditions: + - type: Programmed + status: "True" + reason: Programmed + message: Listener is ready +httpRoutes: + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: http + port: 80 + rules: + - matches: + - path: + value: "/" + backendRefs: + - name: service-1 + port: 8080 + status: + parents: + - parentRef: + namespace: envoy-gateway + name: gateway-1 + sectionName: http + port: 80 + controllerName: gateway.envoyproxy.io/gatewayclass-controller + conditions: + - type: Accepted + status: "True" + reason: Accepted + message: Route is accepted +xdsIR: + envoy-gateway-gateway-1: + http: + - name: envoy-gateway-gateway-1-http + address: 0.0.0.0 + port: 10080 + hostnames: + - "*" + routes: + - name: default-httproute-1-rule-0-match-0-* + pathMatch: + prefix: "/" + destinations: + - host: 7.7.7.7 + port: 8080 + weight: 1 +infraIR: + envoy-gateway-gateway-1: + proxy: + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + name: envoy-gateway-gateway-1 + image: envoyproxy/envoy:translator-tests + listeners: + - address: "" + ports: + - name: http + protocol: "HTTP" + servicePort: 80 + containerPort: 10080 diff --git a/internal/gatewayapi/testdata/httproute-not-attaching-to-listener-non-matching-port.in.yaml b/internal/gatewayapi/testdata/httproute-not-attaching-to-listener-non-matching-port.in.yaml new file mode 100644 index 0000000000..42d894b263 --- /dev/null +++ b/internal/gatewayapi/testdata/httproute-not-attaching-to-listener-non-matching-port.in.yaml @@ -0,0 +1,34 @@ +gateways: + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http-1 + protocol: HTTP + port: 80 + hostname: foo.com + allowedRoutes: + namespaces: + from: All +httpRoutes: + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + port: 81 + rules: + - matches: + - path: + value: "/" + backendRefs: + - name: service-1 + port: 8080 diff --git a/internal/gatewayapi/testdata/httproute-not-attaching-to-listener-non-matching-port.out.yaml b/internal/gatewayapi/testdata/httproute-not-attaching-to-listener-non-matching-port.out.yaml new file mode 100644 index 0000000000..1bc596244e --- /dev/null +++ b/internal/gatewayapi/testdata/httproute-not-attaching-to-listener-non-matching-port.out.yaml @@ -0,0 +1,82 @@ +gateways: + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http-1 + protocol: HTTP + port: 80 + hostname: foo.com + allowedRoutes: + namespaces: + from: All + status: + listeners: + - name: http-1 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + attachedRoutes: 0 + conditions: + - type: Programmed + status: "True" + reason: Programmed + message: Listener is ready +httpRoutes: + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + port: 81 + rules: + - matches: + - path: + value: "/" + backendRefs: + - name: service-1 + port: 8080 + status: + parents: + - parentRef: + namespace: envoy-gateway + name: gateway-1 + port: 81 + controllerName: gateway.envoyproxy.io/gatewayclass-controller + conditions: + - type: Accepted + status: "False" + reason: NoMatchingParent + message: No listeners match this parent ref +xdsIR: + envoy-gateway-gateway-1: + http: + - name: envoy-gateway-gateway-1-http-1 + address: 0.0.0.0 + port: 10080 + hostnames: + - foo.com +infraIR: + envoy-gateway-gateway-1: + proxy: + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + name: envoy-gateway-gateway-1 + image: envoyproxy/envoy:translator-tests + listeners: + - address: "" + ports: + - name: http-1 + protocol: "HTTP" + servicePort: 80 + containerPort: 10080 diff --git a/test/conformance/conformance_test.go b/test/conformance/conformance_test.go index 1bc4cce1f6..f08cff7975 100644 --- a/test/conformance/conformance_test.go +++ b/test/conformance/conformance_test.go @@ -58,6 +58,7 @@ func TestGatewayAPIConformance(t *testing.T) { suite.SupportReferenceGrant: true, suite.SupportHTTPResponseHeaderModification: true, suite.SupportHTTPRouteMethodMatching: true, + suite.SupportRouteDestinationPortMatching: true, }, }) cSuite.Setup(t) @@ -85,6 +86,7 @@ func TestGatewayAPIConformance(t *testing.T) { tests.GatewayInvalidRouteKind, tests.HTTPRouteReferenceGrant, tests.HTTPRoutePartiallyInvalidViaInvalidReferenceGrant, + tests.HTTPRouteInvalidParentRefNotMatchingListenerPort, } cSuite.Run(t, egTests)