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-376] expose kubernetes_resources_labels/annotations_as_tags #1379

Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 2 additions & 0 deletions api/datadoghq/common/envvar.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ const (
DDNamespaceLabelsAsTags = "DD_KUBERNETES_NAMESPACE_LABELS_AS_TAGS"
DDNamespaceAnnotationsAsTags = "DD_KUBERNETES_NAMESPACE_ANNOTATIONS_AS_TAGS"
DDNodeLabelsAsTags = "DD_KUBERNETES_NODE_LABELS_AS_TAGS"
DDKubernetesResourcesLabelsAsTags = "DD_KUBERNETES_RESOURCES_LABELS_AS_TAGS"
DDKubernetesResourcesAnnotationsAsTags = "DD_KUBERNETES_RESOURCES_ANNOTATIONS_AS_TAGS"
DDOrchestratorExplorerEnabled = "DD_ORCHESTRATOR_EXPLORER_ENABLED"
DDOrchestratorExplorerExtraTags = "DD_ORCHESTRATOR_EXPLORER_EXTRA_TAGS"
DDOrchestratorExplorerDDUrl = "DD_ORCHESTRATOR_EXPLORER_ORCHESTRATOR_DD_URL"
Expand Down
14 changes: 14 additions & 0 deletions api/datadoghq/v2alpha1/datadogagent_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1222,6 +1222,20 @@ type GlobalConfig struct {
// +optional
NamespaceAnnotationsAsTags map[string]string `json:"namespaceAnnotationsAsTags,omitempty"`

// Provide a mapping of Kubernetes Resource Groups to labels mapping to Datadog Tags.
// <KUBERNETES_RESOURCE_GROUP>:
// <KUBERNETES_LABEL>: <DATADOG_TAG_KEY>
// KUBERNETES_RESOURCE_GROUP should be in the form `{resource}.{group}` or `{resource}` (example: deployments.apps, pods)
// +optional
KubernetesResourcesLabelsAsTags map[string]map[string]string `json:"kubernetesResourcesLabelsAsTags,omitempty"`

// Provide a mapping of Kubernetes Resource Groups to annotations mapping to Datadog Tags.
// <KUBERNETES_RESOURCE_GROUP>:
// <KUBERNETES_ANNOTATION>: <DATADOG_TAG_KEY>
// KUBERNETES_RESOURCE_GROUP should be in the form `{resource}.{group}` or `{resource}` (example: deployments.apps, pods)
// +optional
KubernetesResourcesAnnotationsAsTags map[string]map[string]string `json:"kubernetesResourcesAnnotationsAsTags,omitempty"`

// NetworkPolicy contains the network configuration.
// +optional
NetworkPolicy *NetworkPolicyConfig `json:"networkPolicy,omitempty"`
Expand Down
36 changes: 36 additions & 0 deletions api/datadoghq/v2alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions config/crd/bases/v1/datadoghq.com_datadogagents.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1949,6 +1949,28 @@ spec:
Default: true
type: boolean
type: object
kubernetesResourcesAnnotationsAsTags:
additionalProperties:
additionalProperties:
type: string
type: object
description: |-
Provide a mapping of Kubernetes Resource Groups to annotations mapping to Datadog Tags.
<KUBERNETES_RESOURCE_GROUP>:
<KUBERNETES_ANNOTATION>: <DATADOG_TAG_KEY>
KUBERNETES_RESOURCE_GROUP should be in the form `{resource}.{group}` or `{resource}` (example: deployments.apps, pods)
type: object
kubernetesResourcesLabelsAsTags:
additionalProperties:
additionalProperties:
type: string
type: object
description: |-
Provide a mapping of Kubernetes Resource Groups to labels mapping to Datadog Tags.
<KUBERNETES_RESOURCE_GROUP>:
<KUBERNETES_LABEL>: <DATADOG_TAG_KEY>
KUBERNETES_RESOURCE_GROUP should be in the form `{resource}.{group}` or `{resource}` (example: deployments.apps, pods)
type: object
localService:
description: LocalService contains configuration to customize the internal traffic policy service.
properties:
Expand Down
2 changes: 2 additions & 0 deletions docs/configuration.v2alpha1.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ spec:
| global.kubelet.host.secretKeyRef.optional | Specify whether the Secret or its key must be defined |
| global.kubelet.hostCAPath | HostCAPath is the host path where the kubelet CA certificate is stored. |
| global.kubelet.tlsVerify | TLSVerify toggles kubelet TLS verification. Default: true |
| global.kubernetesResourcesAnnotationsAsTags | Provide a mapping of Kubernetes Resource Groups to annotations mapping to Datadog Tags. <KUBERNETES_RESOURCE_GROUP>: <KUBERNETES_ANNOTATION>: <DATADOG_TAG_KEY> KUBERNETES_RESOURCE_GROUP should be in the form `{resource}.{group}` or `{resource}` (example: deployments.apps, pods) |
| global.kubernetesResourcesLabelsAsTags | Provide a mapping of Kubernetes Resource Groups to labels mapping to Datadog Tags. <KUBERNETES_RESOURCE_GROUP>: <KUBERNETES_LABEL>: <DATADOG_TAG_KEY> KUBERNETES_RESOURCE_GROUP should be in the form `{resource}.{group}` or `{resource}` (example: deployments.apps, pods) |
| global.localService.forceEnableLocalService | ForceEnableLocalService forces the creation of the internal traffic policy service to target the agent running on the local node. This parameter only applies to Kubernetes 1.21, where the feature is in alpha and is disabled by default. (On Kubernetes 1.22+, the feature entered beta and the internal traffic service is created by default, so this parameter is ignored.) Default: false |
| global.localService.nameOverride | NameOverride defines the name of the internal traffic service to target the agent running on the local node. |
| global.logLevel | LogLevel sets logging verbosity. This can be overridden by container. Valid log levels are: trace, debug, info, warn, error, critical, and off. Default: 'info' |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ func GetExternalMetricsReaderClusterRoleName(dda metav1.Object, versionInfo *ver
return fmt.Sprintf("%s-metrics-reader", GetClusterAgentRbacResourcesName(dda))
}

// GetResourceMetadataAsTagsClusterRoleName returns the name for the cluster role name used for kubernetes resource labels and annotations as tags
func GetResourceMetadataAsTagsClusterRoleName(dda metav1.Object) string {
return fmt.Sprintf("%s-kubernetes-metadata-as-tags", GetClusterAgentRbacResourcesName(dda))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should use -annotations-and-labels-as-tags to stay consistent with what we're doing in the helm chart:

https://github.com/DataDog/helm-charts/blob/efa4d6629c240b545035bc80e05fbafaf83316c1/charts/datadog/templates/cluster-agent-rbac.yaml#L500

Suggested change
return fmt.Sprintf("%s-kubernetes-metadata-as-tags", GetClusterAgentRbacResourcesName(dda))
return fmt.Sprintf("%s-annotations-and-labels-as-tags", GetClusterAgentRbacResourcesName(dda))

}

// GetApiserverAuthReaderRoleBindingName returns the name for the role binding to access the extension-apiserver-authentication cm
func GetApiserverAuthReaderRoleBindingName(dda metav1.Object) string {
return fmt.Sprintf("%s-apiserver", GetClusterAgentRbacResourcesName(dda))
Expand Down
38 changes: 38 additions & 0 deletions internal/controller/datadogagent/override/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
apicommon "github.com/DataDog/datadog-operator/api/datadoghq/common"
"github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1"
apiutils "github.com/DataDog/datadog-operator/api/utils"
componentdca "github.com/DataDog/datadog-operator/internal/controller/datadogagent/component/clusteragent"
"github.com/DataDog/datadog-operator/internal/controller/datadogagent/component/objects"
"github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature"
"github.com/DataDog/datadog-operator/internal/controller/datadogagent/object/volume"
Expand Down Expand Up @@ -219,6 +220,43 @@ func applyGlobalSettings(logger logr.Logger, manager feature.PodTemplateManagers
}
}

// Provide a mapping of Kubernetes Resource Labels to Datadog Tags.
if config.KubernetesResourcesLabelsAsTags != nil {
kubernetesResourceLabelsAsTags, err := json.Marshal(config.KubernetesResourcesLabelsAsTags)
if err != nil {
logger.Error(err, "Failed to unmarshal json input")
} else {
manager.EnvVar().AddEnvVar(&corev1.EnvVar{
Name: apicommon.DDKubernetesResourcesLabelsAsTags,
Value: string(kubernetesResourceLabelsAsTags),
})
}
}

// Provide a mapping of Kubernetes Resource Annotations to Datadog Tags.
if config.KubernetesResourcesLabelsAsTags != nil {
kubernetesResourceAnnotationsAsTags, err := json.Marshal(config.KubernetesResourcesAnnotationsAsTags)
if err != nil {
logger.Error(err, "Failed to unmarshal json input")
} else {
manager.EnvVar().AddEnvVar(&corev1.EnvVar{
Name: apicommon.DDKubernetesResourcesAnnotationsAsTags,
Value: string(kubernetesResourceAnnotationsAsTags),
})
}
}

if componentName == v2alpha1.ClusterAgentComponentName {
if err := resourcesManager.RBACManager().AddClusterPolicyRules(
dda.Namespace,
componentdca.GetResourceMetadataAsTagsClusterRoleName(dda),
v2alpha1.GetClusterAgentServiceAccount(dda),
getKubernetesResourceMetadataAsTagsPolicyRules(config.KubernetesResourcesLabelsAsTags, config.KubernetesResourcesAnnotationsAsTags),
); err != nil {
logger.Error(err, "error adding kubernetes resource metadata as tags clusterrole and clusterrolebinding to store")
}
}

if componentName == v2alpha1.NodeAgentComponentName {
// Kubelet contains the kubelet configuration parameters.
// The environment variable `DD_KUBERNETES_KUBELET_HOST` defaults to `status.hostIP` if not overriden.
Expand Down
79 changes: 79 additions & 0 deletions internal/controller/datadogagent/override/rbac.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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 override

import (
"strings"

"github.com/DataDog/datadog-operator/pkg/kubernetes/rbac"
rbacv1 "k8s.io/api/rbac/v1"
)

func extractGroupAndResource(groupResource string) (group string, resource string, ok bool) {
parts := strings.Split(groupResource, ".")

switch len(parts) {
case 1:
group = ""
resource = parts[0]
ok = true
case 2:
group = parts[1]
resource = parts[0]
ok = true
default:
ok = false
}

return group, resource, ok
}

func appendGroupResource(groupResourceAccumulator map[string]map[string]struct{}, group string, resource string) map[string]map[string]struct{} {
if _, exists := groupResourceAccumulator[group]; !exists {
groupResourceAccumulator[group] = map[string]struct{}{resource: {}}
} else {
groupResourceAccumulator[group][resource] = struct{}{}
}

return groupResourceAccumulator
}

func getKubernetesResourceMetadataAsTagsPolicyRules(resourcesLabelsAsTags, resourcesAnnotationsAsTags map[string]map[string]string) []rbacv1.PolicyRule {
// maps group to resource set
// using map to avoid duplicates
groupResourceAccumulator := map[string]map[string]struct{}{}

for groupResource := range resourcesLabelsAsTags {
if group, resource, ok := extractGroupAndResource(groupResource); ok {
groupResourceAccumulator = appendGroupResource(groupResourceAccumulator, group, resource)
}
}

for groupResource := range resourcesAnnotationsAsTags {
if group, resource, ok := extractGroupAndResource(groupResource); ok {
groupResourceAccumulator = appendGroupResource(groupResourceAccumulator, group, resource)
}
}

policyRules := make([]rbacv1.PolicyRule, 0)

for group, resources := range groupResourceAccumulator {
for resource := range resources {
policyRules = append(policyRules, rbacv1.PolicyRule{
APIGroups: []string{group},
Resources: []string{resource},
Verbs: []string{
rbac.GetVerb,
rbac.ListVerb,
rbac.WatchVerb,
},
},
)
}
}

return policyRules
}
63 changes: 63 additions & 0 deletions internal/controller/datadogagent/override/rbac_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// 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 override

import (
"testing"

"github.com/DataDog/datadog-operator/pkg/kubernetes/rbac"
assert "github.com/stretchr/testify/require"
rbacv1 "k8s.io/api/rbac/v1"
)

func TestGetKubernetesResourceMetadataAsTagsPolicyRules(t *testing.T) {
labelsAsTags := map[string]map[string]string{
"pods": {
"foo": "bar",
"bar": "bar",
},
"deployments.apps": {
"foo": "baz",
"bar": "bar",
},
}

annotationsAsTags := map[string]map[string]string{
"pods": {
"foo": "bar",
"bar": "bar",
},
"deployments.apps": {
"foo": "baz",
"bar": "bar",
},
}

expectedRules := []rbacv1.PolicyRule{
{
APIGroups: []string{""},
Resources: []string{"pods"},
Verbs: []string{
rbac.GetVerb,
rbac.ListVerb,
rbac.WatchVerb,
},
},
{
APIGroups: []string{"apps"},
Resources: []string{"deployments"},
Verbs: []string{
rbac.GetVerb,
rbac.ListVerb,
rbac.WatchVerb,
},
},
}

rules := getKubernetesResourceMetadataAsTagsPolicyRules(labelsAsTags, annotationsAsTags)

assert.ElementsMatch(t, expectedRules, rules)
}
6 changes: 6 additions & 0 deletions internal/controller/testutils/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,12 @@ func NewDatadogAgentWithGlobalConfigSettings(namespace string, name string) v2al
NodeLabelsAsTags: map[string]string{"some-label": "some-tag"},
NamespaceLabelsAsTags: map[string]string{"some-label": "some-tag"},
NamespaceAnnotationsAsTags: map[string]string{"some-annotation": "some-tag"},
KubernetesResourcesLabelsAsTags: map[string]map[string]string{
"some-group.some-resource": {"some-label": "some-tag"},
},
KubernetesResourcesAnnotationsAsTags: map[string]map[string]string{
"some-group.some-resource": {"some-annotation": "some-tag"},
},
NetworkPolicy: &v2alpha1.NetworkPolicyConfig{
Create: apiutils.NewBoolPointer(true),
Flavor: v2alpha1.NetworkPolicyFlavorKubernetes,
Expand Down
Loading