Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CONTP-567] Base impl static tag migration #32833

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,6 @@
/pkg/util/kubernetes/ @DataDog/container-integrations @DataDog/container-platform @DataDog/container-app
/pkg/util/podman/ @DataDog/container-integrations
/pkg/util/prometheus @DataDog/container-integrations
/pkg/util/tags/ @DataDog/container-platform
/pkg/util/trivy/ @DataDog/container-integrations @DataDog/agent-security
/pkg/util/uuid/ @DataDog/agent-shared-components
/pkg/util/cgroups/ @DataDog/container-integrations
Expand Down
43 changes: 12 additions & 31 deletions comp/core/tagger/collectors/workloadmeta_main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,14 @@ import (
"github.com/gobwas/glob"

"github.com/DataDog/datadog-agent/comp/core/config"
"github.com/DataDog/datadog-agent/comp/core/tagger/common"
k8smetadata "github.com/DataDog/datadog-agent/comp/core/tagger/k8s_metadata"
"github.com/DataDog/datadog-agent/comp/core/tagger/taglist"
"github.com/DataDog/datadog-agent/comp/core/tagger/types"
workloadmeta "github.com/DataDog/datadog-agent/comp/core/workloadmeta/def"
configutils "github.com/DataDog/datadog-agent/pkg/config/utils"
"github.com/DataDog/datadog-agent/pkg/status/health"
"github.com/DataDog/datadog-agent/pkg/util/flavor"
"github.com/DataDog/datadog-agent/pkg/util/kubernetes/clustername"
"github.com/DataDog/datadog-agent/pkg/util/log"
tagutil "github.com/DataDog/datadog-agent/pkg/util/tags"
)

