Skip to content

Commit

Permalink
extract kubernetes resource parsers (pod, deployment and metadata) to…
Browse files Browse the repository at this point in the history
… a separate package
  • Loading branch information
adel121 committed Aug 27, 2024
1 parent 9798b29 commit 21e4c4a
Show file tree
Hide file tree
Showing 20 changed files with 943 additions and 675 deletions.
74 changes: 74 additions & 0 deletions comp/core/tagger/filters/filter_builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// 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 2016-present Datadog, Inc.

// Package filters implements the Tagger Filters.
package filters

import (
"maps"

"github.com/DataDog/datadog-agent/comp/core/tagger/types"
)

// AllPrefixesSet returns a set of all possible entity id prefixes that can be used in the tagger
func AllPrefixesSet() map[EntityIDPrefix]struct{} {
return map[EntityIDPrefix]struct{}{
ContainerID: {},
ContainerImageMetadata: {},
ECSTask: {},
Host: {},
KubernetesDeployment: {},
KubernetesMetadata: {},
KubernetesPodUID: {},
Process: {},
}
}

// FilterBuilder builds a tagger subscriber filter based on include/exclude rules
type FilterBuilder struct {
prefixesToInclude map[types.EntityIDPrefix]struct{}

prefixesToExclude map[types.EntityIDPrefix]struct{}
}

// NewFilterBuilder returns a new empty filter builder
func NewFilterBuilder() FilterBuilder {
return FilterBuilder{}
}

// Include includes the specified prefixes in the filter
func (fb FilterBuilder) Include(prefixes ...types.EntityIDPrefix) {
for _, prefix := range prefixes {
fb.prefixesToInclude[prefix] = struct{}{}
}
}

// Exclude excludes the specified prefixes from the filter
func (fb FilterBuilder) Exclude(prefixes ...types.EntityIDPrefix) {
for _, prefix := range prefixes {
fb.prefixesToExclude[prefix] = struct{}{}
}
}

// Build builds a new Filter object based on the calls to Include and Exclude
// If the builder only excludes prefixes, the created filter will match any prefix except for the excluded ones.
// If the builder only includes prefixes, the created filter will match only the prefixes included in the builder.
// If the builder includes prefixes and excludes prefixes, the created filter will match only prefixes that are included but a not excluded in the builder
func (fb FilterBuilder) Build(card types.TagCardinality) Filter {
prefixSet := make(map[types.EntityIDPrefix]struct{})

// only exclude
for prefix := range types.AllPrefixesSet() {
if _, found := fb.prefixesToExclude[prefix]; !found {
prefixSet[prefix] = struct{}{}
}
}

// only include
prefixSet = maps.Clone(fb.prefixesToInclude)

// both include and exclude
return *newFilter(prefixSet, card)
}
58 changes: 58 additions & 0 deletions comp/core/tagger/filters/filters.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// 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 2016-present Datadog, Inc.

// Package filters implements the Tagger Filters.
package filters

import (
"maps"

"github.com/DataDog/datadog-agent/comp/core/tagger/types"
)

// Filter represents a subscription filter for the tagger
type Filter struct {
prefixes map[types.EntityIDPrefix]struct{}
cardinality types.TagCardinality
}

func newFilter(prefixes map[types.EntityIDPrefix]struct{}, cardinality types.TagCardinality) *Filter {
return &Filter{
prefixes: prefixes,
cardinality: cardinality,
}
}

// GetPrefixes returns the prefix set of the filter
// If the filter is nil, an empty set is returned
func (f *Filter) GetPrefixes() map[types.EntityIDPrefix]struct{} {
if f == nil {
return nil
}

return maps.Clone(f.prefixes)
}

// GetCardinality returns the filter cardinality
// If the filter is nil, High cardinality is returned
func (f *Filter) GetCardinality() types.TagCardinality {
if f == nil {
return types.HighCardinality
}

return f.cardinality
}

