From 1042d0fc62df98b669ee40ca7ecf1ef1dce94fcf Mon Sep 17 00:00:00 2001 From: Alexander Yastrebov Date: Thu, 8 Feb 2024 17:23:23 +0100 Subject: [PATCH] dataclients/kubernetes: add LoadEndpointAddresses Add LoadEndpointAddresses to cluster client. It is similar to caching dataclient GetEndpointAddresses. Signed-off-by: Alexander Yastrebov --- dataclients/kubernetes/clusterclient.go | 38 ++++++++++++++++++++++++ dataclients/kubernetes/endpointslices.go | 4 ++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/dataclients/kubernetes/clusterclient.go b/dataclients/kubernetes/clusterclient.go index 3b54ef1849..d3c28b8782 100644 --- a/dataclients/kubernetes/clusterclient.go +++ b/dataclients/kubernetes/clusterclient.go @@ -532,6 +532,10 @@ func (c *ClusterClient) loadEndpointSlices() (map[definitions.ResourceID]*skippe } log.Debugf("all endpointslices received: %d", len(endpointSlices.Items)) + return mapEndpointSlices(&endpointSlices), nil +} + +func mapEndpointSlices(endpointSlices *endpointSliceList) map[definitions.ResourceID]*skipperEndpointSlice { mapSlices := make(map[definitions.ResourceID][]*endpointSlice) for _, endpointSlice := range endpointSlices.Items { resID := endpointSlice.ToResourceID() // service resource ID @@ -585,6 +589,40 @@ func (c *ClusterClient) loadEndpointSlices() (map[definitions.ResourceID]*skippe result[resID].Endpoints = append(result[resID].Endpoints, o) } } + return result +} + +// LoadEndpointAddresses returns the list of all addresses for the given service using endpoints or endpointslices API. +func (c *ClusterClient) LoadEndpointAddresses(namespace, name string) ([]string, error) { + var result []string + if c.enableEndpointSlices { + url := fmt.Sprintf(EndpointSlicesNamespaceFmt, namespace) + + toLabelSelectorQuery(map[string]string{endpointSliceServiceNameLabel: name}) + + var endpointSlices endpointSliceList + if err := c.getJSON(url, &endpointSlices); err != nil { + return nil, fmt.Errorf("requesting endpointslices for %s/%s failed: %v", namespace, name, err) + } + + mapped := mapEndpointSlices(&endpointSlices) + if len(mapped) != 1 { + return nil, fmt.Errorf("unexpected number of endpoint slices for %s/%s: %d", namespace, name, len(mapped)) + } + + for _, eps := range mapped { + result = eps.addresses() + break + } + } else { + url := fmt.Sprintf(EndpointsNamespaceFmt, namespace) + "/" + name + + var ep endpoint + if err := c.getJSON(url, &ep); err != nil { + return nil, fmt.Errorf("requesting endpoints for %s/%s failed: %v", namespace, name, err) + } + result = ep.addresses() + } + sort.Strings(result) return result, nil } diff --git a/dataclients/kubernetes/endpointslices.go b/dataclients/kubernetes/endpointslices.go index 436c3e4a42..e91818c80b 100644 --- a/dataclients/kubernetes/endpointslices.go +++ b/dataclients/kubernetes/endpointslices.go @@ -4,6 +4,8 @@ import ( "github.com/zalando/skipper/dataclients/kubernetes/definitions" ) +const endpointSliceServiceNameLabel = "kubernetes.io/service-name" + // There are [1..N] Kubernetes endpointslices created for a single Kubernetes service. // Kubernetes endpointslices of a given service can have duplicates with different states. // Therefore Kubernetes endpointslices need to be de-duplicated before usage. @@ -97,7 +99,7 @@ type endpointSlice struct { // ToResourceID returns the same string for a group endpointlisces created for the same svc func (eps *endpointSlice) ToResourceID() definitions.ResourceID { - svcName := eps.Meta.Labels["kubernetes.io/service-name"] + svcName := eps.Meta.Labels[endpointSliceServiceNameLabel] namespace := eps.Meta.Namespace return newResourceID(namespace, svcName) }