@@ -13,9 +13,9 @@ import (
1313 "strings"
1414 "sync"
1515
16- pkgconfigsetup "github.com/DataDog/datadog-agent/pkg/config/setup"
1716 v1 "k8s.io/api/core/v1"
1817 discv1 "k8s.io/api/discovery/v1"
18+ "k8s.io/apimachinery/pkg/api/equality"
1919 "k8s.io/apimachinery/pkg/labels"
2020 listersv1 "k8s.io/client-go/listers/core/v1"
2121 disclisters "k8s.io/client-go/listers/discovery/v1"
@@ -26,13 +26,12 @@ import (
2626 "github.com/DataDog/datadog-agent/comp/core/autodiscovery/providers/names"
2727 "github.com/DataDog/datadog-agent/comp/core/autodiscovery/providers/types"
2828 "github.com/DataDog/datadog-agent/comp/core/autodiscovery/telemetry"
29- "github.com/DataDog/datadog-agent/pkg/config/model "
29+ pkgconfigsetup "github.com/DataDog/datadog-agent/pkg/config/setup "
3030 "github.com/DataDog/datadog-agent/pkg/util/kubernetes/apiserver"
3131 "github.com/DataDog/datadog-agent/pkg/util/log"
3232)
3333
3434const (
35- kubeEndpointSliceID = "endpointslices"
3635 kubeEndpointSliceAnnotationPrefix = "ad.datadoghq.com/endpoints."
3736 kubeEndpointSliceAnnotationPrefixLegacy = "service-discovery.datadoghq.com/endpoints."
3837 kubeEndpointSliceResolvePath = "resolve"
@@ -60,8 +59,8 @@ type configInfoSlices struct {
6059
6160// NewKubeEndpointSlicesConfigProvider returns a new ConfigProvider connected to apiserver using EndpointSlices.
6261// Connectivity is not checked at this stage to allow for retries, Collect will do it.
63- func NewKubeEndpointSlicesConfigProvider ( telemetryStore * telemetry. Store ) (types. ConfigProvider , error ) {
64- // Using GetAPIClient (no wait) as Client should already be initialized by Cluster Agent main entrypoint before
62+ // Using GetAPIClient (no wait) as Client should already be initialized by Cluster Agent main entrypoint before
63+ func NewKubeEndpointSlicesConfigProvider ( _ * pkgconfigsetup. ConfigurationProviders , telemetryStore * telemetry. Store ) (types. ConfigProvider , error ) {
6564 ac , err := apiserver .GetAPIClient ()
6665 if err != nil {
6766 return nil , fmt .Errorf ("cannot connect to apiserver: %s" , err )
@@ -100,12 +99,19 @@ func NewKubeEndpointSlicesConfigProvider(telemetryStore *telemetry.Store) (types
10099 return nil , fmt .Errorf ("cannot add event handler to endpointslice informer: %s" , err )
101100 }
102101
102+ if pkgconfigsetup .Datadog ().GetBool ("cluster_checks.support_hybrid_ignore_ad_tags" ) {
103+ log .Warnf ("The `cluster_checks.support_hybrid_ignore_ad_tags` flag is" +
104+ " deprecated and will be removed in a future version. Please replace " +
105+ "`ad.datadoghq.com/endpoints.ignore_autodiscovery_tags` in your service annotations" +
106+ "using adv2 for check specification and adv1 for `ignore_autodiscovery_tags`." )
107+ }
108+
103109 return p , nil
104110}
105111
106112// String returns a string representation of the kubeEndpointSlicesConfigProvider
107113func (k * kubeEndpointSlicesConfigProvider ) String () string {
108- return names .KubeEndpoints
114+ return names .KubeEndpointSlices
109115}
110116
111117// Collect retrieves services from the apiserver, builds Config objects and returns them
@@ -117,7 +123,7 @@ func (k *kubeEndpointSlicesConfigProvider) Collect(context.Context) ([]integrati
117123 k .setUpToDate (true )
118124
119125 var generatedConfigs []integration.Config
120- parsedConfigsInfo := k .parseServiceAnnotationsForEndpointSlices (services , pkgconfigsetup . Datadog () )
126+ parsedConfigsInfo := k .parseServiceAnnotationsForEndpointSlices (services )
121127 for _ , conf := range parsedConfigsInfo {
122128 // Fetch all EndpointSlices for this service
123129 slices , err := k .endpointSliceLister .EndpointSlices (conf .namespace ).List (
@@ -127,7 +133,10 @@ func (k *kubeEndpointSlicesConfigProvider) Collect(context.Context) ([]integrati
127133 log .Errorf ("Cannot get Kubernetes endpointslices: %s" , err )
128134 continue
129135 }
130- generatedConfigs = append (generatedConfigs , generateConfigsFromSlices (conf .tpl , conf .resolveMode , slices , conf .namespace , conf .serviceName )... )
136+ for _ , slice := range slices {
137+ generatedConfigs = append (generatedConfigs , generateConfigFromSlice (conf .tpl , conf .resolveMode , slice , conf .namespace , conf .serviceName )... )
138+ }
139+
131140 serviceKey := fmt .Sprintf ("%s/%s" , conf .namespace , conf .serviceName )
132141 k .Lock ()
133142 k .monitoredServices [serviceKey ] = true
@@ -192,7 +201,6 @@ func (k *kubeEndpointSlicesConfigProvider) invalidateOnServiceUpdate(old, obj in
192201 k .setUpToDate (false )
193202 return
194203 }
195- // Quick exit if resource version did not change
196204 if svc .ResourceVersion == oldSvc .ResourceVersion {
197205 return
198206 }
@@ -240,7 +248,6 @@ func (k *kubeEndpointSlicesConfigProvider) invalidateOnEndpointSliceUpdate(old,
240248 return
241249 }
242250
243- // Get service name from label
244251 serviceName := slice .Labels [kubernetesServiceNameLabelProvider ]
245252 if serviceName == "" {
246253 return
@@ -251,42 +258,18 @@ func (k *kubeEndpointSlicesConfigProvider) invalidateOnEndpointSliceUpdate(old,
251258 k .Lock ()
252259 defer k .Unlock ()
253260 if found := k .monitoredServices [serviceKey ]; found {
254- // Invalidate only when endpoints change
255- if endpointSliceEndpointsDifferProvider (slice , oldSlice ) {
256- k .upToDate = false
257- }
261+ k .upToDate = equality .Semantic .DeepEqual (slice .Endpoints , oldSlice .Endpoints )
258262 }
259263}
260264
261- // endpointSliceEndpointsDifferProvider compares the endpoints in two endpointslices
262- func endpointSliceEndpointsDifferProvider (first , second * discv1.EndpointSlice ) bool {
263- if len (first .Endpoints ) != len (second .Endpoints ) {
264- return true
265- }
266-
267- // Simple comparison - could be optimized with a more sophisticated diff
268- for i := range first .Endpoints {
269- if len (first .Endpoints [i ].Addresses ) != len (second .Endpoints [i ].Addresses ) {
270- return true
271- }
272- for j := range first .Endpoints [i ].Addresses {
273- if first .Endpoints [i ].Addresses [j ] != second .Endpoints [i ].Addresses [j ] {
274- return true
275- }
276- }
277- }
278-
279- return false
280- }
281-
282265// setUpToDate is a thread-safe method to update the upToDate value
283266func (k * kubeEndpointSlicesConfigProvider ) setUpToDate (v bool ) {
284267 k .Lock ()
285268 defer k .Unlock ()
286269 k .upToDate = v
287270}
288271
289- func (k * kubeEndpointSlicesConfigProvider ) parseServiceAnnotationsForEndpointSlices (services []* v1.Service , cfg model. Config ) []configInfoSlices {
272+ func (k * kubeEndpointSlicesConfigProvider ) parseServiceAnnotationsForEndpointSlices (services []* v1.Service ) []configInfoSlices {
290273 var configsInfo []configInfoSlices
291274
292275 setServiceKeys := map [string ]struct {}{}
@@ -300,7 +283,6 @@ func (k *kubeEndpointSlicesConfigProvider) parseServiceAnnotationsForEndpointSli
300283 serviceKey := fmt .Sprintf ("%s/%s" , svc .Namespace , svc .Name )
301284 setServiceKeys [serviceKey ] = struct {}{}
302285
303- // Use same annotation prefix as Endpoints for compatibility
304286 endptConf , errors := utils .ExtractTemplatesFromAnnotations (serviceKey , svc .GetAnnotations (), kubeEndpointID )
305287 for _ , err := range errors {
306288 log .Errorf ("Cannot parse endpoint template for service %s: %s" , serviceKey , err )
@@ -323,8 +305,9 @@ func (k *kubeEndpointSlicesConfigProvider) parseServiceAnnotationsForEndpointSli
323305
324306 ignoreAdForHybridScenariosTags := ignoreADTagsFromAnnotations (svc .GetAnnotations (), kubeEndpointSliceAnnotationPrefix )
325307 for i := range endptConf {
326- endptConf [i ].Source = "kube_endpointslices:" + serviceKey
327- if cfg .GetBool ("cluster_checks.support_hybrid_ignore_ad_tags" ) {
308+ // TODO: Kept same source for now, but we should consider using a different source.
309+ endptConf [i ].Source = "kube_endpoints:" + apiserver .EntityForEndpoints (svc .Namespace , svc .Name , "" )
310+ if pkgconfigsetup .Datadog ().GetBool ("cluster_checks.support_hybrid_ignore_ad_tags" ) {
328311 endptConf [i ].IgnoreAutodiscoveryTags = endptConf [i ].IgnoreAutodiscoveryTags || ignoreAdForHybridScenariosTags
329312 }
330313 configsInfo = append (configsInfo , configInfoSlices {
@@ -360,70 +343,59 @@ func hasEndpointSliceAnnotations(svc *v1.Service) bool {
360343 return false
361344}
362345
363- // generateConfigsFromSlices creates a config template for each endpoint IP across all slices
364- func generateConfigsFromSlices (tpl integration.Config , resolveMode endpointResolveMode , slices [] * discv1.EndpointSlice , namespace , serviceName string ) []integration.Config {
365- if len ( slices ) == 0 {
366- log .Warnf ("No EndpointSlices for service %s/%s, cannot generate config templates" , namespace , serviceName )
346+ // generateConfigFromSlice creates a config template for each endpoint IP across all slices
347+ func generateConfigFromSlice (tpl integration.Config , resolveMode endpointResolveMode , slice * discv1.EndpointSlice , namespace , serviceName string ) []integration.Config {
348+ if slice == nil {
349+ log .Warnf ("EndpointSlice for %s/%s is nil , cannot generate config templates" , namespace , serviceName )
367350 return []integration.Config {tpl }
368351 }
369352 generatedConfigs := make ([]integration.Config , 0 )
370353
371354 // Check resolve annotation to know how we should process this endpoint
372- resolveFunc := getEndpointResolveFuncForSlices (resolveMode , namespace , serviceName )
373-
374- for _ , slice := range slices {
375- for _ , endpoint := range slice .Endpoints {
376- for _ , ip := range endpoint .Addresses {
377- // Set a new entity containing the endpoint's IP
378- entity := apiserver .EntityForEndpoints (namespace , serviceName , ip )
379- newConfig := integration.Config {
380- ServiceID : entity ,
381- Name : tpl .Name ,
382- Instances : tpl .Instances ,
383- InitConfig : tpl .InitConfig ,
384- MetricConfig : tpl .MetricConfig ,
385- LogsConfig : tpl .LogsConfig ,
386- ADIdentifiers : []string {entity },
387- ClusterCheck : true ,
388- Provider : tpl .Provider ,
389- Source : tpl .Source ,
390- IgnoreAutodiscoveryTags : tpl .IgnoreAutodiscoveryTags ,
391- }
392-
393- if resolveFunc != nil {
394- resolveFunc (& newConfig , endpoint , ip )
395- }
396-
397- generatedConfigs = append (generatedConfigs , newConfig )
355+ resolveFunc := getEndpointResolveFuncForSlice (resolveMode , namespace , serviceName )
356+
357+ for _ , endpoint := range slice .Endpoints {
358+ for _ , ip := range endpoint .Addresses {
359+ // Set a new entity containing the endpoint's IP
360+ entity := apiserver .EntityForEndpoints (namespace , serviceName , ip )
361+ newConfig := integration.Config {
362+ ServiceID : entity ,
363+ Name : tpl .Name ,
364+ Instances : tpl .Instances ,
365+ InitConfig : tpl .InitConfig ,
366+ MetricConfig : tpl .MetricConfig ,
367+ LogsConfig : tpl .LogsConfig ,
368+ ADIdentifiers : []string {entity },
369+ ClusterCheck : true ,
370+ Provider : tpl .Provider ,
371+ Source : tpl .Source ,
372+ IgnoreAutodiscoveryTags : tpl .IgnoreAutodiscoveryTags ,
373+ }
374+
375+ if resolveFunc != nil {
376+ resolveFunc (& newConfig , endpoint )
398377 }
378+
379+ generatedConfigs = append (generatedConfigs , newConfig )
399380 }
400381 }
401382 return generatedConfigs
402383}
403384
404- // getEndpointResolveFuncForSlices returns a function that resolves the endpoint address for EndpointSlices
405- func getEndpointResolveFuncForSlices (resolveMode endpointResolveMode , namespace , name string ) func (* integration.Config , discv1.Endpoint , string ) {
406- var resolveFunc func (* integration.Config , discv1.Endpoint , string )
385+ // getEndpointResolveFuncForSlice returns a function that resolves the endpoint address for EndpointSlices
386+ func getEndpointResolveFuncForSlice (resolveMode endpointResolveMode , namespace , name string ) func (* integration.Config , discv1.Endpoint ) {
387+ var resolveFunc func (* integration.Config , discv1.Endpoint )
407388
408389 switch resolveMode {
409390 case kubeEndpointResolveIP :
410391 // IP: we explicitly ignore what's behind this address (nothing to do)
411392
412393 case "" , kubeEndpointResolveAuto :
413394 // Auto or empty (default to auto): we try to resolve the POD behind this address
414- resolveFunc = func (config * integration.Config , endpoint discv1.Endpoint , _ string ) {
415- if endpoint .TargetRef != nil && endpoint .TargetRef .Kind == "Pod" {
416- config .NodeName = endpoint .TargetRef .Name
417- }
418- }
419-
395+ resolveFunc = utils .ResolveEndpointSliceConfigAuto
420396 default :
421397 log .Warnf ("Unknown resolve mode %s for service %s/%s, defaulting to auto" , resolveMode , namespace , name )
422- resolveFunc = func (config * integration.Config , endpoint discv1.Endpoint , _ string ) {
423- if endpoint .TargetRef != nil && endpoint .TargetRef .Kind == "Pod" {
424- config .NodeName = endpoint .TargetRef .Name
425- }
426- }
398+ resolveFunc = utils .ResolveEndpointSliceConfigAuto
427399 }
428400
429401 return resolveFunc
0 commit comments