// MatchesPrefix returns whether or not the filter matches the prefix passed as argument
func (f *Filter) MatchesPrefix(prefix types.EntityIDPrefix) bool {
// A nil filter should match everything
if f == nil {
return true
}

_, found := f.prefixes[prefix]

return found
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ package kubeapiserver

import (
"context"
"github.com/DataDog/datadog-agent/pkg/util/log"
"k8s.io/apimachinery/pkg/runtime/schema"
"regexp"
"strings"

appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -23,9 +19,9 @@ import (
"k8s.io/client-go/tools/cache"

"github.com/DataDog/datadog-agent/comp/core/config"
kubernetesresourceparsers "github.com/DataDog/datadog-agent/comp/core/workloadmeta/collectors/util/kubernetes_resource_parsers"
workloadmeta "github.com/DataDog/datadog-agent/comp/core/workloadmeta/def"
languagedetectionUtil "github.com/DataDog/datadog-agent/pkg/languagedetection/util"
ddkube "github.com/DataDog/datadog-agent/pkg/util/kubernetes"
"github.com/DataDog/datadog-agent/pkg/util/log"
)

// deploymentFilter filters out deployments that can't be used for unified service tagging or process language detection
Expand Down Expand Up @@ -59,10 +55,10 @@ func newDeploymentStore(ctx context.Context, wlm workloadmeta.Component, cfg con

func newDeploymentReflectorStore(wlmetaStore workloadmeta.Component, cfg config.Reader) *reflectorStore {
annotationsExclude := cfg.GetStringSlice("cluster_agent.kubernetes_resources_collection.deployment_annotations_exclude")
parser, err := newdeploymentParser(annotationsExclude)
parser, err := kubernetesresourceparsers.NewDeploymentParser(annotationsExclude)
if err != nil {
_ = log.Errorf("unable to parse all deployment_annotations_exclude: %v, err:", err)
parser, _ = newdeploymentParser(nil)
parser, _ = kubernetesresourceparsers.NewDeploymentParser(nil)
}

store := &reflectorStore{
Expand All @@ -74,70 +70,3 @@ func newDeploymentReflectorStore(wlmetaStore workloadmeta.Component, cfg config.

return store
}

type deploymentParser struct {
annotationsFilter []*regexp.Regexp
gvr *schema.GroupVersionResource
}

func newdeploymentParser(annotationsExclude []string) (objectParser, error) {
filters, err := parseFilters(annotationsExclude)
if err != nil {
return nil, err
}
return deploymentParser{
annotationsFilter: filters,
gvr: &schema.GroupVersionResource{
Group: "apps",
Version: "v1",
Resource: "deployments",
},
}, nil
}

func updateContainerLanguage(cl languagedetectionUtil.ContainersLanguages, container languagedetectionUtil.Container, languages string) {
if _, found := cl[container]; !found {
cl[container] = make(languagedetectionUtil.LanguageSet)
}

for _, lang := range strings.Split(languages, ",") {
cl[container][languagedetectionUtil.Language(strings.TrimSpace(lang))] = struct{}{}
}
}

func (p deploymentParser) Parse(obj interface{}) workloadmeta.Entity {
deployment := obj.(*appsv1.Deployment)
containerLanguages := make(languagedetectionUtil.ContainersLanguages)

for annotation, languages := range deployment.Annotations {

containerName, isInitContainer := languagedetectionUtil.ExtractContainerFromAnnotationKey(annotation)
if containerName != "" && languages != "" {

updateContainerLanguage(
containerLanguages,
languagedetectionUtil.Container{
Name: containerName,
Init: isInitContainer,
},
languages)
}
}

return &workloadmeta.KubernetesDeployment{
EntityID: workloadmeta.EntityID{
Kind: workloadmeta.KindKubernetesDeployment,
ID: deployment.Namespace + "/" + deployment.Name, // we use the namespace/name as id to make it easier for the admission controller to retrieve the corresponding deployment
},
EntityMeta: workloadmeta.EntityMeta{
Name: deployment.Name,
Namespace: deployment.Namespace,
Labels: deployment.Labels,
Annotations: filterMapStringKey(deployment.Annotations, p.annotationsFilter),
},
Env: deployment.Labels[ddkube.EnvTagLabelKey],
Service: deployment.Labels[ddkube.ServiceTagLabelKey],
Version: deployment.Labels[ddkube.VersionTagLabelKey],
InjectableLanguages: containerLanguages,
}
}
Loading

0 comments on commit 21e4c4a

Please sign in to comment.