From 2ecc54da663dc10c9257a61843cd14ba1bb77dcc Mon Sep 17 00:00:00 2001 From: Tanuj Dwivedi Date: Fri, 13 Oct 2023 08:59:08 +0530 Subject: [PATCH] Endpoint Slice support for ServiceImport (#1947) * Endpoint Slice support for ServiceImport Signed-off-by: tanujd11 * addressed review comments Signed-off-by: tanujd11 --------- Signed-off-by: tanujd11 --- internal/gatewayapi/resource.go | 11 ++- internal/gatewayapi/route.go | 74 ++++++++++++------- ...ener-with-serviceimport-backendref.in.yaml | 20 +++++ ...ner-with-serviceimport-backendref.out.yaml | 2 +- ...ther-namespace-allowed-by-refgrant.in.yaml | 20 +++++ ...her-namespace-allowed-by-refgrant.out.yaml | 2 +- 6 files changed, 98 insertions(+), 31 deletions(-) diff --git a/internal/gatewayapi/resource.go b/internal/gatewayapi/resource.go index b27e78614dc..15a87de6bac 100644 --- a/internal/gatewayapi/resource.go +++ b/internal/gatewayapi/resource.go @@ -106,11 +106,18 @@ func (r *Resources) GetSecret(namespace, name string) *v1.Secret { return nil } -func (r *Resources) GetEndpointSlicesForService(svcNamespace, svcName string) []*discoveryv1.EndpointSlice { +func (r *Resources) GetEndpointSlicesForBackend(svcNamespace, svcName string, backendKind string) []*discoveryv1.EndpointSlice { endpointSlices := []*discoveryv1.EndpointSlice{} for _, endpointSlice := range r.EndpointSlices { + var backendSelectorLabel string + switch backendKind { + case KindService: + backendSelectorLabel = discoveryv1.LabelServiceName + case KindServiceImport: + backendSelectorLabel = mcsapi.LabelServiceName + } if svcNamespace == endpointSlice.Namespace && - endpointSlice.GetLabels()[discoveryv1.LabelServiceName] == svcName { + endpointSlice.GetLabels()[backendSelectorLabel] == svcName { endpointSlices = append(endpointSlices, endpointSlice) } } diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index 1873ac7cd4f..ee8f45d7037 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -11,9 +11,11 @@ import ( "time" corev1 "k8s.io/api/core/v1" + v1 "k8s.io/api/discovery/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/gateway-api/apis/v1alpha2" "sigs.k8s.io/gateway-api/apis/v1beta1" + mcsapi "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1" "github.com/envoyproxy/gateway/internal/ir" "github.com/envoyproxy/gateway/internal/utils/ptr" @@ -1009,14 +1011,26 @@ func (t *Translator) processDestination(backendRef v1beta1.BackendRef, var endpoints []*ir.DestinationEndpoint switch KindDerefOr(backendRef.Kind, KindService) { - // TODO: Use EndpointSlice for ServiceImport case KindServiceImport: - backendIps := resources.GetServiceImport(backendNamespace, string(backendRef.Name)).Spec.IPs - for _, ip := range backendIps { - ep := ir.NewDestEndpoint( - ip, - uint32(*backendRef.Port)) - endpoints = append(endpoints, ep) + serviceImport := resources.GetServiceImport(backendNamespace, string(backendRef.Name)) + var servicePort mcsapi.ServicePort + for _, port := range serviceImport.Spec.Ports { + if port.Port == int32(*backendRef.Port) { + servicePort = port + break + } + } + if !t.EndpointRoutingDisabled { + endpointSlices := resources.GetEndpointSlicesForBackend(backendNamespace, string(backendRef.Name), KindDerefOr(backendRef.Kind, KindService)) + endpoints = getIREndpointsFromEndpointSlice(endpointSlices, servicePort.Name, servicePort.Protocol) + } else { + backendIps := resources.GetServiceImport(backendNamespace, string(backendRef.Name)).Spec.IPs + for _, ip := range backendIps { + ep := ir.NewDestEndpoint( + ip, + uint32(*backendRef.Port)) + endpoints = append(endpoints, ep) + } } case KindService: service := resources.GetService(backendNamespace, string(backendRef.Name)) @@ -1030,26 +1044,8 @@ func (t *Translator) processDestination(backendRef v1beta1.BackendRef, // Route to endpoints by default if !t.EndpointRoutingDisabled { - endpointSlices := resources.GetEndpointSlicesForService(backendNamespace, string(backendRef.Name)) - - for _, endpointSlice := range endpointSlices { - for _, endpoint := range endpointSlice.Endpoints { - for _, endpointPort := range endpointSlice.Ports { - // Check if the endpoint port matches the service port - // and if endpoint is Ready - if *endpointPort.Name == servicePort.Name && - *endpointPort.Protocol == servicePort.Protocol && - *endpoint.Conditions.Ready { - for _, address := range endpoint.Addresses { - ep := ir.NewDestEndpoint( - address, - uint32(servicePort.TargetPort.IntVal)) - endpoints = append(endpoints, ep) - } - } - } - } - } + endpointSlices := resources.GetEndpointSlicesForBackend(backendNamespace, string(backendRef.Name), KindDerefOr(backendRef.Kind, KindService)) + endpoints = getIREndpointsFromEndpointSlice(endpointSlices, servicePort.Name, servicePort.Protocol) } else { // Fall back to Service CluserIP routing ep := ir.NewDestEndpoint( @@ -1135,3 +1131,27 @@ func (t *Translator) processAllowedListenersForParentRefs(routeContext RouteCont } return relevantRoute } + +func getIREndpointsFromEndpointSlice(endpointSlices []*v1.EndpointSlice, portName string, portProtocol corev1.Protocol) []*ir.DestinationEndpoint { + endpoints := []*ir.DestinationEndpoint{} + for _, endpointSlice := range endpointSlices { + for _, endpoint := range endpointSlice.Endpoints { + for _, endpointPort := range endpointSlice.Ports { + // Check if the endpoint port matches the service port + // and if endpoint is Ready + if *endpointPort.Name == portName && + *endpointPort.Protocol == portProtocol && + *endpoint.Conditions.Ready { + for _, address := range endpoint.Addresses { + ep := ir.NewDestEndpoint( + address, + uint32(*endpointPort.Port)) + endpoints = append(endpoints, ep) + } + } + } + } + } + + return endpoints +} diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-serviceimport-backendref.in.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-serviceimport-backendref.in.yaml index 96c2a37b982..b090ab618b4 100644 --- a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-serviceimport-backendref.in.yaml +++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-serviceimport-backendref.in.yaml @@ -44,3 +44,23 @@ serviceImports: - 7.7.7.7 ports: - port: 8080 + name: http + protocol: TCP +endpointSlices: + - apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + name: service-import-1 + namespace: default + labels: + multicluster.kubernetes.io/service-name: service-import-1 + addressType: IPv4 + ports: + - name: http + protocol: TCP + port: 8080 + endpoints: + - addresses: + - "8.8.8.8" + conditions: + ready: true diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-serviceimport-backendref.out.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-serviceimport-backendref.out.yaml index 28662768177..4f007fcb909 100644 --- a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-serviceimport-backendref.out.yaml +++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-serviceimport-backendref.out.yaml @@ -113,7 +113,7 @@ xdsIR: name: httproute/default/httproute-1/rule/0 settings: - endpoints: - - host: 7.7.7.7 + - host: 8.8.8.8 port: 8080 weight: 1 hostname: '*' diff --git a/internal/gatewayapi/testdata/httproute-with-backendref-serviceimport-in-other-namespace-allowed-by-refgrant.in.yaml b/internal/gatewayapi/testdata/httproute-with-backendref-serviceimport-in-other-namespace-allowed-by-refgrant.in.yaml index d0cc7bab69d..ba04517a1f6 100644 --- a/internal/gatewayapi/testdata/httproute-with-backendref-serviceimport-in-other-namespace-allowed-by-refgrant.in.yaml +++ b/internal/gatewayapi/testdata/httproute-with-backendref-serviceimport-in-other-namespace-allowed-by-refgrant.in.yaml @@ -45,6 +45,26 @@ serviceImports: - 7.7.7.7 ports: - port: 8080 + name: http + protocol: TCP +endpointSlices: + - apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + name: service-import-1 + namespace: backends + labels: + multicluster.kubernetes.io/service-name: service-import-1 + addressType: IPv4 + ports: + - name: http + protocol: TCP + port: 8080 + endpoints: + - addresses: + - "8.8.8.8" + conditions: + ready: true referenceGrants: - apiVersion: gateway.networking.k8s.io/v1alpha2 kind: ReferenceGrant diff --git a/internal/gatewayapi/testdata/httproute-with-backendref-serviceimport-in-other-namespace-allowed-by-refgrant.out.yaml b/internal/gatewayapi/testdata/httproute-with-backendref-serviceimport-in-other-namespace-allowed-by-refgrant.out.yaml index 7e86c1bef82..1e063589383 100644 --- a/internal/gatewayapi/testdata/httproute-with-backendref-serviceimport-in-other-namespace-allowed-by-refgrant.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-backendref-serviceimport-in-other-namespace-allowed-by-refgrant.out.yaml @@ -113,7 +113,7 @@ xdsIR: name: httproute/default/httproute-1/rule/0 settings: - endpoints: - - host: 7.7.7.7 + - host: 8.8.8.8 port: 8080 weight: 1 hostname: '*'