Skip to content

Commit

Permalink
add kubernetes_resources_annotations_as_tags and kubernetes_resources…
Browse files Browse the repository at this point in the history
…_labels_as_tags
  • Loading branch information
adel121 committed Jul 15, 2024
1 parent e1ae6d8 commit 0f4cd6a
Show file tree
Hide file tree
Showing 8 changed files with 548 additions and 54 deletions.
97 changes: 85 additions & 12 deletions comp/core/tagger/taggerimpl/collectors/workloadmeta_extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"encoding/json"
"errors"
"fmt"
"slices"
"strings"

k8smetadata "github.com/DataDog/datadog-agent/comp/core/tagger/k8s_metadata"
Expand Down Expand Up @@ -114,8 +113,6 @@ var (
highCardOrchestratorLabels = map[string]string{
"io.rancher.container.name": tags.RancherContainer,
}

handledKubernetesMetadataResources = []string{"namespaces", "nodes"}
)

func (c *WorkloadMetaCollector) processEvents(evBundle workloadmeta.EventBundle) {
Expand Down Expand Up @@ -156,7 +153,7 @@ func (c *WorkloadMetaCollector) processEvents(evBundle workloadmeta.EventBundle)
case workloadmeta.KindProcess:
// tagInfos = append(tagInfos, c.handleProcess(ev)...) No tags for now
case workloadmeta.KindKubernetesDeployment:
// tagInfos = append(tagInfos, c.handleDeployment(ev)...) No tags for now
tagInfos = append(tagInfos, c.handleKubeDeployment(ev)...)
default:
log.Errorf("cannot handle event for entity %q with kind %q", entityID.ID, entityID.Kind)
}
Expand Down Expand Up @@ -357,6 +354,23 @@ func (c *WorkloadMetaCollector) handleKubePod(ev workloadmeta.Event) []*types.Ta
k8smetadata.AddMetadataAsTags(name, value, c.nsAnnotationsAsTags, c.globNsAnnotations, tagList)
}

// pod annotations and labels as tags
labelsAsTags := c.k8sResourcesLabelsAsTags["pods"]
annotationsAsTags := c.k8sResourcesAnnotationsAsTags["pods"]

if len(labelsAsTags)+len(annotationsAsTags) > 0 {
globLabels := c.globK8sResourceLabels["pods"]
globAnnotations := c.globK8sResourceAnnotations["pods"]

for name, value := range pod.Labels {
k8smetadata.AddMetadataAsTags(name, value, labelsAsTags, globLabels, tagList)
}

for name, value := range pod.Annotations {
k8smetadata.AddMetadataAsTags(name, value, annotationsAsTags, globAnnotations, tagList)
}
}