const (
Expand All @@ -35,8 +33,6 @@ const (
processSource = workloadmetaCollectorName + "-" + string(workloadmeta.KindProcess)
kubeMetadataSource = workloadmetaCollectorName + "-" + string(workloadmeta.KindKubernetesMetadata)
deploymentSource = workloadmetaCollectorName + "-" + string(workloadmeta.KindKubernetesDeployment)

clusterTagNamePrefix = "kube_cluster_name"
)

// CollectorPriorities holds collector priorities
Expand Down Expand Up @@ -90,37 +86,17 @@ func (c *WorkloadMetaCollector) initK8sResourcesMetaAsTags(resourcesLabelsAsTags

// Run runs the continuous event watching loop and sends new tags to the
// tagger based on the events sent by the workloadmeta.
func (c *WorkloadMetaCollector) Run(ctx context.Context, datadogConfig config.Component) {
c.collectStaticGlobalTags(ctx, datadogConfig)
func (c *WorkloadMetaCollector) Run(ctx context.Context) {
c.stream(ctx)
}

func (c *WorkloadMetaCollector) collectStaticGlobalTags(ctx context.Context, datadogConfig config.Component) {
c.staticTags = tagutil.GetStaticTags(ctx, datadogConfig)
if _, exists := c.staticTags[clusterTagNamePrefix]; flavor.GetFlavor() == flavor.ClusterAgent && !exists {
// If we are running the cluster agent, we want to set the kube_cluster_name tag as a global tag if we are able
// to read it, for the instances where we are running in an environment where hostname cannot be detected.
if cluster := clustername.GetClusterNameTagValue(ctx, ""); cluster != "" {
if c.staticTags == nil {
c.staticTags = make(map[string][]string, 1)
}
if _, exists := c.staticTags[clusterTagNamePrefix]; !exists {
c.staticTags[clusterTagNamePrefix] = []string{}
}
c.staticTags[clusterTagNamePrefix] = append(c.staticTags[clusterTagNamePrefix], cluster)
}
}
// These are the global tags that should only be applied to the internal global entity on DCA.
// Whereas the static tags are applied to containers and pods directly as well.
globalEnvTags := tagutil.GetGlobalEnvTags(datadogConfig)
c.staticTags = common.GetStaticTags(ctx, datadogConfig)

tagList := taglist.NewTagList()

for _, tags := range []map[string][]string{c.staticTags, globalEnvTags} {
for tagKey, valueList := range tags {
for _, value := range valueList {
tagList.AddLow(tagKey, value)
}
for tagKey, valueList := range c.staticTags {
for _, value := range valueList {
tagList.AddLow(tagKey, value)
}
}

Expand Down Expand Up @@ -172,7 +148,7 @@ func (c *WorkloadMetaCollector) stream(ctx context.Context) {
}

// NewWorkloadMetaCollector returns a new WorkloadMetaCollector.
func NewWorkloadMetaCollector(_ context.Context, cfg config.Component, store workloadmeta.Component, p processor) *WorkloadMetaCollector {
func NewWorkloadMetaCollector(ctx context.Context, cfg config.Component, store workloadmeta.Component, p processor) *WorkloadMetaCollector {
c := &WorkloadMetaCollector{
tagProcessor: p,
store: store,
Expand All @@ -196,6 +172,11 @@ func NewWorkloadMetaCollector(_ context.Context, cfg config.Component, store wor
metadataAsTags := configutils.GetMetadataAsTags(cfg)
c.initK8sResourcesMetaAsTags(metadataAsTags.GetResourcesLabelsAsTags(), metadataAsTags.GetResourcesAnnotationsAsTags())

// initializes with the static global tags
if c.tagProcessor != nil {
c.collectStaticGlobalTags(ctx, cfg)
}

return c
}

Expand Down
92 changes: 92 additions & 0 deletions comp/core/tagger/common/static_tags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2024-present Datadog, Inc.

// Package common provides common utilities that are useful when interacting with the tagger.
package common

import (
"context"
"strings"

"github.com/DataDog/datadog-agent/comp/core/config"
"github.com/DataDog/datadog-agent/pkg/config/env"
configUtils "github.com/DataDog/datadog-agent/pkg/config/utils"
"github.com/DataDog/datadog-agent/pkg/util/fargate"
"github.com/DataDog/datadog-agent/pkg/util/flavor"
"github.com/DataDog/datadog-agent/pkg/util/kubernetes/clustername"
"github.com/DataDog/datadog-agent/pkg/util/log"
)

// GetStaticTags gets the "static tags" for this agent. These are tags
// that are attached directly to everything the agent produces, but _not_
// included in host tags. In environments with no host metadata (such as where
// the hostname is empty), tags that would otherwise be included in host
// metadata are generated by this function.
func GetStaticTags(ctx context.Context, datadogConfig config.Reader) map[string][]string {
tags := []string{}

if flavor.GetFlavor() == flavor.ClusterAgent {
// DD_CLUSTER_CHECKS_EXTRA_TAGS / DD_ORCHESTRATOR_EXPLORER_EXTRA_TAGS
tags = append(tags, configUtils.GetConfiguredDCATags(datadogConfig)...)
}

if flavor.GetFlavor() == flavor.ClusterAgent || fargate.IsFargateInstance() {
// Fargate (ECS/EKS) + Cluster Agent does not have host tag resolution so
// we must manually add the following tags that are typically host tags.

// DD_TAGS / DD_EXTRA_TAGS
tags = append(tags, configUtils.GetConfiguredTags(datadogConfig, false)...)

// kube_cluster_name
clusterTagNamePrefix := "kube_cluster_name:"
var tag string
var found bool
for _, tag = range tags {
if strings.HasPrefix(tag, clusterTagNamePrefix) {
found = true
break
}
}
if found {
log.Infof("'%s' was set manually via DD_TAGS, not changing it", clusterTagNamePrefix+tag)
} else {
cluster := clustername.GetClusterNameTagValue(ctx, "")
if cluster == "" {
log.Infof("Couldn't build the %q.. tag, DD_CLUSTER_NAME can be used to set it", clusterTagNamePrefix)
} else {
tags = append(tags, clusterTagNamePrefix+cluster)
}
}
}

// EKS Fargate specific tags
if env.IsFeaturePresent(env.EKSFargate) {
// eks_fargate_node
node, err := fargate.GetEKSFargateNodename()
if err != nil {
log.Infof("Couldn't build the 'eks_fargate_node' tag: %v", err)
} else {
tags = append(tags, "eks_fargate_node:"+node)
}
}

return ConvertTagSliceToMap(tags)
}

// ConvertTagSliceToMap converts a slice of tags to a map of tags
// eg. ["key1:value1", "key2:value2", "key1:value3"] -> {"key1": ["value1", "value3"], "key2": ["value2"]}
func ConvertTagSliceToMap(tags []string) map[string][]string {
tagsMap := make(map[string][]string)
for _, tag := range tags {
parts := strings.SplitN(tag, ":", 2)
if len(parts) != 2 {
continue
}
key := parts[0]
value := parts[1]
tagsMap[key] = append(tagsMap[key], value)
}
return tagsMap
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2022-present Datadog, Inc.

package tags
package common

import (
"context"
Expand Down Expand Up @@ -58,41 +58,6 @@ func TestStaticTags(t *testing.T) {
})
}

func TestStaticTagsSlice(t *testing.T) {
mockConfig := configmock.New(t)
mockConfig.SetWithoutSource("kubernetes_kubelet_nodename", "eksnode")
defer mockConfig.SetWithoutSource("kubernetes_kubelet_nodename", "")

env.SetFeatures(t, env.EKSFargate)

t.Run("just tags", func(t *testing.T) {
mockConfig.SetWithoutSource("tags", []string{"some:tag", "another:tag", "nocolon"})
defer mockConfig.SetWithoutSource("tags", []string{})
staticTags := GetStaticTagsSlice(context.Background(), mockConfig)
assert.ElementsMatch(t, []string{
"nocolon",
"some:tag",
"another:tag",
"eks_fargate_node:eksnode",
}, staticTags)
})

t.Run("tags and extra_tags", func(t *testing.T) {
mockConfig.SetWithoutSource("tags", []string{"some:tag", "nocolon"})
mockConfig.SetWithoutSource("extra_tags", []string{"extra:tag", "missingcolon"})
defer mockConfig.SetWithoutSource("tags", []string{})
defer mockConfig.SetWithoutSource("extra_tags", []string{})
staticTags := GetStaticTagsSlice(context.Background(), mockConfig)
assert.ElementsMatch(t, []string{
"nocolon",
"missingcolon",
"some:tag",
"extra:tag",
"eks_fargate_node:eksnode",
}, staticTags)
})
}

func TestExtraGlobalEnvTags(t *testing.T) {
mockConfig := configmock.New(t)
mockConfig.SetWithoutSource("tags", []string{"some:tag", "nocolon"})
Expand All @@ -107,13 +72,13 @@ func TestExtraGlobalEnvTags(t *testing.T) {

t.Run("Agent extraGlobalTags", func(t *testing.T) {
flavor.SetFlavor(flavor.DefaultAgent)
globalTags := GetGlobalEnvTags(mockConfig)
assert.Equal(t, map[string][]string(nil), globalTags)
globalTags := GetStaticTags(context.Background(), mockConfig)
assert.Equal(t, map[string][]string{}, globalTags)
})

t.Run("ClusterAgent extraGlobalTags", func(t *testing.T) {
flavor.SetFlavor(flavor.ClusterAgent)
globalTags := GetGlobalEnvTags(mockConfig)
globalTags := GetStaticTags(context.Background(), mockConfig)
assert.Equal(t, map[string][]string{
"some": {"tag"},
"extra": {"tag"},
Expand Down
2 changes: 1 addition & 1 deletion comp/core/tagger/impl/local_tagger.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func (t *localTagger) Start(ctx context.Context) error {
)

go t.tagStore.Run(t.ctx)
go t.collector.Run(t.ctx, t.cfg)
go t.collector.Run(t.ctx)

return nil
}
Expand Down
2 changes: 1 addition & 1 deletion comp/core/tagger/impl/tagger.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ func NewTaggerClient(params tagger.Params, cfg config.Component, wmeta workloadm
var err error
telemetryStore := telemetry.NewStore(telemetryComp)
if params.UseFakeTagger {
defaultTagger = taggermock.New().Comp
defaultTagger = taggermock.New(taggermock.Dependencies{Config: cfg}).Comp
} else {
defaultTagger, err = newLocalTagger(cfg, wmeta, telemetryStore)
}
Expand Down
24 changes: 17 additions & 7 deletions comp/core/tagger/mock/fake_tagger.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"context"
"strconv"

"github.com/DataDog/datadog-agent/comp/core/config"
"github.com/DataDog/datadog-agent/comp/core/tagger/collectors"
tagger "github.com/DataDog/datadog-agent/comp/core/tagger/def"
"github.com/DataDog/datadog-agent/comp/core/tagger/origindetection"
"github.com/DataDog/datadog-agent/comp/core/tagger/tagstore"
Expand All @@ -35,19 +37,27 @@ type FakeTagger struct {
store *tagstore.TagStore
}

// Provides is a struct containing the mock and the endpoint
// Dependencies is the mock dependencies for the tagger component
type Dependencies struct {
Config config.Component
}

// Provides is a struct containing the mock
type Provides struct {
Comp Mock
}

// New instantiates a new fake tagger
func New() Provides {
return Provides{
Comp: &FakeTagger{
errors: make(map[string]error),
store: tagstore.NewTagStore(nil),
},
func New(deps Dependencies) Provides {
fakeTagger := &FakeTagger{
errors: make(map[string]error),
store: tagstore.NewTagStore(nil),
}

// Initialize the fakeTagger similar to localTagger start()
_ = collectors.NewWorkloadMetaCollector(context.Background(), deps.Config, nil, fakeTagger.store)

return Provides{Comp: fakeTagger}
}

// SetTags allows to set tags in store for a given source, entity
Expand Down
6 changes: 5 additions & 1 deletion comp/core/tagger/mock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ package mock
import (
"testing"

"github.com/DataDog/datadog-agent/comp/core/config"
"github.com/DataDog/datadog-agent/pkg/util/fxutil"
)

Expand All @@ -23,5 +24,8 @@ func Module() fxutil.Module {

// SetupFakeTagger calls fxutil.Test to create a mock tagger for testing
func SetupFakeTagger(t testing.TB) Mock {
return fxutil.Test[Mock](t, Module())
return fxutil.Test[Mock](t,
config.MockModule(),
Module(),
)
}
14 changes: 9 additions & 5 deletions comp/dogstatsd/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
api "github.com/DataDog/datadog-agent/comp/api/api/def"
configComponent "github.com/DataDog/datadog-agent/comp/core/config"
log "github.com/DataDog/datadog-agent/comp/core/log/def"
tagger "github.com/DataDog/datadog-agent/comp/core/tagger/def"
"github.com/DataDog/datadog-agent/comp/core/tagger/types"
"github.com/DataDog/datadog-agent/comp/core/telemetry"
workloadmeta "github.com/DataDog/datadog-agent/comp/core/workloadmeta/def"
"github.com/DataDog/datadog-agent/comp/dogstatsd/listeners"
Expand All @@ -40,7 +42,6 @@ import (
"github.com/DataDog/datadog-agent/pkg/util/option"
"github.com/DataDog/datadog-agent/pkg/util/sort"
statutil "github.com/DataDog/datadog-agent/pkg/util/stat"
tagutil "github.com/DataDog/datadog-agent/pkg/util/tags"
)

var (
Expand Down Expand Up @@ -79,6 +80,7 @@ type dependencies struct {
Params Params
WMeta option.Option[workloadmeta.Component]
Telemetry telemetry.Component
Tagger tagger.Component
}

type provides struct {
Expand Down Expand Up @@ -184,7 +186,7 @@ func initTelemetry() {

// TODO: (components) - merge with newServerCompat once NewServerlessServer is removed
func newServer(deps dependencies) provides {
s := newServerCompat(deps.Config, deps.Log, deps.Replay, deps.Debug, deps.Params.Serverless, deps.Demultiplexer, deps.WMeta, deps.PidMap, deps.Telemetry)
s := newServerCompat(deps.Config, deps.Log, deps.Replay, deps.Debug, deps.Params.Serverless, deps.Demultiplexer, deps.WMeta, deps.PidMap, deps.Telemetry, deps.Tagger)

if deps.Config.GetBool("use_dogstatsd") {
deps.Lc.Append(fx.Hook{
Expand All @@ -199,7 +201,7 @@ func newServer(deps dependencies) provides {
}
}

func newServerCompat(cfg model.Reader, log log.Component, capture replay.Component, debug serverdebug.Component, serverless bool, demux aggregator.Demultiplexer, wmeta option.Option[workloadmeta.Component], pidMap pidmap.Component, telemetrycomp telemetry.Component) *server {
func newServerCompat(cfg model.Reader, log log.Component, capture replay.Component, debug serverdebug.Component, serverless bool, demux aggregator.Demultiplexer, wmeta option.Option[workloadmeta.Component], pidMap pidmap.Component, telemetrycomp telemetry.Component, tagger tagger.Component) *server {
// This needs to be done after the configuration is loaded
once.Do(func() { initTelemetry() })
var stats *statutil.Stats
Expand Down Expand Up @@ -237,9 +239,11 @@ func newServerCompat(cfg model.Reader, log log.Component, capture replay.Compone

// if the server is running in a context where static tags are required, add those
// to extraTags.
if staticTags := tagutil.GetStaticTagsSlice(context.TODO(), cfg); staticTags != nil {
extraTags = append(extraTags, staticTags...)
staticTags, err := tagger.GlobalTags(types.LowCardinality)
if err != nil {
log.Errorf("Dogstatsd: unable to get static tags: %s", err)
}
extraTags = append(extraTags, staticTags...)
sort.UniqInPlace(extraTags)

entityIDPrecedenceEnabled := cfg.GetBool("dogstatsd_entity_id_precedence")
Expand Down
Loading
Loading