diff --git a/charts/datadog/CHANGELOG.md b/charts/datadog/CHANGELOG.md index 3da3aac32..e9dc822e2 100644 --- a/charts/datadog/CHANGELOG.md +++ b/charts/datadog/CHANGELOG.md @@ -1,5 +1,9 @@ # Datadog changelog +## 3.107.0 + +* * Validation has been added for values under `datadog.apm.instrumentation`. Additional or incorrect values will fail a helm install or upgrade operation. + ## 3.106.0 * Target based workload selection for Single Step Instrumentation has been added in preview (requires Cluster Agent 7.64.0+) diff --git a/charts/datadog/Chart.yaml b/charts/datadog/Chart.yaml index 26f1d0255..eb3a81ea1 100644 --- a/charts/datadog/Chart.yaml +++ b/charts/datadog/Chart.yaml @@ -1,7 +1,7 @@ --- apiVersion: v1 name: datadog -version: 3.106.0 +version: 3.107.0 appVersion: "7" description: Datadog Agent keywords: diff --git a/charts/datadog/README.md b/charts/datadog/README.md index b7c979c3c..7049b2c07 100644 --- a/charts/datadog/README.md +++ b/charts/datadog/README.md @@ -1,6 +1,6 @@ # Datadog -![Version: 3.106.0](https://img.shields.io/badge/Version-3.106.0-informational?style=flat-square) ![AppVersion: 7](https://img.shields.io/badge/AppVersion-7-informational?style=flat-square) +![Version: 3.107.0](https://img.shields.io/badge/Version-3.107.0-informational?style=flat-square) ![AppVersion: 7](https://img.shields.io/badge/AppVersion-7-informational?style=flat-square) [Datadog](https://www.datadoghq.com/) is a hosted infrastructure monitoring platform. This chart adds the Datadog Agent to all nodes in your cluster via a DaemonSet. It also optionally depends on the [kube-state-metrics chart](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-state-metrics). For more information about monitoring Kubernetes with Datadog, please refer to the [Datadog documentation website](https://docs.datadoghq.com/agent/basic_agent_usage/kubernetes/). diff --git a/charts/datadog/values.schema.json b/charts/datadog/values.schema.json new file mode 100644 index 000000000..49279eda8 --- /dev/null +++ b/charts/datadog/values.schema.json @@ -0,0 +1,300 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "title": "Values", + "type": "object", + "properties": { + "datadog": { + "type": "object", + "properties": { + "apm": { + "type": "object", + "properties": { + "instrumentation": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "enabledNamespaces": { + "type": "array", + "items": { + "type": "string" + } + }, + "disabledNamespaces": { + "type": "array", + "items": { + "type": "string" + } + }, + "libVersions": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "targets": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "podSelector": { + "type": "object", + "properties": { + "matchLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "matchExpressions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string", + "enum": [ + "In", + "NotIn", + "Exists", + "DoesNotExist" + ] + }, + "values": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + } + }, + "required": ["key", "operator"], + "additionalProperties": false + } + } + }, + "additionalProperties": false + }, + "namespaceSelector": { + "type": "object", + "properties": { + "matchNames": { + "type": "array", + "items": { + "type": "string" + } + }, + "matchLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "matchExpressions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string", + "enum": [ + "In", + "NotIn", + "Exists", + "DoesNotExist" + ] + }, + "values": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + } + }, + "required": ["key", "operator"], + "additionalProperties": false + } + } + }, + "anyOf": [ + { + "if": { + "properties": { + "matchNames": { + "type": "array", + "minItems": 1 + } + } + }, + "then": { + "properties": { + "matchLabels": { + "type": "object", + "maxProperties": 0 + }, + "matchExpressions": { + "type": "array", + "maxItems": 0 + } + } + } + }, + { + "if": { + "properties": { + "matchLabels": { + "type": "object", + "minProperties": 1 + } + } + }, + "then": { + "properties": { + "matchNames": { + "type": "array", + "maxItems": 0 + } + } + } + }, + { + "if": { + "properties": { + "matchExpressions": { + "type": "array", + "minItems": 1 + } + } + }, + "then": { + "properties": { + "matchNames": { + "type": "array", + "maxItems": 0 + } + } + } + } + ], + "additionalProperties": false + }, + "ddTraceVersions": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "ddTraceConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": ["name", "value"], + "additionalProperties": false + } + } + }, + "required": ["name"], + "additionalProperties": false + } + }, + "skipKPITelemetry": { + "type": "boolean" + }, + "language_detection": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "injector": { + "type": "object", + "properties": { + "imageTag": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false, + "allOf": [ + { + "if": { + "properties": { + "enabledNamespaces": { + "type": "array", + "minItems": 1 + } + } + }, + "then": { + "properties": { + "targets": { + "type": "array", + "maxItems": 0 + } + } + } + }, + { + "if": { + "properties": { + "libVersions": { + "type": "object", + "minProperties": 1 + } + } + }, + "then": { + "properties": { + "targets": { + "type": "array", + "maxItems": 0 + } + } + } + }, + { + "if": { + "properties": { + "enabledNamespaces": { + "type": "array", + "minItems": 1 + } + } + }, + "then": { + "properties": { + "disabledNamespaces": { + "type": "array", + "maxItems": 0 + } + } + } + } + ] + } + } + } + } + } + } +} diff --git a/test/datadog/apm_instrumentation_test.go b/test/datadog/apm_instrumentation_test.go new file mode 100644 index 000000000..290b1aa70 --- /dev/null +++ b/test/datadog/apm_instrumentation_test.go @@ -0,0 +1,172 @@ +package datadog + +import ( + "testing" + + "github.com/DataDog/helm-charts/test/common" + "github.com/stretchr/testify/assert" +) + +func TestAPMConfigValidation(t *testing.T) { + tests := []struct { + name string + command common.HelmCommand + isValid bool + }{ + { + name: "valid enabled configuration", + command: common.HelmCommand{ + ReleaseName: "datadog", + ChartPath: "../../charts/datadog", + Values: []string{ + "../../charts/datadog/values.yaml", + "values/instrumentation/valid_enabled.yaml", + }, + }, + isValid: true, + }, + { + name: "valid target configuration", + command: common.HelmCommand{ + ReleaseName: "datadog", + ChartPath: "../../charts/datadog", + Values: []string{ + "../../charts/datadog/values.yaml", + "values/instrumentation/valid_targets.yaml", + }, + }, + isValid: true, + }, + { + name: "valid namespace configuration", + command: common.HelmCommand{ + ReleaseName: "datadog", + ChartPath: "../../charts/datadog", + Values: []string{ + "../../charts/datadog/values.yaml", + "values/instrumentation/valid_namespace.yaml", + }, + }, + isValid: true, + }, + { + name: "both namespaces and targets", + command: common.HelmCommand{ + ReleaseName: "datadog", + ChartPath: "../../charts/datadog", + Values: []string{ + "../../charts/datadog/values.yaml", + "values/instrumentation/namespaces_and_targets.yaml", + }, + }, + isValid: false, + }, + { + name: "both libversions and targets", + command: common.HelmCommand{ + ReleaseName: "datadog", + ChartPath: "../../charts/datadog", + Values: []string{ + "../../charts/datadog/values.yaml", + "values/instrumentation/libversions_and_targets.yaml", + }, + }, + isValid: false, + }, + { + name: "both enabled and disabled namespaces", + command: common.HelmCommand{ + ReleaseName: "datadog", + ChartPath: "../../charts/datadog", + Values: []string{ + "../../charts/datadog/values.yaml", + "values/instrumentation/enabled_and_disabled_namespaces.yaml", + }, + }, + isValid: false, + }, + { + name: "both matchLabels and matchNames for namespace selector", + command: common.HelmCommand{ + ReleaseName: "datadog", + ChartPath: "../../charts/datadog", + Values: []string{ + "../../charts/datadog/values.yaml", + "values/instrumentation/namespace_labels_and_names.yaml", + }, + }, + isValid: false, + }, + { + name: "both matchExpressions and matchNames for namespace selector", + command: common.HelmCommand{ + ReleaseName: "datadog", + ChartPath: "../../charts/datadog", + Values: []string{ + "../../charts/datadog/values.yaml", + "values/instrumentation/namespace_exprs_and_names.yaml", + }, + }, + isValid: false, + }, + { + name: "extraneous instrumentation key", + command: common.HelmCommand{ + ReleaseName: "datadog", + ChartPath: "../../charts/datadog", + Values: []string{ + "../../charts/datadog/values.yaml", + "values/instrumentation/extra_instrumentation_key.yaml", + }, + }, + isValid: false, + }, + { + name: "extraneous target key", + command: common.HelmCommand{ + ReleaseName: "datadog", + ChartPath: "../../charts/datadog", + Values: []string{ + "../../charts/datadog/values.yaml", + "values/instrumentation/extra_target_key.yaml", + }, + }, + isValid: false, + }, + { + name: "extraneous pod selector key", + command: common.HelmCommand{ + ReleaseName: "datadog", + ChartPath: "../../charts/datadog", + Values: []string{ + "../../charts/datadog/values.yaml", + "values/instrumentation/extra_podselector_key.yaml", + }, + }, + isValid: false, + }, + { + name: "extraneous namespace selector key", + command: common.HelmCommand{ + ReleaseName: "datadog", + ChartPath: "../../charts/datadog", + Values: []string{ + "../../charts/datadog/values.yaml", + "values/instrumentation/extra_namespaceselector_key.yaml", + }, + }, + isValid: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := common.RenderChart(t, tt.command) + if tt.isValid { + assert.Nil(t, err, "expected no error, got %v", err) + } else { + assert.NotNil(t, err, "expected error, got nil") + } + }) + } +} diff --git a/test/datadog/values/instrumentation/enabled_and_disabled_namespaces.yaml b/test/datadog/values/instrumentation/enabled_and_disabled_namespaces.yaml new file mode 100644 index 000000000..dda03e844 --- /dev/null +++ b/test/datadog/values/instrumentation/enabled_and_disabled_namespaces.yaml @@ -0,0 +1,11 @@ +--- +datadog: + apm: + instrumentation: + enabled: true + enabledNamespaces: + - "foo" + - "bar" + disabledNamespaces: + - "application" + - "test" \ No newline at end of file diff --git a/test/datadog/values/instrumentation/extra_instrumentation_key.yaml b/test/datadog/values/instrumentation/extra_instrumentation_key.yaml new file mode 100644 index 000000000..20e6bf221 --- /dev/null +++ b/test/datadog/values/instrumentation/extra_instrumentation_key.yaml @@ -0,0 +1,6 @@ +--- +datadog: + apm: + instrumentation: + enabled: true + foo: "i am extraneous" \ No newline at end of file diff --git a/test/datadog/values/instrumentation/extra_namespaceselector_key.yaml b/test/datadog/values/instrumentation/extra_namespaceselector_key.yaml new file mode 100644 index 000000000..382044647 --- /dev/null +++ b/test/datadog/values/instrumentation/extra_namespaceselector_key.yaml @@ -0,0 +1,16 @@ +--- +datadog: + apm: + instrumentation: + enabled: true + disabledNamespaces: + - "infra" + - "system" + targets: + - name: "billing-service" + namespaceSelector: + matchLabels: + app: "billing-service" + foo: "i am extraneous" + ddTraceVersions: + python: "v2" \ No newline at end of file diff --git a/test/datadog/values/instrumentation/extra_podselector_key.yaml b/test/datadog/values/instrumentation/extra_podselector_key.yaml new file mode 100644 index 000000000..f94a6991c --- /dev/null +++ b/test/datadog/values/instrumentation/extra_podselector_key.yaml @@ -0,0 +1,16 @@ +--- +datadog: + apm: + instrumentation: + enabled: true + disabledNamespaces: + - "infra" + - "system" + targets: + - name: "billing-service" + podSelector: + matchLabels: + app: "billing-service" + foo: "i am extraneous" + ddTraceVersions: + python: "v2" \ No newline at end of file diff --git a/test/datadog/values/instrumentation/extra_target_key.yaml b/test/datadog/values/instrumentation/extra_target_key.yaml new file mode 100644 index 000000000..c104a9ab5 --- /dev/null +++ b/test/datadog/values/instrumentation/extra_target_key.yaml @@ -0,0 +1,16 @@ +--- +datadog: + apm: + instrumentation: + enabled: true + disabledNamespaces: + - "infra" + - "system" + targets: + - name: "billing-service" + foo: "i am extraneous" + podSelector: + matchLabels: + app: "billing-service" + ddTraceVersions: + python: "v2" \ No newline at end of file diff --git a/test/datadog/values/instrumentation/libversions_and_targets.yaml b/test/datadog/values/instrumentation/libversions_and_targets.yaml new file mode 100644 index 000000000..748ed4c60 --- /dev/null +++ b/test/datadog/values/instrumentation/libversions_and_targets.yaml @@ -0,0 +1,14 @@ +--- +datadog: + apm: + instrumentation: + enabled: true + libVersions: + python: "v2" + targets: + - name: "billing-service" + podSelector: + matchLabels: + app: "billing-service" + ddTraceVersions: + python: "v2" \ No newline at end of file diff --git a/test/datadog/values/instrumentation/namespace_exprs_and_names.yaml b/test/datadog/values/instrumentation/namespace_exprs_and_names.yaml new file mode 100644 index 000000000..a28e88934 --- /dev/null +++ b/test/datadog/values/instrumentation/namespace_exprs_and_names.yaml @@ -0,0 +1,19 @@ +--- +datadog: + apm: + instrumentation: + enabled: true + targets: + - name: "billing-service" + namespaceSelector: + matchNames: + - "foo" + - "bar" + matchExpressions: + - key: "foo" + operator: "In" + values: + - "bar" + - "baz" + ddTraceVersions: + python: "v2" \ No newline at end of file diff --git a/test/datadog/values/instrumentation/namespace_labels_and_names.yaml b/test/datadog/values/instrumentation/namespace_labels_and_names.yaml new file mode 100644 index 000000000..d29e22d62 --- /dev/null +++ b/test/datadog/values/instrumentation/namespace_labels_and_names.yaml @@ -0,0 +1,15 @@ +--- +datadog: + apm: + instrumentation: + enabled: true + targets: + - name: "billing-service" + namespaceSelector: + matchLabels: + app: "billing-service" + matchNames: + - "foo" + - "bar" + ddTraceVersions: + python: "v2" \ No newline at end of file diff --git a/test/datadog/values/instrumentation/namespaces_and_targets.yaml b/test/datadog/values/instrumentation/namespaces_and_targets.yaml new file mode 100644 index 000000000..84ae3c1ba --- /dev/null +++ b/test/datadog/values/instrumentation/namespaces_and_targets.yaml @@ -0,0 +1,15 @@ +--- +datadog: + apm: + instrumentation: + enabled: true + enabledNamespaces: + - "foo" + - "bar" + targets: + - name: "billing-service" + podSelector: + matchLabels: + app: "billing-service" + ddTraceVersions: + python: "v2" \ No newline at end of file diff --git a/test/datadog/values/instrumentation/valid_enabled.yaml b/test/datadog/values/instrumentation/valid_enabled.yaml new file mode 100644 index 000000000..2e1914f9e --- /dev/null +++ b/test/datadog/values/instrumentation/valid_enabled.yaml @@ -0,0 +1,5 @@ +--- +datadog: + apm: + instrumentation: + enabled: true \ No newline at end of file diff --git a/test/datadog/values/instrumentation/valid_namespace.yaml b/test/datadog/values/instrumentation/valid_namespace.yaml new file mode 100644 index 000000000..223607852 --- /dev/null +++ b/test/datadog/values/instrumentation/valid_namespace.yaml @@ -0,0 +1,10 @@ +--- +datadog: + apm: + instrumentation: + enabled: true + enabledNamespaces: + - "application" + - "test" + libVersions: + python: "v2" \ No newline at end of file diff --git a/test/datadog/values/instrumentation/valid_targets.yaml b/test/datadog/values/instrumentation/valid_targets.yaml new file mode 100644 index 000000000..07bfcf347 --- /dev/null +++ b/test/datadog/values/instrumentation/valid_targets.yaml @@ -0,0 +1,48 @@ +--- +datadog: + apm: + instrumentation: + enabled: true + disabledNamespaces: + - "infra" + - "system" + targets: + - name: "billing-service" + podSelector: + matchLabels: + app: "billing-service" + namespaceSelector: + matchNames: + - "billing-service" + ddTraceVersions: + python: "v2" + - name: "microservices" + podSelector: + matchLabels: + language: "java" + namespaceSelector: + matchLabels: + tracing: "yes" + ddTraceVersions: + java: "v1" + ddTraceConfigs: + - name: "DD_PROFILING_ENABLED" + value: "true" + - name: "enabled-prod-namespaces" + namespaceSelector: + matchLabels: + tracing: "yes" + matchExpressions: + - key: "env" + operator: "In" + values: + - "prod" + ddTraceVersions: + dotnet: "v1" + - name: "unknown-language" + podSelector: + matchLabels: + language: "unknown" + - name: "Default" + ddTraceVersions: + js: "v5"