kubeServiceDisabled := false
for _, disabledTag := range config.Datadog().GetStringSlice("kubernetes_ad_tags_disabled") {
if disabledTag == "kube_service" {
Expand Down Expand Up @@ -512,21 +526,75 @@ func (c *WorkloadMetaCollector) handleGardenContainer(container *workloadmeta.Co
}
}

func (c *WorkloadMetaCollector) handleKubeMetadata(ev workloadmeta.Event) []*types.TagInfo {
kubeMetadata := ev.Entity.(*workloadmeta.KubernetesMetadata)
func (c *WorkloadMetaCollector) handleKubeDeployment(ev workloadmeta.Event) []*types.TagInfo {
deployment := ev.Entity.(*workloadmeta.KubernetesDeployment)

resource := kubeMetadata.GVR.Resource
groupResource := "deployments.apps"

if !slices.Contains(handledKubernetesMetadataResources, resource) {
labelsAsTags := c.k8sResourcesLabelsAsTags[groupResource]
annotationsAsTags := c.k8sResourcesAnnotationsAsTags[groupResource]

if len(labelsAsTags)+len(annotationsAsTags) == 0 {
return nil
}

globLabels := c.globK8sResourceLabels[groupResource]
globAnnotations := c.globK8sResourceAnnotations[groupResource]

tagList := taglist.NewTagList()

switch resource {
case "nodes":
// No tags for nodes
case "namespaces":
for name, value := range deployment.Labels {
k8smetadata.AddMetadataAsTags(name, value, labelsAsTags, globLabels, tagList)
}

for name, value := range deployment.Annotations {
k8smetadata.AddMetadataAsTags(name, value, annotationsAsTags, globAnnotations, tagList)
}

low, orch, high, standard := tagList.Compute()

if len(low)+len(orch)+len(high)+len(standard) == 0 {
return nil
}

tagInfos := []*types.TagInfo{
{
Source: deploymentSource,
Entity: buildTaggerEntityID(deployment.EntityID),
HighCardTags: high,
OrchestratorCardTags: orch,
LowCardTags: low,
StandardTags: standard,
},
}

return tagInfos
}

func (c *WorkloadMetaCollector) handleKubeMetadata(ev workloadmeta.Event) []*types.TagInfo {
kubeMetadata := ev.Entity.(*workloadmeta.KubernetesMetadata)

tagList := taglist.NewTagList()

// Generic resource annotations and labels as tags
groupResource := kubeMetadata.GVR.GroupResource().String()

labelsAsTags := c.k8sResourcesLabelsAsTags[groupResource]
annotationsAsTags := c.k8sResourcesAnnotationsAsTags[groupResource]

globLabels := c.globK8sResourceLabels[groupResource]
globAnnotations := c.globK8sResourceAnnotations[groupResource]

for name, value := range kubeMetadata.Labels {
k8smetadata.AddMetadataAsTags(name, value, labelsAsTags, globLabels, tagList)
}

for name, value := range kubeMetadata.Annotations {
k8smetadata.AddMetadataAsTags(name, value, annotationsAsTags, globAnnotations, tagList)
}

// Namespace annotations and labels as tags
if kubeMetadata.GVR.Resource == "namespaces" {
for name, value := range kubeMetadata.Labels {
k8smetadata.AddMetadataAsTags(name, value, c.nsLabelsAsTags, c.globNsLabels, tagList)
}
Expand All @@ -537,6 +605,11 @@ func (c *WorkloadMetaCollector) handleKubeMetadata(ev workloadmeta.Event) []*typ
}

low, orch, high, standard := tagList.Compute()

if len(low)+len(orch)+len(high)+len(standard) == 0 {
return nil
}

tagInfos := []*types.TagInfo{
{
Source: kubeMetadataSource,
Expand Down
79 changes: 64 additions & 15 deletions comp/core/tagger/taggerimpl/collectors/workloadmeta_main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package collectors

import (
"context"
"encoding/json"
"strings"

"github.com/gobwas/glob"
Expand Down Expand Up @@ -34,6 +35,7 @@ const (
processSource = workloadmetaCollectorName + "-" + string(workloadmeta.KindProcess)
hostSource = workloadmetaCollectorName + "-" + string(workloadmeta.KindHost)
kubeMetadataSource = workloadmetaCollectorName + "-" + string(workloadmeta.KindKubernetesMetadata)
deploymentSource = workloadmetaCollectorName + "-" + string(workloadmeta.KindKubernetesDeployment)

clusterTagNamePrefix = "kube_cluster_name"
)
Expand All @@ -55,17 +57,21 @@ type WorkloadMetaCollector struct {
containerEnvAsTags map[string]string
containerLabelsAsTags map[string]string

staticTags map[string]string
labelsAsTags map[string]string
annotationsAsTags map[string]string
nsLabelsAsTags map[string]string
nsAnnotationsAsTags map[string]string
globLabels map[string]glob.Glob
globAnnotations map[string]glob.Glob
globNsLabels map[string]glob.Glob
globNsAnnotations map[string]glob.Glob
globContainerLabels map[string]glob.Glob
globContainerEnvLabels map[string]glob.Glob
staticTags map[string]string
labelsAsTags map[string]string
annotationsAsTags map[string]string
nsLabelsAsTags map[string]string
nsAnnotationsAsTags map[string]string
k8sResourcesAnnotationsAsTags map[string]map[string]string
k8sResourcesLabelsAsTags map[string]map[string]string
globLabels map[string]glob.Glob
globAnnotations map[string]glob.Glob
globNsLabels map[string]glob.Glob
globNsAnnotations map[string]glob.Glob
globContainerLabels map[string]glob.Glob
globContainerEnvLabels map[string]glob.Glob
globK8sResourceAnnotations map[string]map[string]glob.Glob
globK8sResourceLabels map[string]map[string]glob.Glob

collectEC2ResourceTags bool
collectPersistentVolumeClaimsTags bool
Expand All @@ -83,6 +89,21 @@ func (c *WorkloadMetaCollector) initPodMetaAsTags(labelsAsTags, annotationsAsTag
c.nsAnnotationsAsTags, c.globNsAnnotations = k8smetadata.InitMetadataAsTags(nsAnnotationsAsTags)
}

func (c *WorkloadMetaCollector) initK8sResourcesMetaAsTags(resourcesLabelsAsTags, resourcesAnnotationsAsTags map[string]map[string]string) {
c.k8sResourcesAnnotationsAsTags = map[string]map[string]string{}
c.k8sResourcesLabelsAsTags = map[string]map[string]string{}
c.globK8sResourceAnnotations = map[string]map[string]glob.Glob{}
c.globK8sResourceLabels = map[string]map[string]glob.Glob{}

for resource, labelsAsTags := range resourcesLabelsAsTags {
c.k8sResourcesLabelsAsTags[resource], c.globK8sResourceLabels[resource] = k8smetadata.InitMetadataAsTags(labelsAsTags)
}

for resource, annotationsAsTags := range resourcesAnnotationsAsTags {
c.k8sResourcesAnnotationsAsTags[resource], c.globK8sResourceAnnotations[resource] = k8smetadata.InitMetadataAsTags(annotationsAsTags)
}
}

// 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) {
Expand Down Expand Up @@ -184,19 +205,47 @@ func NewWorkloadMetaCollector(_ context.Context, store workloadmeta.Component, p
nsAnnotationsAsTags := config.Datadog().GetStringMapString("kubernetes_namespace_annotations_as_tags")
c.initPodMetaAsTags(labelsAsTags, annotationsAsTags, nsLabelsAsTags, nsAnnotationsAsTags)

k8sResourcesAnnotationsAsTags := retrieveDoubleMappingFromConfig("kubernetes_resources_annotations_as_tags")
k8sResourcesLabelsAsTags := retrieveDoubleMappingFromConfig("kubernetes_resources_labels_as_tags")
c.initK8sResourcesMetaAsTags(k8sResourcesLabelsAsTags, k8sResourcesAnnotationsAsTags)

return c
}

func retrieveDoubleMappingFromConfig(configKey string) map[string]map[string]string {
valueFromConfig := config.Datadog().GetString(configKey)

var doubleMap map[string]map[string]string
err := json.Unmarshal([]byte(valueFromConfig), &doubleMap)

if err != nil {
log.Errorf("failed to parse %s with value %s into json: %v", configKey, valueFromConfig, err)
return map[string]map[string]string{}
}

for resource, tags := range doubleMap {
doubleMap[resource] = lowerCaseMapKeys(tags)
}

return doubleMap
}

// retrieveMappingFromConfig gets a stringmapstring config key and
// lowercases all map keys to make envvar and yaml sources consistent
func retrieveMappingFromConfig(configKey string) map[string]string {
labelsList := config.Datadog().GetStringMapString(configKey)
for label, value := range labelsList {
delete(labelsList, label)
labelsList[strings.ToLower(label)] = value

return lowerCaseMapKeys(labelsList)
}

// lowercases all map keys
func lowerCaseMapKeys(m map[string]string) map[string]string {
for label, value := range m {
delete(m, label)
m[strings.ToLower(label)] = value
}

return labelsList
return m
}

// mergeMaps merges two maps, in case of conflict the first argument is prioritized
Expand Down
Loading

0 comments on commit 0f4cd6a

Please sign in to comment.