diff --git a/docs/cluster_agent_setup.md b/docs/cluster_agent_setup.md index c707b5ad1c..dc38a70543 100644 --- a/docs/cluster_agent_setup.md +++ b/docs/cluster_agent_setup.md @@ -73,3 +73,27 @@ datadog-agent-hjlbg 1/1 Running 0 33s ``` [1]: https://github.com/DataDog/datadog-operator/blob/main/examples/datadogagent/datadog-agent-with-clusteragent.yaml + +## Running without the Cluster Agent + +The Cluster Agent is optional. If you don't need cluster-level features (Kubernetes State Metrics Core, Admission Controller, Cluster Checks, External Metrics Server, Orchestrator Explorer, etc.), you can disable it and run the node Agent on its own, for example: [`datadog-agent-without-clusteragent.yaml` file][2]: + +```yaml +apiVersion: datadoghq.com/v2alpha1 +kind: DatadogAgent +metadata: + name: datadog +spec: + global: + clusterName: my-example-cluster + credentials: + apiKey: "" + + override: + clusterAgent: + disabled: true +``` + +With `spec.override.clusterAgent.disabled: true`, no Cluster Agent `Deployment`, `Service`, or RBAC is created, and the node Agent is configured to run without one (`DD_CLUSTER_AGENT_ENABLED` is set to `false`). Any feature under `spec.features` that requires the Cluster Agent (for example `kubeStateMetricsCore`, `admissionController`, `clusterChecks`, `externalMetricsServer`, or `orchestratorExplorer`) is automatically left disabled rather than producing a broken, half-configured deployment — remove `override.clusterAgent.disabled` if you later need any of those features. + +[2]: https://github.com/DataDog/datadog-operator/blob/main/examples/datadogagent/datadog-agent-without-clusteragent.yaml diff --git a/examples/datadogagent/datadog-agent-without-clusteragent.yaml b/examples/datadogagent/datadog-agent-without-clusteragent.yaml new file mode 100644 index 0000000000..8832d8632c --- /dev/null +++ b/examples/datadogagent/datadog-agent-without-clusteragent.yaml @@ -0,0 +1,13 @@ +apiVersion: datadoghq.com/v2alpha1 +kind: DatadogAgent +metadata: + name: datadog +spec: + global: + clusterName: my-example-cluster + credentials: + apiKey: + + override: + clusterAgent: + disabled: true diff --git a/internal/controller/datadogagent/dependencies.go b/internal/controller/datadogagent/dependencies.go index 4a15b0f00f..a52b352733 100644 --- a/internal/controller/datadogagent/dependencies.go +++ b/internal/controller/datadogagent/dependencies.go @@ -15,6 +15,7 @@ import ( v1alpha1 "github.com/DataDog/datadog-operator/api/datadoghq/v1alpha1" "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1" + apiutils "github.com/DataDog/datadog-operator/api/utils" "github.com/DataDog/datadog-operator/internal/controller/datadogagent/common" "github.com/DataDog/datadog-operator/internal/controller/datadogagent/component/clusteragent" "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature" @@ -55,11 +56,25 @@ func (r *Reconciler) manageDDADependenciesWithDDAI(ctx context.Context, logger l return err } - // DCA token - if err := global.AddDCATokenDependencies(logger, instance.GetObjectMeta(), &instance.Spec, &instance.Status, resourceManagers); err != nil { - return err + // DCA token and Service are only needed when a Cluster Agent is actually + // going to be deployed; otherwise they're resources without a consumer. + clusterAgentDisabled := false + if override, ok := instance.Spec.Override[v2alpha1.ClusterAgentComponentName]; ok { + clusterAgentDisabled = apiutils.BoolValue(override.Disabled) + } + if !clusterAgentDisabled { + // DCA token + if err := global.AddDCATokenDependencies(logger, instance.GetObjectMeta(), &instance.Spec, &instance.Status, resourceManagers); err != nil { + return err + } + ensureAutoGeneratedTokenInStatus(instance, newDDAStatus, resourceManagers, logger) + + // DCA service + service := clusteragent.GetClusterAgentService(instance) + if err := resourceManagers.ServiceManager().AddService(service.Name, service.Namespace, service.Spec.Selector, service.Spec.Ports, service.Spec.InternalTrafficPolicy); err != nil { + return err + } } - ensureAutoGeneratedTokenInStatus(instance, newDDAStatus, resourceManagers, logger) // APM Telemetry // ConfigMap stores DatadogAgent resource UID and creation time whether or not DatadogAgentInternal is enabled. @@ -67,12 +82,6 @@ func (r *Reconciler) manageDDADependenciesWithDDAI(ctx context.Context, logger l return err } - // DCA service - service := clusteragent.GetClusterAgentService(instance) - if err := resourceManagers.ServiceManager().AddService(service.Name, service.Namespace, service.Spec.Selector, service.Spec.Ports, service.Spec.InternalTrafficPolicy); err != nil { - return err - } - // Dependencies that can get configs from DDA and DDAI // Example: agent local service for APM, DSD, and OTLP if err := r.addDDASharedDependencies(instance, ddais, resourceManagers); err != nil { diff --git a/internal/controller/datadogagent/feature/admissioncontroller/feature.go b/internal/controller/datadogagent/feature/admissioncontroller/feature.go index 6d705b0263..5fcfb53f48 100644 --- a/internal/controller/datadogagent/feature/admissioncontroller/feature.go +++ b/internal/controller/datadogagent/feature/admissioncontroller/feature.go @@ -110,7 +110,15 @@ func (f *admissionControllerFeature) Configure(dda metav1.Object, ddaSpec *v2alp ac := ddaSpec.Features.AdmissionController - if ac != nil && apiutils.BoolValue(ac.Enabled) { + // The admission controller webhook server runs inside the Cluster Agent; without one + // there's nothing to back the webhook Service, and the API server would block pod + // creation trying to reach it. + clusterAgentDisabled := false + if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok { + clusterAgentDisabled = apiutils.BoolValue(clusterAgent.Disabled) + } + + if !clusterAgentDisabled && ac != nil && apiutils.BoolValue(ac.Enabled) { if ac.Validation != nil && ac.Validation.Enabled != nil { f.validationWebhookConfig = &ValidationConfig{enabled: apiutils.BoolValue(ac.Validation.Enabled)} } diff --git a/internal/controller/datadogagent/feature/admissioncontroller/feature_test.go b/internal/controller/datadogagent/feature/admissioncontroller/feature_test.go index 61a4219cb2..8adfd04bf2 100644 --- a/internal/controller/datadogagent/feature/admissioncontroller/feature_test.go +++ b/internal/controller/datadogagent/feature/admissioncontroller/feature_test.go @@ -36,6 +36,14 @@ func Test_admissionControllerFeature_Configure(t *testing.T) { Build(), WantConfigure: false, }, + { + Name: "Admission Controller enabled but cluster agent disabled", + DDA: testutils.NewDatadogAgentBuilder(). + WithAdmissionControllerEnabled(true). + WithClusterAgentDisabled(true). + Build(), + WantConfigure: false, + }, { Name: "Admission Controller enabled grants CSI driver RBAC unconditionally", DDA: testutils.NewDatadogAgentBuilder(). diff --git a/internal/controller/datadogagent/feature/apm/feature_test.go b/internal/controller/datadogagent/feature/apm/feature_test.go index 198d3f095c..d22b515b77 100644 --- a/internal/controller/datadogagent/feature/apm/feature_test.go +++ b/internal/controller/datadogagent/feature/apm/feature_test.go @@ -106,6 +106,43 @@ func TestAPMConfigureSSIWithoutNodeAPM(t *testing.T) { assert.True(t, feat.shouldEnableLanguageDetection()) } +// TestAPMConfigureSSIClusterAgentDisabled verifies that SSI (including language detection, +// which runs on the Cluster Agent admission controller path) is not configured when the +// Cluster Agent is disabled via override, even though admissionController and SSI are both +// otherwise enabled. This is handled by validateSSISharedComponentPrerequisites (checked via +// shouldConfigureSSI), not by a dedicated override check in this feature. +func TestAPMConfigureSSIClusterAgentDisabled(t *testing.T) { + dda := &v2alpha1.DatadogAgent{ + ObjectMeta: v1.ObjectMeta{ + Name: "datadog", + Namespace: "default", + }, + Spec: v2alpha1.DatadogAgentSpec{ + Features: &v2alpha1.DatadogFeatures{ + AdmissionController: &v2alpha1.AdmissionControllerFeatureConfig{Enabled: ptr.To(true)}, + APM: &v2alpha1.APMFeatureConfig{ + Enabled: ptr.To(false), + SingleStepInstrumentation: &v2alpha1.SingleStepInstrumentation{ + Enabled: ptr.To(true), + LanguageDetection: &v2alpha1.LanguageDetectionConfig{Enabled: ptr.To(true)}, + }, + }, + }, + Override: map[v2alpha1.ComponentName]*v2alpha1.DatadogAgentComponentOverride{ + v2alpha1.ClusterAgentComponentName: { + Disabled: ptr.To(true), + }, + }, + }, + } + + feat := buildAPMFeature(&feature.Options{}).(*apmFeature) + reqComp := feat.Configure(dda, &dda.Spec, nil) + + assert.False(t, reqComp.ClusterAgent.IsEnabled()) + assert.False(t, feat.shouldEnableLanguageDetection()) +} + func TestAPMFeature(t *testing.T) { tests := test.FeatureTestSuite{ { diff --git a/internal/controller/datadogagent/feature/appsec/feature.go b/internal/controller/datadogagent/feature/appsec/feature.go index 28fa89808f..84bd228304 100644 --- a/internal/controller/datadogagent/feature/appsec/feature.go +++ b/internal/controller/datadogagent/feature/appsec/feature.go @@ -110,6 +110,12 @@ func (f *appsecFeature) Configure(dda metav1.Object, ddaSpec *v2alpha1.DatadogAg return feature.RequiredComponents{} } + // AppSec injection is configured and served by the Cluster Agent; without one there's + // nothing to create RBAC for. + if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok && apiutils.BoolValue(clusterAgent.Disabled) { + return feature.RequiredComponents{} + } + var inj *v2alpha1.AppsecInjectorConfig if ddaSpec.Features != nil && ddaSpec.Features.Appsec != nil { inj = ddaSpec.Features.Appsec.Injector diff --git a/internal/controller/datadogagent/feature/appsec/feature_test.go b/internal/controller/datadogagent/feature/appsec/feature_test.go index a7f5c344b0..f40e814111 100644 --- a/internal/controller/datadogagent/feature/appsec/feature_test.go +++ b/internal/controller/datadogagent/feature/appsec/feature_test.go @@ -786,6 +786,21 @@ func TestAppsecFeatureConfigure(t *testing.T) { } } +func TestAppsecFeatureConfigureClusterAgentDisabled(t *testing.T) { + dda := testutils.NewDatadogAgentBuilder(). + WithClusterAgentTag("7.76.0"). + WithClusterAgentDisabled(true). + WithAnnotations(map[string]string{ + AnnotationInjectorEnabled: "true", + }). + Build() + + f := buildAppsecFeature(nil).(*appsecFeature) + reqComp := f.Configure(dda, &dda.Spec, nil) + + assert.False(t, reqComp.IsEnabled(), "AppSec should not be enabled when the cluster agent is disabled") +} + func TestAppsecFeatureManageClusterAgentDisabled(t *testing.T) { // Test that ManageClusterAgent does nothing when feature is disabled dda := testutils.NewDatadogAgentBuilder(). diff --git a/internal/controller/datadogagent/feature/asm/feature.go b/internal/controller/datadogagent/feature/asm/feature.go index 006b2a813a..6dfde6a6c3 100644 --- a/internal/controller/datadogagent/feature/asm/feature.go +++ b/internal/controller/datadogagent/feature/asm/feature.go @@ -56,6 +56,10 @@ func (f *asmFeature) Configure(_ metav1.Object, ddaSpec *v2alpha1.DatadogAgentSp return feature.RequiredComponents{} } + if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok && apiutils.BoolValue(clusterAgent.Disabled) { + return feature.RequiredComponents{} + } + f.threatsEnabled = apiutils.BoolValue(asm.Threats.Enabled) f.iastEnabled = apiutils.BoolValue(asm.IAST.Enabled) f.scaEnabled = apiutils.BoolValue(asm.SCA.Enabled) diff --git a/internal/controller/datadogagent/feature/asm/feature_test.go b/internal/controller/datadogagent/feature/asm/feature_test.go index fd4a3e3295..d46accfafa 100644 --- a/internal/controller/datadogagent/feature/asm/feature_test.go +++ b/internal/controller/datadogagent/feature/asm/feature_test.go @@ -68,6 +68,15 @@ func TestASMFeature(t *testing.T) { WantConfigure: true, ClusterAgent: assertEnv(envVar{name: DDAdmissionControllerAppsecEnabled, value: "true", present: true}), }, + { + Name: "ASM Threats enabled but cluster agent disabled", + DDA: testutils.NewDatadogAgentBuilder(). + WithAdmissionControllerEnabled(true). + WithASMEnabled(true, false, false). + WithClusterAgentDisabled(true). + Build(), + WantConfigure: false, + }, { Name: "ASM Threats enabled, admission controller not enabled", DDA: testutils.NewDatadogAgentBuilder(). diff --git a/internal/controller/datadogagent/feature/autoscaling/feature.go b/internal/controller/datadogagent/feature/autoscaling/feature.go index 95351c2a7f..a1fd2709fd 100644 --- a/internal/controller/datadogagent/feature/autoscaling/feature.go +++ b/internal/controller/datadogagent/feature/autoscaling/feature.go @@ -71,6 +71,12 @@ func (f *autoscalingFeature) Configure(dda metav1.Object, ddaSpec *v2alpha1.Data return feature.RequiredComponents{} } + // Autoscaling decisions are computed and served by the Cluster Agent; without one + // there's no RBAC to create. + if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok && apiutils.BoolValue(clusterAgent.Disabled) { + return feature.RequiredComponents{} + } + if autoscaling.Workload != nil && apiutils.BoolValue(autoscaling.Workload.Enabled) { f.workloadEnabled = true if autoscaling.Workload.InPlaceVerticalScaling != nil { diff --git a/internal/controller/datadogagent/feature/autoscaling/feature_test.go b/internal/controller/datadogagent/feature/autoscaling/feature_test.go index e5a774ce4a..a899ca2665 100644 --- a/internal/controller/datadogagent/feature/autoscaling/feature_test.go +++ b/internal/controller/datadogagent/feature/autoscaling/feature_test.go @@ -119,6 +119,18 @@ func TestAutoscalingFeature(t *testing.T) { tests.Run(t, buildAutoscalingFeature) } +func TestAutoscalingFeature_ClusterAgentDisabled(t *testing.T) { + dda := newAgent(true, true, true, false, false) + dda.Spec.Override = map[v2alpha1.ComponentName]*v2alpha1.DatadogAgentComponentOverride{ + v2alpha1.ClusterAgentComponentName: {Disabled: ptr.To(true)}, + } + + f := buildAutoscalingFeature(nil) + reqComp := f.Configure(dda, &dda.Spec, nil) + + assert.False(t, reqComp.IsEnabled(), "autoscaling should not be enabled when the cluster agent is disabled") +} + func newAgent(workloadEnabled, clusterEnabled, admissionEnabled, clusterSpotEnabled, workloadInPlaceVerticalScalingEnabled bool) *v2alpha1.DatadogAgent { return &v2alpha1.DatadogAgent{ ObjectMeta: metav1.ObjectMeta{ diff --git a/internal/controller/datadogagent/feature/clusterchecks/feature.go b/internal/controller/datadogagent/feature/clusterchecks/feature.go index 08d0bdb47f..d1aeda6832 100644 --- a/internal/controller/datadogagent/feature/clusterchecks/feature.go +++ b/internal/controller/datadogagent/feature/clusterchecks/feature.go @@ -58,6 +58,10 @@ func (f *clusterChecksFeature) ID() feature.IDType { } func (f *clusterChecksFeature) Configure(dda metav1.Object, ddaSpec *v2alpha1.DatadogAgentSpec, _ *v2alpha1.RemoteConfigConfiguration) (reqComp feature.RequiredComponents) { + if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok && apiutils.BoolValue(clusterAgent.Disabled) { + return reqComp + } + if apiutils.BoolValue(ddaSpec.Features.ClusterChecks.Enabled) { f.updateConfigHash(dda, ddaSpec) f.owner = dda diff --git a/internal/controller/datadogagent/feature/clusterchecks/feature_test.go b/internal/controller/datadogagent/feature/clusterchecks/feature_test.go index 4dced2ec45..7f056bcbbb 100644 --- a/internal/controller/datadogagent/feature/clusterchecks/feature_test.go +++ b/internal/controller/datadogagent/feature/clusterchecks/feature_test.go @@ -68,6 +68,14 @@ func TestClusterChecksFeature(t *testing.T) { ClusterAgent: test.NewDefaultComponentTest().WithWantFunc(wantClusterAgentHasExpectedEnvsAndChecksum), Agent: testAgentHasExpectedEnvsWithNoRunners(apicommon.CoreAgentContainerName), }, + { + Name: "cluster checks enabled but cluster agent disabled", + DDA: testutils.NewDatadogAgentBuilder(). + WithClusterChecksEnabled(true). + WithClusterAgentDisabled(true). + Build(), + WantConfigure: false, + }, { Name: "cluster checks enabled and runners not enabled with single container strategy", DDA: testutils.NewDatadogAgentBuilder(). diff --git a/internal/controller/datadogagent/feature/controlplanemonitoring/feature.go b/internal/controller/datadogagent/feature/controlplanemonitoring/feature.go index 658bbf3d34..0ebb374793 100644 --- a/internal/controller/datadogagent/feature/controlplanemonitoring/feature.go +++ b/internal/controller/datadogagent/feature/controlplanemonitoring/feature.go @@ -67,6 +67,12 @@ func (f *controlPlaneMonitoringFeature) Configure(dda metav1.Object, ddaSpec *v2 controlPlaneMonitoring := ddaSpec.Features.ControlPlaneMonitoring + // Control plane monitoring is driven by the Cluster Agent; without one there's no RBAC + // or ConfigMap to create. + if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok && apiutils.BoolValue(clusterAgent.Disabled) { + return reqComp + } + if controlPlaneMonitoring != nil && apiutils.BoolValue(controlPlaneMonitoring.Enabled) { f.enabled = true reqComp.ClusterAgent.IsRequired = new(true) diff --git a/internal/controller/datadogagent/feature/controlplanemonitoring/feature_test.go b/internal/controller/datadogagent/feature/controlplanemonitoring/feature_test.go index c6e27a2cec..e8e84194d9 100644 --- a/internal/controller/datadogagent/feature/controlplanemonitoring/feature_test.go +++ b/internal/controller/datadogagent/feature/controlplanemonitoring/feature_test.go @@ -38,6 +38,14 @@ func Test_controlPlaneMonitoringFeature_Configure(t *testing.T) { Build(), WantConfigure: false, }, + { + Name: "Control Plane Monitoring enabled but cluster agent disabled", + DDA: testutils.NewDatadogAgentBuilder(). + WithControlPlaneMonitoring(true). + WithClusterAgentDisabled(true). + Build(), + WantConfigure: false, + }, { Name: "Control Plane Monitoring enabled with default provider", DDA: testutils.NewInitializedDatadogAgentBuilder(resourcesNamespace, resourcesName). diff --git a/internal/controller/datadogagent/feature/cspm/feature.go b/internal/controller/datadogagent/feature/cspm/feature.go index c7e2aacc98..be85e190f3 100644 --- a/internal/controller/datadogagent/feature/cspm/feature.go +++ b/internal/controller/datadogagent/feature/cspm/feature.go @@ -80,7 +80,14 @@ func (f *cspmFeature) Configure(dda metav1.Object, ddaSpec *v2alpha1.DatadogAgen cspmConfig := ddaSpec.Features.CSPM - if cspmConfig != nil && apiutils.BoolValue(cspmConfig.Enabled) { + // CSPM dispatches its checks via the Cluster Agent; without one there's no RBAC to + // create and the node-side check has nothing to report through. + clusterAgentDisabled := false + if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok { + clusterAgentDisabled = apiutils.BoolValue(clusterAgent.Disabled) + } + + if !clusterAgentDisabled && cspmConfig != nil && apiutils.BoolValue(cspmConfig.Enabled) { f.enable = true f.serviceAccountName = constants.GetClusterAgentServiceAccount(dda.GetName(), ddaSpec) diff --git a/internal/controller/datadogagent/feature/cspm/feature_test.go b/internal/controller/datadogagent/feature/cspm/feature_test.go index 412fb5a32e..4878739eac 100644 --- a/internal/controller/datadogagent/feature/cspm/feature_test.go +++ b/internal/controller/datadogagent/feature/cspm/feature_test.go @@ -83,6 +83,17 @@ func Test_cspmFeature_Configure(t *testing.T) { DDA: ddaCSPMDisabled.DeepCopy(), WantConfigure: false, }, + { + Name: "CSPM enabled but cluster agent disabled", + DDA: func() *v2alpha1.DatadogAgent { + dda := ddaCSPMEnabled.DeepCopy() + dda.Spec.Override = map[v2alpha1.ComponentName]*v2alpha1.DatadogAgentComponentOverride{ + v2alpha1.ClusterAgentComponentName: {Disabled: ptr.To(true)}, + } + return dda + }(), + WantConfigure: false, + }, { Name: "CSPM enabled", DDA: ddaCSPMEnabled, diff --git a/internal/controller/datadogagent/feature/enabledefault/feature.go b/internal/controller/datadogagent/feature/enabledefault/feature.go index 51abd700e3..cb33ba6b94 100644 --- a/internal/controller/datadogagent/feature/enabledefault/feature.go +++ b/internal/controller/datadogagent/feature/enabledefault/feature.go @@ -7,10 +7,13 @@ package enabledefault import ( "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 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" + "github.com/DataDog/datadog-operator/internal/controller/datadogagent/common" "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature" ) @@ -32,8 +35,9 @@ func buildDefaultFeature(options *feature.Options) feature.Feature { } type defaultFeature struct { - owner metav1.Object - logger logr.Logger + owner metav1.Object + clusterAgentDisabled bool + logger logr.Logger } // ID returns the ID of the Feature @@ -45,11 +49,24 @@ func (f *defaultFeature) Configure(dda metav1.Object, ddaSpec *v2alpha1.DatadogA trueValue := true f.owner = dda + if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok { + f.clusterAgentDisabled = apiutils.BoolValue(clusterAgent.Disabled) + } + + // IsRequired: false (rather than nil) tells the merge that the Cluster Agent is + // explicitly disabled via override, so checkComponentEnabledWithOverride resolves + // this as a clean disable instead of an override/feature conflict, as long as no + // other feature still requires it. + clusterAgentRequired := feature.RequiredComponent{ + IsRequired: &trueValue, + Containers: []apicommon.AgentContainerName{apicommon.ClusterAgentContainerName}, + } + if f.clusterAgentDisabled { + clusterAgentRequired = feature.RequiredComponent{IsRequired: new(false)} + } + return feature.RequiredComponents{ - ClusterAgent: feature.RequiredComponent{ - IsRequired: &trueValue, - Containers: []apicommon.AgentContainerName{apicommon.ClusterAgentContainerName}, - }, + ClusterAgent: clusterAgentRequired, Agent: feature.RequiredComponent{ IsRequired: &trueValue, Containers: []apicommon.AgentContainerName{}, @@ -73,12 +90,30 @@ func (f *defaultFeature) ManageClusterAgent(managers feature.PodTemplateManagers // if SingleContainerStrategy is enabled and can be used with the configured feature set. // It should do nothing if the feature doesn't need to configure it. func (f *defaultFeature) ManageSingleContainerNodeAgent(managers feature.PodTemplateManagers) error { - return nil + return f.overrideClusterAgentEnabledEnvVar(managers) } // ManageNodeAgent allows a feature to configure the Node Agent's corev1.PodTemplateSpec // It should do nothing if the feature doesn't need to configure it. func (f *defaultFeature) ManageNodeAgent(managers feature.PodTemplateManagers) error { + return f.overrideClusterAgentEnabledEnvVar(managers) +} + +// overrideClusterAgentEnabledEnvVar corrects DD_CLUSTER_AGENT_ENABLED, which the default pod +// template scaffolding (component/agent/default.go) hardcodes to "true" on every agent +// container regardless of whether a Cluster Agent is actually being deployed. +func (f *defaultFeature) overrideClusterAgentEnabledEnvVar(managers feature.PodTemplateManagers) error { + if !f.clusterAgentDisabled { + return nil + } + envVar := &corev1.EnvVar{ + Name: common.DDClusterAgentEnabled, + Value: "false", + } + managers.EnvVar().AddEnvVar(envVar) + // AddEnvVar only reaches regular containers; the init-config init container builds its + // env vars from the same hardcoded-true default and needs the override too. + managers.EnvVar().AddEnvVarToInitContainer(apicommon.InitConfigContainerName, envVar) return nil } diff --git a/internal/controller/datadogagent/feature/enabledefault/feature_test.go b/internal/controller/datadogagent/feature/enabledefault/feature_test.go new file mode 100644 index 0000000000..bb64d6ebde --- /dev/null +++ b/internal/controller/datadogagent/feature/enabledefault/feature_test.go @@ -0,0 +1,131 @@ +// 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 enabledefault + +import ( + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + + apicommon "github.com/DataDog/datadog-operator/api/datadoghq/common" + "github.com/DataDog/datadog-operator/internal/controller/datadogagent/common" + "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature/fake" + mergerfake "github.com/DataDog/datadog-operator/internal/controller/datadogagent/merger/fake" + "github.com/DataDog/datadog-operator/pkg/testutils" +) + +func Test_defaultFeature_ClusterAgentEnabledEnvVar(t *testing.T) { + tests := []struct { + name string + clusterAgentDisabled bool + wantClusterAgentValue string + }{ + { + name: "cluster agent enabled (default)", + clusterAgentDisabled: false, + wantClusterAgentValue: "", + }, + { + name: "cluster agent disabled", + clusterAgentDisabled: true, + wantClusterAgentValue: "false", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + builder := testutils.NewDatadogAgentBuilder() + if tt.clusterAgentDisabled { + builder = builder.WithClusterAgentDisabled(true) + } + dda := builder.Build() + + f := buildDefaultFeature(nil).(*defaultFeature) + f.Configure(dda, &dda.Spec, nil) + + mgr := fake.NewPodTemplateManagers(t, corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + {Name: "agent"}, + }, + }, + }) + + err := f.ManageNodeAgent(mgr) + assert.NoError(t, err) + + envVars := mgr.EnvVarMgr.EnvVarsByC[mergerfake.AllContainers] + var gotValue string + var found bool + for _, e := range envVars { + if e.Name == common.DDClusterAgentEnabled { + gotValue = e.Value + found = true + } + } + + if tt.clusterAgentDisabled { + assert.True(t, found, "expected DD_CLUSTER_AGENT_ENABLED to be explicitly overridden") + assert.Equal(t, tt.wantClusterAgentValue, gotValue) + } else { + assert.False(t, found, "should not override DD_CLUSTER_AGENT_ENABLED when the cluster agent is enabled") + } + + initEnvVars := mgr.EnvVarMgr.EnvVarsByC[apicommon.InitConfigContainerName] + var initFound bool + var initValue string + for _, e := range initEnvVars { + if e.Name == common.DDClusterAgentEnabled { + initFound = true + initValue = e.Value + } + } + if tt.clusterAgentDisabled { + assert.True(t, initFound, "expected DD_CLUSTER_AGENT_ENABLED to be explicitly overridden on the init-config container") + assert.Equal(t, tt.wantClusterAgentValue, initValue) + } else { + assert.False(t, initFound, "should not override DD_CLUSTER_AGENT_ENABLED on the init-config container when the cluster agent is enabled") + } + }) + } +} + +// Test_defaultFeature_Configure_ClusterAgentRequired verifies that, when the Cluster Agent is +// disabled via override, Configure resolves ClusterAgent.IsRequired to an explicit false rather +// than leaving it true (or nil). An explicit false merges with any other feature's requirement +// as "component is disabled" rather than "feature wants it but override disables it", so +// checkComponentEnabledWithOverride resolves this as a clean disable instead of persisting an +// OverrideReconcileConflict status condition on an otherwise legitimate no-Cluster-Agent setup. +func Test_defaultFeature_Configure_ClusterAgentRequired(t *testing.T) { + tests := []struct { + name string + clusterAgentDisabled bool + wantIsEnabled bool + }{ + {name: "cluster agent enabled (default)", clusterAgentDisabled: false, wantIsEnabled: true}, + {name: "cluster agent disabled", clusterAgentDisabled: true, wantIsEnabled: false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + builder := testutils.NewDatadogAgentBuilder() + if tt.clusterAgentDisabled { + builder = builder.WithClusterAgentDisabled(true) + } + dda := builder.Build() + + f := buildDefaultFeature(nil) + reqComp := f.Configure(dda, &dda.Spec, nil) + + assert.Equal(t, tt.wantIsEnabled, reqComp.ClusterAgent.IsEnabled()) + if tt.clusterAgentDisabled { + assert.NotNil(t, reqComp.ClusterAgent.IsRequired) + assert.False(t, *reqComp.ClusterAgent.IsRequired) + } + }) + } +} diff --git a/internal/controller/datadogagent/feature/eventcollection/feature.go b/internal/controller/datadogagent/feature/eventcollection/feature.go index 45a3b1bd5c..1636b452f5 100644 --- a/internal/controller/datadogagent/feature/eventcollection/feature.go +++ b/internal/controller/datadogagent/feature/eventcollection/feature.go @@ -62,6 +62,12 @@ func (f *eventCollectionFeature) ID() feature.IDType { func (f *eventCollectionFeature) Configure(dda metav1.Object, ddaSpec *v2alpha1.DatadogAgentSpec, _ *v2alpha1.RemoteConfigConfiguration) (reqComp feature.RequiredComponents) { f.owner = dda + // Event collection is configured using the Cluster Agent only; without one there's no + // RBAC to create. + if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok && apiutils.BoolValue(clusterAgent.Disabled) { + return reqComp + } + // v2alpha1 configures event collection using the cluster agent only // leader election is enabled by default if ddaSpec.Features != nil && ddaSpec.Features.EventCollection != nil && apiutils.BoolValue(ddaSpec.Features.EventCollection.CollectKubernetesEvents) { diff --git a/internal/controller/datadogagent/feature/eventcollection/feature_test.go b/internal/controller/datadogagent/feature/eventcollection/feature_test.go index b83627819a..a73d36bf31 100644 --- a/internal/controller/datadogagent/feature/eventcollection/feature_test.go +++ b/internal/controller/datadogagent/feature/eventcollection/feature_test.go @@ -34,6 +34,14 @@ func Test_eventCollectionFeature_Configure(t *testing.T) { Build(), WantConfigure: false, }, + { + Name: "Event Collection enabled but cluster agent disabled", + DDA: testutils.NewDatadogAgentBuilder(). + WithEventCollectionKubernetesEvents(true). + WithClusterAgentDisabled(true). + Build(), + WantConfigure: false, + }, { Name: "Event Collection enabled", DDA: testutils.NewDatadogAgentBuilder(). diff --git a/internal/controller/datadogagent/feature/externalmetrics/feature.go b/internal/controller/datadogagent/feature/externalmetrics/feature.go index b8d765b32e..8195863f78 100644 --- a/internal/controller/datadogagent/feature/externalmetrics/feature.go +++ b/internal/controller/datadogagent/feature/externalmetrics/feature.go @@ -77,6 +77,12 @@ func (f *externalMetricsFeature) Configure(dda metav1.Object, ddaSpec *v2alpha1. f.owner = dda em := ddaSpec.Features.ExternalMetricsServer + // The external metrics server is served by the Cluster Agent; without one there's + // nothing to back the APIService or create RBAC for. + if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok && apiutils.BoolValue(clusterAgent.Disabled) { + return reqComp + } + if em != nil && apiutils.BoolValue(em.Enabled) { // By default, we register the external metrics endpoint f.registerAPIService = em.RegisterAPIService == nil || apiutils.BoolValue(em.RegisterAPIService) diff --git a/internal/controller/datadogagent/feature/externalmetrics/feature_test.go b/internal/controller/datadogagent/feature/externalmetrics/feature_test.go index 7acc951df2..a6b81eceac 100644 --- a/internal/controller/datadogagent/feature/externalmetrics/feature_test.go +++ b/internal/controller/datadogagent/feature/externalmetrics/feature_test.go @@ -105,6 +105,18 @@ func TestExternalMetricsFeature(t *testing.T) { tests.Run(t, buildExternalMetricsFeature) } +func TestExternalMetricsFeature_ClusterAgentDisabled(t *testing.T) { + dda := newAgent(true, true, false, false, v2alpha1.DatadogCredentials{}) + dda.Spec.Override = map[v2alpha1.ComponentName]*v2alpha1.DatadogAgentComponentOverride{ + v2alpha1.ClusterAgentComponentName: {Disabled: ptr.To(true)}, + } + + f := buildExternalMetricsFeature(nil) + reqComp := f.Configure(dda, &dda.Spec, nil) + + assert.False(t, reqComp.IsEnabled(), "external metrics should not be enabled when the cluster agent is disabled") +} + func newAgent(enabled, registerAPIService, useDDM, wpaController bool, secret v2alpha1.DatadogCredentials) *v2alpha1.DatadogAgent { return &v2alpha1.DatadogAgent{ Spec: v2alpha1.DatadogAgentSpec{ diff --git a/internal/controller/datadogagent/feature/helmcheck/feature.go b/internal/controller/datadogagent/feature/helmcheck/feature.go index b9092f9468..9413262875 100644 --- a/internal/controller/datadogagent/feature/helmcheck/feature.go +++ b/internal/controller/datadogagent/feature/helmcheck/feature.go @@ -65,6 +65,12 @@ func (f *helmCheckFeature) Configure(dda metav1.Object, ddaSpec *v2alpha1.Datado f.owner = dda helmCheck := ddaSpec.Features.HelmCheck + // The helm check only ever runs inside the Cluster Agent (or Cluster Check Runners it + // dispatches to); without one there's no RBAC to create. + if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok && apiutils.BoolValue(clusterAgent.Disabled) { + return reqComp + } + if helmCheck != nil && apiutils.BoolValue(helmCheck.Enabled) { reqComp.ClusterAgent.IsRequired = new(true) reqComp.ClusterAgent.Containers = []apicommon.AgentContainerName{apicommon.ClusterAgentContainerName} diff --git a/internal/controller/datadogagent/feature/helmcheck/feature_test.go b/internal/controller/datadogagent/feature/helmcheck/feature_test.go index 3486c49295..b231f295d0 100644 --- a/internal/controller/datadogagent/feature/helmcheck/feature_test.go +++ b/internal/controller/datadogagent/feature/helmcheck/feature_test.go @@ -40,6 +40,14 @@ func Test_helmCheckFeature_Configure(t *testing.T) { Build(), WantConfigure: false, }, + { + Name: "Helm check enabled but cluster agent disabled", + DDA: testutils.NewDatadogAgentBuilder(). + WithHelmCheckEnabled(true). + WithClusterAgentDisabled(true). + Build(), + WantConfigure: false, + }, { Name: "Helm check enabled", DDA: testutils.NewInitializedDatadogAgentBuilder(resourcesNamespace, resourcesName). diff --git a/internal/controller/datadogagent/feature/instrumentationcrd/feature.go b/internal/controller/datadogagent/feature/instrumentationcrd/feature.go index 3ef3f7be90..6ed9eb1a4e 100644 --- a/internal/controller/datadogagent/feature/instrumentationcrd/feature.go +++ b/internal/controller/datadogagent/feature/instrumentationcrd/feature.go @@ -12,6 +12,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" "github.com/DataDog/datadog-operator/internal/controller/datadogagent/common" "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature" featureutils "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature/utils" @@ -61,6 +62,13 @@ func (f *instrumentationCRDFeature) Configure(dda metav1.Object, ddaSpec *v2alph return feature.RequiredComponents{} } + // The instrumentation-checks autodiscovery provider requires a live Cluster Agent to serve + // configs to the node agent; without one the node agent just spams connection errors trying + // to reach a Cluster Agent Kubernetes Service that doesn't exist. + if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok && apiutils.BoolValue(clusterAgent.Disabled) { + return feature.RequiredComponents{} + } + // If the cluster agent version is explicitly set and below the minimum, skip enabling. if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok && clusterAgent.Image != nil { version := common.GetAgentVersionFromImage(*clusterAgent.Image) diff --git a/internal/controller/datadogagent/feature/instrumentationcrd/feature_test.go b/internal/controller/datadogagent/feature/instrumentationcrd/feature_test.go index 7264a7c546..31365458b3 100644 --- a/internal/controller/datadogagent/feature/instrumentationcrd/feature_test.go +++ b/internal/controller/datadogagent/feature/instrumentationcrd/feature_test.go @@ -97,6 +97,17 @@ func Test_instrumentationCRDFeature_Configure(t *testing.T) { ClusterAgent: instrumentationCRDClusterAgentFunc(false), Agent: instrumentationCRDAgentFunc(false), }, + { + Name: "InstrumentationCRD disabled when cluster agent is disabled, even if versions meet minimum", + DDA: testutils.NewInitializedDatadogAgentBuilder(resourcesNamespace, resourcesName). + WithClusterAgentImage("cluster-agent:7.82.0"). + WithNodeAgentImage("agent:7.82.0"). + WithClusterAgentDisabled(true). + Build(), + WantConfigure: false, + ClusterAgent: instrumentationCRDClusterAgentFunc(false), + Agent: instrumentationCRDAgentFunc(false), + }, } tests.Run(t, buildInstrumentationCRDFeature) diff --git a/internal/controller/datadogagent/feature/kubernetesactions/feature.go b/internal/controller/datadogagent/feature/kubernetesactions/feature.go index dbe186a372..9d0929e38f 100644 --- a/internal/controller/datadogagent/feature/kubernetesactions/feature.go +++ b/internal/controller/datadogagent/feature/kubernetesactions/feature.go @@ -67,6 +67,11 @@ func (f *kubernetesActionsFeature) Configure(dda metav1.Object, ddaSpec *v2alpha return reqComp } + // Kubernetes Actions runs inside the Cluster Agent; without one there's no RBAC to create. + if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok && apiutils.BoolValue(clusterAgent.Disabled) { + return reqComp + } + if !utils.IsAboveMinVersion(clusterAgentVersion(ddaSpec), ClusterAgentMinVersion, nil) { f.logger.V(1).Info("cluster agent version is too low for Kubernetes Actions", "min", ClusterAgentMinVersion) return reqComp diff --git a/internal/controller/datadogagent/feature/kubernetesactions/feature_test.go b/internal/controller/datadogagent/feature/kubernetesactions/feature_test.go index 86a8a39724..b573a017fa 100644 --- a/internal/controller/datadogagent/feature/kubernetesactions/feature_test.go +++ b/internal/controller/datadogagent/feature/kubernetesactions/feature_test.go @@ -35,6 +35,14 @@ func Test_kubernetesActionsFeature_Configure(t *testing.T) { Build(), WantConfigure: false, }, + { + Name: "KubernetesActions enabled but cluster agent disabled", + DDA: testutils.NewDatadogAgentBuilder(). + WithKubernetesActionsEnabled(true). + WithClusterAgentDisabled(true). + Build(), + WantConfigure: false, + }, { Name: "KubernetesActions enabled but cluster agent version too low", DDA: testutils.NewDatadogAgentBuilder(). diff --git a/internal/controller/datadogagent/feature/kubernetesstatecore/feature.go b/internal/controller/datadogagent/feature/kubernetesstatecore/feature.go index 45d5b1dcac..e529890c85 100644 --- a/internal/controller/datadogagent/feature/kubernetesstatecore/feature.go +++ b/internal/controller/datadogagent/feature/kubernetesstatecore/feature.go @@ -94,6 +94,14 @@ func (f *ksmFeature) Configure(dda metav1.Object, ddaSpec *v2alpha1.DatadogAgent f.owner = dda var output feature.RequiredComponents + // This check only ever runs inside the Cluster Agent (or Cluster Check Runners it + // dispatches to) — without a live Cluster Agent there's no code path for it to run at + // all, and creating its RBAC/ConfigMap would just leave them bound to a nonexistent + // ServiceAccount. + if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok && apiutils.BoolValue(clusterAgent.Disabled) { + return output + } + if ddaSpec.Features != nil && ddaSpec.Features.KubeStateMetricsCore != nil && apiutils.BoolValue(ddaSpec.Features.KubeStateMetricsCore.Enabled) { output.ClusterAgent.IsRequired = new(true) output.ClusterAgent.Containers = []apicommon.AgentContainerName{apicommon.ClusterAgentContainerName} diff --git a/internal/controller/datadogagent/feature/kubernetesstatecore/feature_test.go b/internal/controller/datadogagent/feature/kubernetesstatecore/feature_test.go index 57c96920ed..d003481112 100644 --- a/internal/controller/datadogagent/feature/kubernetesstatecore/feature_test.go +++ b/internal/controller/datadogagent/feature/kubernetesstatecore/feature_test.go @@ -48,6 +48,14 @@ func Test_ksmFeature_Configure(t *testing.T) { Build(), WantConfigure: false, }, + { + Name: "ksm-core enabled but cluster agent disabled", + DDA: testutils.NewDatadogAgentBuilder(). + WithKSMEnabled(true). + WithClusterAgentDisabled(true). + Build(), + WantConfigure: false, + }, { Name: "ksm-core enabled", DDA: testutils.NewDatadogAgentBuilder(). diff --git a/internal/controller/datadogagent/feature/orchestratorexplorer/feature.go b/internal/controller/datadogagent/feature/orchestratorexplorer/feature.go index b1dd8ede82..c1c9eb9435 100644 --- a/internal/controller/datadogagent/feature/orchestratorexplorer/feature.go +++ b/internal/controller/datadogagent/feature/orchestratorexplorer/feature.go @@ -51,6 +51,7 @@ func buildOrchestratorExplorerFeature(options *feature.Options) feature.Feature type orchestratorExplorerFeature struct { enabled bool + clusterAgentDisabled bool runInClusterChecksRunner bool scrubContainers bool collectKubernetesNetworkResources bool @@ -82,9 +83,18 @@ func (f *orchestratorExplorerFeature) Configure(dda metav1.Object, ddaSpec *v2al // Merge configuration from Status.RemoteConfigConfiguration into the Spec f.mergeConfigs(ddaSpec, ddaRCStatus) + // This check only ever runs inside the Cluster Agent (or Cluster Check Runners it + // dispatches to) — without a live Cluster Agent there's no code path for it to run at + // all, so treat it as disabled and skip requiring/configuring the Cluster Agent side + // (ManageDependencies also no-ops below) to avoid creating RBAC bound to a nonexistent + // ServiceAccount. The node agent still gets the explicit disable env var below. + if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok && apiutils.BoolValue(clusterAgent.Disabled) { + f.clusterAgentDisabled = true + } + orchestratorExplorer := ddaSpec.Features.OrchestratorExplorer - if orchestratorExplorer != nil && apiutils.BoolValue(orchestratorExplorer.Enabled) { + if !f.clusterAgentDisabled && orchestratorExplorer != nil && apiutils.BoolValue(orchestratorExplorer.Enabled) { f.enabled = true reqComp.ClusterAgent.IsRequired = new(true) reqComp.Agent.IsRequired = new(true) @@ -133,7 +143,9 @@ func (f *orchestratorExplorerFeature) Configure(dda metav1.Object, ddaSpec *v2al } } - reqComp.ClusterAgent.Containers = []apicommon.AgentContainerName{apicommon.ClusterAgentContainerName} + if !f.clusterAgentDisabled { + reqComp.ClusterAgent.Containers = []apicommon.AgentContainerName{apicommon.ClusterAgentContainerName} + } reqContainers := []apicommon.AgentContainerName{apicommon.CoreAgentContainerName} // Process Agent is not required as of agent version 7.51.0 if nodeAgent, ok := ddaSpec.Override[v2alpha1.NodeAgentComponentName]; ok { @@ -173,6 +185,10 @@ func (f *orchestratorExplorerFeature) mergeConfigs(ddaSpec *v2alpha1.DatadogAgen // ManageDependencies allows a feature to manage its dependencies. // Feature's dependencies should be added in the store. func (f *orchestratorExplorerFeature) ManageDependencies(managers feature.ResourceManagers) error { + if f.clusterAgentDisabled { + return nil + } + // Create a configMap if CustomConfig.ConfigData is provided and CustomConfig.ConfigMap == nil, // OR if the default configMap is needed. configCM, err := f.buildOrchestratorExplorerConfigMap() diff --git a/internal/controller/datadogagent/feature/orchestratorexplorer/feature_test.go b/internal/controller/datadogagent/feature/orchestratorexplorer/feature_test.go index 1c1dd79336..7082a854b8 100644 --- a/internal/controller/datadogagent/feature/orchestratorexplorer/feature_test.go +++ b/internal/controller/datadogagent/feature/orchestratorexplorer/feature_test.go @@ -59,6 +59,23 @@ func Test_orchestratorExplorerFeature_Configure(t *testing.T) { Build(), WantConfigure: true, }, + { + Name: "orchestrator explorer enabled but cluster agent disabled", + DDA: testutils.NewDatadogAgentBuilder(). + WithOrchestratorExplorerEnabled(true). + WithClusterAgentDisabled(true). + Build(), + WantConfigure: true, + WantDependenciesFunc: func(t testing.TB, sc store.StoreClient) { + _, found := sc.Get(kubernetes.ClusterRolesKind, "", "-orch-exp-dca") + assert.False(t, found, "should not create a ClusterRole bound to a nonexistent cluster agent ServiceAccount") + }, + Agent: test.NewDefaultComponentTest().WithWantFunc(func(t testing.TB, mgrInterface feature.PodTemplateManagers) { + mgr := mgrInterface.(*fake.PodTemplateManagers) + envVars := mgr.EnvVarMgr.EnvVarsByC[apicommon.CoreAgentContainerName] + assert.Contains(t, envVars, &corev1.EnvVar{Name: DDOrchestratorExplorerEnabled, Value: "false"}) + }), + }, { Name: "orchestrator explorer enabled", DDA: testutils.NewDatadogAgentBuilder(). diff --git a/internal/controller/datadogagent/feature/privateactionrunner/feature.go b/internal/controller/datadogagent/feature/privateactionrunner/feature.go index 35c5d03c6d..c99bb4e770 100644 --- a/internal/controller/datadogagent/feature/privateactionrunner/feature.go +++ b/internal/controller/datadogagent/feature/privateactionrunner/feature.go @@ -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" "github.com/DataDog/datadog-operator/internal/controller/datadogagent/common" "github.com/DataDog/datadog-operator/internal/controller/datadogagent/experimental" "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature" @@ -101,8 +102,14 @@ func (f *privateActionRunnerFeature) Configure(dda metav1.Object, ddaSpec *v2alp } } - // Check for Cluster Agent configuration (annotation-based) - if featureutils.HasFeatureEnableAnnotation(dda, featureutils.EnableClusterAgentPrivateActionRunnerAnnotation) { + // Check for Cluster Agent configuration (annotation-based). Skipped when the Cluster Agent + // is disabled via override: otherwise this would still require a Cluster Agent and create + // its ConfigMap/RBAC with nothing to deploy them onto. + clusterAgentDisabled := false + if override, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok { + clusterAgentDisabled = apiutils.BoolValue(override.Disabled) + } + if !clusterAgentDisabled && featureutils.HasFeatureEnableAnnotation(dda, featureutils.EnableClusterAgentPrivateActionRunnerAnnotation) { // Use config data from annotation directly, or fall back to default if configData, ok := featureutils.GetFeatureConfigAnnotation(dda, featureutils.ClusterAgentPrivateActionRunnerConfigDataAnnotation); ok { f.clusterConfigData = configData diff --git a/internal/controller/datadogagent/feature/privateactionrunner/feature_test.go b/internal/controller/datadogagent/feature/privateactionrunner/feature_test.go index 3512977ee4..c69b80ea77 100644 --- a/internal/controller/datadogagent/feature/privateactionrunner/feature_test.go +++ b/internal/controller/datadogagent/feature/privateactionrunner/feature_test.go @@ -711,6 +711,36 @@ func Test_privateActionRunnerFeature_ConfigureClusterAgent(t *testing.T) { } } +// Test_privateActionRunnerFeature_ConfigureClusterAgent_ClusterAgentDisabled verifies that the +// cluster-side annotation is ignored when the Cluster Agent is disabled via override, so this +// feature doesn't require a Cluster Agent or create its ConfigMap/RBAC with nothing to deploy +// them onto. +func Test_privateActionRunnerFeature_ConfigureClusterAgent_ClusterAgentDisabled(t *testing.T) { + f := buildPrivateActionRunnerFeature(nil) + dda := &v2alpha1.DatadogAgent{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "cluster-agent.datadoghq.com/private-action-runner-enabled": "true", + }, + }, + } + ddaSpec := &v2alpha1.DatadogAgentSpec{ + Override: map[v2alpha1.ComponentName]*v2alpha1.DatadogAgentComponentOverride{ + v2alpha1.ClusterAgentComponentName: { + Disabled: new(true), + }, + }, + } + + reqComp := f.Configure(dda, ddaSpec, nil) + + assert.False(t, reqComp.ClusterAgent.IsEnabled()) + + parFeat, ok := f.(*privateActionRunnerFeature) + require.True(t, ok) + assert.Nil(t, parFeat.clusterConfig, "clusterConfig should not be set when the cluster agent is disabled") +} + func Test_privateActionRunnerFeature_ManageClusterAgent_ConfigMap(t *testing.T) { testScheme := runtime.NewScheme() _ = corev1.AddToScheme(testScheme) diff --git a/internal/controller/datadogagent/feature/prometheusscrape/feature.go b/internal/controller/datadogagent/feature/prometheusscrape/feature.go index 4161d78bf1..0b495b09cd 100644 --- a/internal/controller/datadogagent/feature/prometheusscrape/feature.go +++ b/internal/controller/datadogagent/feature/prometheusscrape/feature.go @@ -64,12 +64,19 @@ func (f *prometheusScrapeFeature) Configure(_ metav1.Object, ddaSpec *v2alpha1.D apicommon.CoreAgentContainerName, }, }, - ClusterAgent: feature.RequiredComponent{ + } + + clusterAgentDisabled := false + if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok { + clusterAgentDisabled = apiutils.BoolValue(clusterAgent.Disabled) + } + if !clusterAgentDisabled { + reqComp.ClusterAgent = feature.RequiredComponent{ IsRequired: new(true), Containers: []apicommon.AgentContainerName{ apicommon.ClusterAgentContainerName, }, - }, + } } } diff --git a/internal/controller/datadogagent/feature/prometheusscrape/feature_test.go b/internal/controller/datadogagent/feature/prometheusscrape/feature_test.go index 694ba74116..8faca6faf8 100644 --- a/internal/controller/datadogagent/feature/prometheusscrape/feature_test.go +++ b/internal/controller/datadogagent/feature/prometheusscrape/feature_test.go @@ -211,11 +211,51 @@ func Test_prometheusScrapeFeature_Configure(t *testing.T) { }, ), }, + { + Name: "Prometheus scrape enabled but cluster agent disabled", + DDA: testutils.NewDatadogAgentBuilder(). + WithPrometheusScrapeEnabled(true). + WithClusterAgentDisabled(true). + Build(), + WantConfigure: true, + Agent: test.NewDefaultComponentTest().WithWantFunc( + func(t testing.TB, mgrInterface feature.PodTemplateManagers) { + wantEnvVars := []*corev1.EnvVar{ + { + Name: DDPrometheusScrapeEnabled, + Value: "true", + }, + { + Name: DDPrometheusScrapeServiceEndpoints, + Value: "false", + }, + } + assertContainerEnvVars(t, mgrInterface, apicommon.CoreAgentContainerName, wantEnvVars) + }, + ), + }, } tests.Run(t, buildPrometheusScrapeFeature) } +// Test_prometheusScrapeFeature_Configure_ClusterAgentDisabled verifies that, when the cluster +// agent is disabled via override, Configure does not require it or declare it configured, even +// though Prometheus scrape is enabled and still runs node-side. +func Test_prometheusScrapeFeature_Configure_ClusterAgentDisabled(t *testing.T) { + dda := testutils.NewDatadogAgentBuilder(). + WithPrometheusScrapeEnabled(true). + WithClusterAgentDisabled(true). + Build() + + f := buildPrometheusScrapeFeature(nil) + reqComp := f.Configure(dda, &dda.Spec, nil) + + assert.False(t, reqComp.ClusterAgent.IsEnabled()) + assert.Empty(t, reqComp.ClusterAgent.Containers) + assert.True(t, reqComp.Agent.IsEnabled()) +} + func assertContainerEnvVars(t testing.TB, mgrInterface feature.PodTemplateManagers, containerName apicommon.AgentContainerName, wantEnvVars []*corev1.EnvVar) { mgr := mgrInterface.(*fake.PodTemplateManagers) envVars := mgr.EnvVarMgr.EnvVarsByC[containerName] diff --git a/internal/controller/datadogagent/feature/remoteconfig/feature.go b/internal/controller/datadogagent/feature/remoteconfig/feature.go index ff472d5dd8..092377e310 100644 --- a/internal/controller/datadogagent/feature/remoteconfig/feature.go +++ b/internal/controller/datadogagent/feature/remoteconfig/feature.go @@ -64,6 +64,10 @@ func (f *rcFeature) ID() feature.IDType { // Configure is used to configure the feature from a v2alpha1.DatadogAgent instance. func (f *rcFeature) Configure(_ metav1.Object, ddaSpec *v2alpha1.DatadogAgentSpec, _ *v2alpha1.RemoteConfigConfiguration) (reqComp feature.RequiredComponents) { + clusterAgentDisabled := false + if clusterAgent, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok { + clusterAgentDisabled = apiutils.BoolValue(clusterAgent.Disabled) + } if ddaSpec.Features != nil && ddaSpec.Features.RemoteConfiguration != nil && ddaSpec.Features.RemoteConfiguration.Enabled != nil { // If a value exists, explicitly enable or disable Remote Config and override the default @@ -73,12 +77,16 @@ func (f *rcFeature) Configure(_ metav1.Object, ddaSpec *v2alpha1.DatadogAgentSpe // Ref: https://github.com/DataDog/datadog-operator/blob/c4b6e498048a11fbe99d1ea51d2870c6be578799/internal/controller/datadogagent/feature/types.go#L37 if f.enabled { reqComp.Agent.IsRequired = ddaSpec.Features.RemoteConfiguration.Enabled - reqComp.ClusterAgent.IsRequired = ddaSpec.Features.RemoteConfiguration.Enabled + if !clusterAgentDisabled { + reqComp.ClusterAgent.IsRequired = ddaSpec.Features.RemoteConfiguration.Enabled + } } } reqComp.Agent.Containers = []apicommon.AgentContainerName{apicommon.CoreAgentContainerName} - reqComp.ClusterAgent.Containers = []apicommon.AgentContainerName{apicommon.ClusterAgentContainerName} + if !clusterAgentDisabled { + reqComp.ClusterAgent.Containers = []apicommon.AgentContainerName{apicommon.ClusterAgentContainerName} + } return reqComp } diff --git a/internal/controller/datadogagent/feature/remoteconfig/feature_test.go b/internal/controller/datadogagent/feature/remoteconfig/feature_test.go index 112c54b797..9dc7c084e3 100644 --- a/internal/controller/datadogagent/feature/remoteconfig/feature_test.go +++ b/internal/controller/datadogagent/feature/remoteconfig/feature_test.go @@ -49,11 +49,37 @@ func Test_rcFeature_Configure(t *testing.T) { Agent: rcAgentNodeWantFunc(false), ClusterAgent: rcClusterAgentNodeWantFunc(false), }, + { + Name: "RC enabled but cluster agent disabled", + DDA: testutils.NewDatadogAgentBuilder(). + WithRemoteConfigEnabled(true). + WithClusterAgentDisabled(true). + Build(), + WantConfigure: true, + Agent: rcAgentNodeWantFunc(true), + }, } tests.Run(t, buildRCFeature) } +// Test_rcFeature_Configure_ClusterAgentDisabled verifies that, when the cluster agent is +// disabled via override, Configure does not require it or declare it configured, even though +// remote config is enabled and still runs node-side. +func Test_rcFeature_Configure_ClusterAgentDisabled(t *testing.T) { + dda := testutils.NewDatadogAgentBuilder(). + WithRemoteConfigEnabled(true). + WithClusterAgentDisabled(true). + Build() + + f := buildRCFeature(nil) + reqComp := f.Configure(dda, &dda.Spec, nil) + + assert.False(t, reqComp.ClusterAgent.IsEnabled()) + assert.Empty(t, reqComp.ClusterAgent.Containers) + assert.True(t, reqComp.Agent.IsEnabled()) +} + func rcAgentNodeWantFunc(rcEnabled bool) *test.ComponentTest { return test.NewDefaultComponentTest().WithWantFunc( func(t testing.TB, mgrInterface feature.PodTemplateManagers) { diff --git a/internal/controller/datadogagent/feature/servicediscovery/feature.go b/internal/controller/datadogagent/feature/servicediscovery/feature.go index 6ef5f9c521..ecb57f7a88 100644 --- a/internal/controller/datadogagent/feature/servicediscovery/feature.go +++ b/internal/controller/datadogagent/feature/servicediscovery/feature.go @@ -33,6 +33,7 @@ func buildFeature(*feature.Options) feature.Feature { } type serviceDiscoveryFeature struct { + enabled bool useSystemProbeLite bool } @@ -43,13 +44,22 @@ func (f *serviceDiscoveryFeature) ID() feature.IDType { // Configure is used to configure the feature from a v2alpha1.DatadogAgent instance. func (f *serviceDiscoveryFeature) Configure(_ metav1.Object, ddaSpec *v2alpha1.DatadogAgentSpec, _ *v2alpha1.RemoteConfigConfiguration) (reqComp feature.RequiredComponents) { + f.enabled = resolveEnabled(ddaSpec) f.useSystemProbeLite = false - if resolveEnabled(ddaSpec) { + + if f.enabled { f.useSystemProbeLite = shouldEnableServiceDiscoveryByDefault(ddaSpec) reqComp.Agent = feature.RequiredComponent{ IsRequired: new(true), Containers: []apicommon.AgentContainerName{apicommon.CoreAgentContainerName, apicommon.SystemProbeContainerName}, } + } else { + // Not required, but still needs the core agent container configured so that + // DD_DISCOVERY_ENABLED is explicitly written as "false" instead of being omitted + // (the agent defaults service discovery to on for versions >= 7.78.0). + reqComp.Agent = feature.RequiredComponent{ + Containers: []apicommon.AgentContainerName{apicommon.CoreAgentContainerName}, + } } return reqComp @@ -98,6 +108,11 @@ func (f *serviceDiscoveryFeature) ManageClusterAgent(managers feature.PodTemplat // ManageNodeAgent allows a feature to configure the Node Agent's corev1.PodTemplateSpec // It should do nothing if the feature doesn't need to configure it. func (f *serviceDiscoveryFeature) ManageNodeAgent(managers feature.PodTemplateManagers) error { + f.writeEnabledEnvVar(apicommon.CoreAgentContainerName, managers) + if !f.enabled { + return nil + } + // annotations managers.Annotation().AddAnnotation(common.SystemProbeAppArmorAnnotationKey, common.SystemProbeAppArmorAnnotationValue) @@ -127,7 +142,7 @@ func (f *serviceDiscoveryFeature) ManageNodeAgent(managers feature.PodTemplateMa Value: "true", } - managers.EnvVar().AddEnvVarToContainers([]apicommon.AgentContainerName{apicommon.CoreAgentContainerName, apicommon.SystemProbeContainerName}, enableEnvVar) + managers.EnvVar().AddEnvVarToContainer(apicommon.SystemProbeContainerName, enableEnvVar) managers.EnvVar().AddEnvVarToInitContainer(apicommon.InitConfigContainerName, enableEnvVar) if f.useSystemProbeLite { @@ -151,10 +166,20 @@ func (f *serviceDiscoveryFeature) ManageNodeAgent(managers feature.PodTemplateMa // ManageSingleContainerNodeAgent allows a feature to configure the Agent container for the Node Agent's corev1.PodTemplateSpec // if SingleContainerStrategy is enabled and can be used with the configured feature set. // It should do nothing if the feature doesn't need to configure it. -func (f *serviceDiscoveryFeature) ManageSingleContainerNodeAgent(feature.PodTemplateManagers) error { +func (f *serviceDiscoveryFeature) ManageSingleContainerNodeAgent(managers feature.PodTemplateManagers) error { + f.writeEnabledEnvVar(apicommon.UnprivilegedSingleAgentContainerName, managers) return nil } +// writeEnabledEnvVar explicitly reflects the resolved enabled state on the given container. +// Otherwise, this feature defaults to enabled in the Agent code for versions >= 7.78.0. +func (f *serviceDiscoveryFeature) writeEnabledEnvVar(containerName apicommon.AgentContainerName, managers feature.PodTemplateManagers) { + managers.EnvVar().AddEnvVarToContainer(containerName, &corev1.EnvVar{ + Name: common.DDServiceDiscoveryEnabled, + Value: apiutils.BoolToString(&f.enabled), + }) +} + // ManageClusterChecksRunner allows a feature to configure the ClusterChecksRunner's corev1.PodTemplateSpec // It should do nothing if the feature doesn't need to configure it. func (f *serviceDiscoveryFeature) ManageClusterChecksRunner(feature.PodTemplateManagers) error { diff --git a/internal/controller/datadogagent/feature/servicediscovery/feature_test.go b/internal/controller/datadogagent/feature/servicediscovery/feature_test.go index 9b49a5a624..48ce75775b 100644 --- a/internal/controller/datadogagent/feature/servicediscovery/feature_test.go +++ b/internal/controller/datadogagent/feature/servicediscovery/feature_test.go @@ -50,7 +50,8 @@ func Test_serviceDiscoveryFeature_Configure(t *testing.T) { { Name: "service discovery not enabled", DDA: ddaServiceDiscoveryDisabled.DeepCopy(), - WantConfigure: false, + WantConfigure: true, + Agent: test.NewDefaultComponentTest().WithWantFunc(getDisabledWantFunc()), }, { Name: "service discovery enabled", @@ -251,10 +252,77 @@ func Test_serviceDiscoveryFeature_resolveEnabled_InheritsDefaultVersionWhenImage } } +// Test_serviceDiscoveryFeature_ManageSingleContainerNodeAgent verifies that the resolved enabled +// state is also written to the unprivileged single-agent container when SingleContainerStrategy +// is used, since reconciliation calls ManageSingleContainerNodeAgent instead of ManageNodeAgent +// in that mode. Without this, a disabled service-discovery feature would omit +// DD_DISCOVERY_ENABLED=false from that container, letting the Agent's own >= 7.78.0 auto-on +// default re-enable it. +func Test_serviceDiscoveryFeature_ManageSingleContainerNodeAgent(t *testing.T) { + tests := []struct { + name string + enabled bool + want string + }{ + {name: "disabled", enabled: false, want: "false"}, + {name: "enabled", enabled: true, want: "true"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + f := &serviceDiscoveryFeature{enabled: tt.enabled} + + newPTS := corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + {Name: string(apicommon.UnprivilegedSingleAgentContainerName)}, + }, + }, + } + mgr := fake.NewPodTemplateManagers(t, newPTS) + + err := f.ManageSingleContainerNodeAgent(mgr) + assert.NoError(t, err) + + wantEnvVars := []*corev1.EnvVar{ + { + Name: common.DDServiceDiscoveryEnabled, + Value: tt.want, + }, + } + gotEnvVars := mgr.EnvVarMgr.EnvVarsByC[apicommon.UnprivilegedSingleAgentContainerName] + assert.True(t, apiutils.IsEqualStruct(gotEnvVars, wantEnvVars), "single-agent container env vars \ndiff = %s", cmp.Diff(gotEnvVars, wantEnvVars)) + }) + } +} + func serviceDiscoveryEnabledForVersion(version string) bool { return pkgutils.IsAboveMinVersion(version, serviceDiscoveryAutoEnableMinVersion, nil) } +// getDisabledWantFunc asserts that, when service discovery is explicitly disabled, the core +// agent container still receives an explicit DD_DISCOVERY_ENABLED="false" env var instead of +// omitting it entirely (which would let the agent's own >= 7.78.0 auto-on default win), and +// that none of the system-probe-specific configuration is applied. +func getDisabledWantFunc() func(t testing.TB, mgrInterface feature.PodTemplateManagers) { + return func(t testing.TB, mgrInterface feature.PodTemplateManagers) { + mgr := mgrInterface.(*fake.PodTemplateManagers) + + wantAgentEnvVars := []*corev1.EnvVar{ + { + Name: common.DDServiceDiscoveryEnabled, + Value: "false", + }, + } + agentEnvVars := mgr.EnvVarMgr.EnvVarsByC[apicommon.CoreAgentContainerName] + assert.True(t, apiutils.IsEqualStruct(agentEnvVars, wantAgentEnvVars), "Agent env vars \ndiff = %s", cmp.Diff(agentEnvVars, wantAgentEnvVars)) + + assert.Empty(t, mgr.EnvVarMgr.EnvVarsByC[apicommon.SystemProbeContainerName]) + assert.Empty(t, mgr.VolumeMountMgr.VolumeMountsByC[apicommon.SystemProbeContainerName]) + assert.Empty(t, mgr.VolumeMgr.Volumes) + } +} + func getWantFunc(wantSystemProbeLite bool) func(t testing.TB, mgrInterface feature.PodTemplateManagers) { return func(t testing.TB, mgrInterface feature.PodTemplateManagers) { mgr := mgrInterface.(*fake.PodTemplateManagers) diff --git a/internal/controller/datadogagent/feature/types.go b/internal/controller/datadogagent/feature/types.go index c5efd26b6a..b636693ada 100644 --- a/internal/controller/datadogagent/feature/types.go +++ b/internal/controller/datadogagent/feature/types.go @@ -99,6 +99,15 @@ func (rc *RequiredComponent) Merge(in *RequiredComponent) *RequiredComponent { return rc } +// merge priority: false > true > nil. +// +// This is relied upon for the no-Cluster-Agent configuration (override.clusterAgent.disabled): +// the enabledefault feature resolves its ClusterAgent.IsRequired to an explicit false in that +// case, which wins here over any other feature's true. Every feature that can require the +// Cluster Agent is still expected to check the override itself in Configure() and skip that +// requirement when disabled — this merge priority is a safety net, not a substitute for that +// check, so a feature whose ManageDependencies creates real Cluster-Agent-only resources must +// not rely on it alone. func merge(a, b *bool) *bool { if a == nil && b == nil { return nil diff --git a/internal/controller/datadogagent/global/global.go b/internal/controller/datadogagent/global/global.go index 65503f5524..3c289cb938 100644 --- a/internal/controller/datadogagent/global/global.go +++ b/internal/controller/datadogagent/global/global.go @@ -240,8 +240,16 @@ func applyGlobalSettings(logger logr.Logger, manager feature.PodTemplateManagers // Credentials credentialResource(ddaMeta, ddaSpec, manager) - // DCA token - if requiredComponents.ClusterAgent.IsEnabled() { + // DCA token. requiredComponents.ClusterAgent.IsEnabled() reflects feature + // requirements only; it stays true even when override.clusterAgent.disabled + // is set, since that override is resolved later at the component-reconcile + // layer. Check it directly here so the node agent doesn't reference a token + // Secret that will never be created. + clusterAgentDisabled := false + if override, ok := ddaSpec.Override[v2alpha1.ClusterAgentComponentName]; ok { + clusterAgentDisabled = apiutils.BoolValue(override.Disabled) + } + if requiredComponents.ClusterAgent.IsEnabled() && !clusterAgentDisabled { dcaTokenResource(ddaMeta, ddaSpec, resourcesManager, manager) } diff --git a/internal/controller/testutils/renderer/render_golden_test.go b/internal/controller/testutils/renderer/render_golden_test.go index a3335123f1..93f802b215 100644 --- a/internal/controller/testutils/renderer/render_golden_test.go +++ b/internal/controller/testutils/renderer/render_golden_test.go @@ -167,6 +167,16 @@ func TestRender_Golden(t *testing.T) { provider: kubernetes.TalosProvider, golden: "testdata/golden/talos-talos.golden.yaml", }, + { + // Regression fixture for the no-cluster-agent use case: cluster agent + // disabled via override while several cluster-agent-dependent features + // (kubeStateMetricsCore, orchestratorExplorer, serviceDiscovery) are also + // enabled. Locks in that no Cluster Agent Deployment/RBAC/Service is + // rendered and that DD_CLUSTER_AGENT_ENABLED resolves to "false" node-side. + name: "no cluster agent, baseline (no provider)", + ddaFile: "testdata/no-cluster-agent-dda.yaml", + golden: "testdata/golden/no-cluster-agent-baseline.golden.yaml", + }, // OpenShift cases. Provider strings are the real node-label-derived values: // detection yields "openshift-", never a bare "openshift". { diff --git a/internal/controller/testutils/renderer/testdata/golden/no-cluster-agent-baseline.golden.yaml b/internal/controller/testutils/renderer/testdata/golden/no-cluster-agent-baseline.golden.yaml new file mode 100644 index 0000000000..29c9cd60da --- /dev/null +++ b/internal/controller/testutils/renderer/testdata/golden/no-cluster-agent-baseline.golden.yaml @@ -0,0 +1,844 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/instance: datadog-agent + app.kubernetes.io/managed-by: datadog-operator + app.kubernetes.io/name: datadog-agent-deployment + app.kubernetes.io/part-of: -datadog--agent + app.kubernetes.io/version: "" + operator.datadoghq.com/managed-by-store: "true" + name: datadog-agent-agent + ownerReferences: + - apiVersion: datadoghq.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: DatadogAgentInternal + name: datadog-agent + uid: "" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/instance: datadog-agent + app.kubernetes.io/managed-by: datadog-operator + app.kubernetes.io/name: datadog-agent-deployment + app.kubernetes.io/part-of: -datadog--agent + app.kubernetes.io/version: "" + operator.datadoghq.com/managed-by-store: "true" + name: datadog-agent-agent +rules: +- apiGroups: + - "" + resources: + - endpoints + - nodes/metrics + - nodes/proxy + - nodes/spec + - nodes/stats + verbs: + - get +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get +- apiGroups: + - metrics.eks.amazonaws.com + resources: + - kcm/metrics + - ksh/metrics + verbs: + - get +- nonResourceURLs: + - /metrics + - /metrics/slis + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/instance: datadog-agent + app.kubernetes.io/managed-by: datadog-operator + app.kubernetes.io/name: datadog-agent-deployment + app.kubernetes.io/part-of: -datadog--agent + app.kubernetes.io/version: "" + operator.datadoghq.com/managed-by-store: "true" + name: datadog-agent-agent +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: datadog-agent-agent +subjects: +- kind: ServiceAccount + name: datadog-agent-agent +--- +apiVersion: v1 +data: + install_info: | + --- + install_method: + tool: datadog-operator + tool_version: unknown + installer_version: 0.0.0 +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/instance: datadog-agent + app.kubernetes.io/managed-by: datadog-operator + app.kubernetes.io/name: datadog-agent-deployment + app.kubernetes.io/part-of: -datadog--agent + app.kubernetes.io/version: "" + operator.datadoghq.com/managed-by-dda-controller: "true" + operator.datadoghq.com/managed-by-store: "true" + name: datadog-agent-install-info + ownerReferences: + - apiVersion: datadoghq.com/v2alpha1 + blockOwnerDeletion: true + controller: true + kind: DatadogAgent + name: datadog-agent + uid: "" +--- +apiVersion: v1 +data: + system-probe-seccomp.json: "{\n\t\t\t\"defaultAction\": \"SCMP_ACT_ERRNO\",\n\t\t\t\"syscalls\": + [\n\t\t\t\t{\n\t\t\t\t\"names\": [\"accept4\",\"access\",\"arch_prctl\",\"bind\",\"bpf\",\"brk\",\"capget\",\"capset\",\"chdir\",\"chmod\",\"chown\",\"clock_gettime\",\"clone\",\"clone3\",\"close\",\"close_range\",\"connect\",\"copy_file_range\",\"creat\",\"dup\",\"dup2\",\"dup3\",\"epoll_create\",\"epoll_create1\",\"epoll_ctl\",\"epoll_ctl_old\",\"epoll_pwait\",\"epoll_wait\",\"epoll_wait_old\",\"eventfd\",\"eventfd2\",\"execve\",\"execveat\",\"exit\",\"exit_group\",\"faccessat\",\"faccessat2\",\"fchmod\",\"fchmodat\",\"fchown\",\"fchown32\",\"fchownat\",\"fcntl\",\"fcntl64\",\"fdatasync\",\"flock\",\"fstat\",\"fstat64\",\"fstatfs\",\"fsync\",\"ftruncate\",\"futex\",\"futimens\",\"getcwd\",\"getdents\",\"getdents64\",\"getegid\",\"geteuid\",\"getgid\",\"getgroups\",\"getpeername\",\"getpgid\",\"getpgrp\",\"getpid\",\"getppid\",\"getpriority\",\"getrandom\",\"getresgid\",\"getresgid32\",\"getresuid\",\"getresuid32\",\"getrlimit\",\"getrusage\",\"getsid\",\"getsockname\",\"getsockopt\",\"gettid\",\"gettimeofday\",\"getuid\",\"getxattr\",\"inotify_add_watch\",\"inotify_init\",\"inotify_init1\",\"inotify_rm_watch\",\"ioctl\",\"ipc\",\"listen\",\"lseek\",\"lstat\",\"lstat64\",\"madvise\",\"memfd_create\",\"mkdir\",\"mkdirat\",\"mknod\",\"mknodat\",\"mmap\",\"mmap2\",\"mprotect\",\"mremap\",\"munmap\",\"nanosleep\",\"newfstatat\",\"open\",\"openat\",\"openat2\",\"pause\",\"perf_event_open\",\"pidfd_open\",\"pidfd_send_signal\",\"pipe\",\"pipe2\",\"poll\",\"ppoll\",\"prctl\",\"pread64\",\"prlimit64\",\"pselect6\",\"pwrite64\",\"read\",\"readlink\",\"readlinkat\",\"recvfrom\",\"recvmmsg\",\"recvmsg\",\"rename\",\"renameat\",\"renameat2\",\"restart_syscall\",\"rmdir\",\"rseq\",\"rt_sigaction\",\"rt_sigpending\",\"rt_sigprocmask\",\"rt_sigqueueinfo\",\"rt_sigreturn\",\"rt_sigsuspend\",\"rt_sigtimedwait\",\"rt_tgsigqueueinfo\",\"sched_getaffinity\",\"sched_yield\",\"seccomp\",\"select\",\"semtimedop\",\"send\",\"sendmmsg\",\"sendmsg\",\"sendto\",\"set_robust_list\",\"set_tid_address\",\"setgid\",\"setgid32\",\"setgroups\",\"setgroups32\",\"setitimer\",\"setns\",\"setpgid\",\"setresgid\",\"setresuid\",\"setrlimit\",\"setsid\",\"setsockopt\",\"setuid\",\"setuid32\",\"shutdown\",\"sigaltstack\",\"socket\",\"socketcall\",\"socketpair\",\"stat\",\"stat64\",\"statfs\",\"statx\",\"symlinkat\",\"sysinfo\",\"tgkill\",\"tkill\",\"umask\",\"uname\",\"unlink\",\"unlinkat\",\"utime\",\"utimensat\",\"utimes\",\"wait4\",\"waitid\",\"waitpid\",\"write\",\"writev\"],\n\t\t\t\t\"action\": + \"SCMP_ACT_ALLOW\",\n\t\t\t\t\"args\": null\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\"names\": + [\n\t\t\t\t\t\"setns\"\n\t\t\t\t],\n\t\t\t\t\"action\": \"SCMP_ACT_ALLOW\",\n\t\t\t\t\"args\": + [\n\t\t\t\t\t{\n\t\t\t\t\t\"index\": 1,\n\t\t\t\t\t\"value\": 1073741824,\n\t\t\t\t\t\"valueTwo\": + 0,\n\t\t\t\t\t\"op\": \"SCMP_CMP_EQ\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"comment\": + \"\",\n\t\t\t\t\"includes\": {},\n\t\t\t\t\"excludes\": {}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\"names\": + [\n\t\t\t\t\t\"kill\"\n\t\t\t\t],\n\t\t\t\t\"action\": \"SCMP_ACT_ALLOW\",\n\t\t\t\t\"args\": + [\n\t\t\t\t\t{\n\t\t\t\t\t\"index\": 1,\n\t\t\t\t\t\"value\": 0,\n\t\t\t\t\t\"op\": + \"SCMP_CMP_EQ\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"comment\": \"allow process + detection via kill\",\n\t\t\t\t\"includes\": {},\n\t\t\t\t\"excludes\": {}\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t\t" +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/instance: datadog-agent + app.kubernetes.io/managed-by: datadog-operator + app.kubernetes.io/name: datadog-agent-deployment + app.kubernetes.io/part-of: -datadog--agent + app.kubernetes.io/version: "" + operator.datadoghq.com/managed-by-store: "true" + name: datadog-agent-system-probe-seccomp + ownerReferences: + - apiVersion: datadoghq.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: DatadogAgentInternal + name: datadog-agent + uid: "" +--- +apiVersion: v1 +data: + install_id: "" + install_time: "-62135596800" + install_type: k8s_manual +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/instance: datadog-agent + app.kubernetes.io/managed-by: datadog-operator + app.kubernetes.io/name: datadog-agent-deployment + app.kubernetes.io/part-of: -datadog--agent + app.kubernetes.io/version: "" + operator.datadoghq.com/managed-by-dda-controller: "true" + operator.datadoghq.com/managed-by-store: "true" + name: datadog-apm-telemetry-kpi + ownerReferences: + - apiVersion: datadoghq.com/v2alpha1 + blockOwnerDeletion: true + controller: true + kind: DatadogAgent + name: datadog-agent + uid: "" +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/instance: datadog-agent + app.kubernetes.io/managed-by: datadog-operator + app.kubernetes.io/name: datadog-agent-deployment + app.kubernetes.io/part-of: -datadog--agent + app.kubernetes.io/version: "" + operator.datadoghq.com/managed-by-dda-controller: "true" + operator.datadoghq.com/managed-by-store: "true" + name: datadog-agent-agent + ownerReferences: + - apiVersion: datadoghq.com/v2alpha1 + blockOwnerDeletion: true + controller: true + kind: DatadogAgent + name: datadog-agent + uid: "" +spec: + internalTrafficPolicy: Local + ports: + - name: traceport + port: 8126 + protocol: TCP + targetPort: 8126 + - name: dogstatsdport + port: 8125 + protocol: UDP + targetPort: 8125 + selector: + agent.datadoghq.com/component: agent + app.kubernetes.io/part-of: -datadog--agent + type: ClusterIP +--- +apiVersion: datadoghq.com/v1alpha1 +kind: DatadogAgentInternal +metadata: + annotations: + agent.datadoghq.com/ddaispechash: dfd098c5b6d812e3015528cfcd1cdfec + finalizers: + - finalizer.datadoghq.com/datadogagentinternal + labels: + agent.datadoghq.com/datadogagent: datadog-agent + name: datadog-agent + ownerReferences: + - apiVersion: datadoghq.com/v2alpha1 + blockOwnerDeletion: true + controller: true + kind: DatadogAgent + name: datadog-agent + uid: "" +spec: + features: + admissionController: + cwsInstrumentation: + enabled: false + enabled: true + kubernetesAdmissionEvents: + enabled: false + mutateUnlabelled: false + mutation: + enabled: true + serviceName: datadog-admission-controller + validation: + enabled: true + apm: + enabled: true + errorTrackingStandalone: + enabled: false + hostPortConfig: + enabled: false + hostPort: 8126 + instrumentation: + enabled: false + injector: {} + languageDetection: + enabled: true + unixDomainSocketConfig: + enabled: true + path: /var/run/datadog/apm.socket + asm: + iast: + enabled: false + sca: + enabled: false + threats: + enabled: false + clusterChecks: + enabled: true + useClusterChecksRunners: false + controlPlaneMonitoring: + enabled: true + cspm: + enabled: false + cws: + enabled: false + dataPlane: + dogstatsd: + enabled: true + dogstatsd: + hostPortConfig: + enabled: false + nonLocalTraffic: true + originDetectionEnabled: false + unixDomainSocketConfig: + enabled: true + path: /var/run/datadog/dsd.socket + dynamicInstrumentation: + enabled: false + ebpfCheck: + enabled: false + eventCollection: + collectKubernetesEvents: true + externalMetricsServer: + enabled: false + gpu: + enabled: false + helmCheck: + enabled: false + kubeStateMetricsCore: + enabled: true + liveContainerCollection: + enabled: true + liveProcessCollection: + enabled: false + logCollection: + enabled: false + npm: + enabled: false + oomKill: + enabled: false + orchestratorExplorer: + enabled: true + scrubContainers: true + otelCollector: + enabled: false + otlp: + receiver: + protocols: + grpc: + enabled: false + endpoint: 0.0.0.0:4317 + http: + enabled: false + endpoint: 0.0.0.0:4318 + processDiscovery: + enabled: true + prometheusScrape: + enabled: false + remoteConfiguration: + enabled: true + serviceDiscovery: + enabled: true + tcpQueueLength: + enabled: false + usm: + enabled: false + global: + clusterAgentTokenSecret: + keyName: token + secretName: datadog-agent-token + clusterName: test-cluster + containerStrategy: optimized + credentials: + apiSecret: + keyName: api-key + secretName: datadog-secret + appSecret: + keyName: app-key + secretName: datadog-secret + fips: + enabled: false + kubelet: + podResourcesSocketPath: /var/lib/kubelet/pod-resources/ + tlsVerify: false + logLevel: info + registry: registry.datadoghq.com + site: datadoghq.com + useFIPSAgent: false + override: + clusterAgent: + annotations: + checksum/dca-token-custom-config: 3f6998966e6de63b16d45512e01ccc84 + disabled: true + image: + tag: 7.80.0 + nodeAgent: + annotations: + checksum/dca-token-custom-config: 3f6998966e6de63b16d45512e01ccc84 + image: + tag: 7.80.0 +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + annotations: + agent.datadoghq.com/agentspechash: 31c33ac002c7494d749cd50ac5942818 + labels: + agent.datadoghq.com/component: agent + agent.datadoghq.com/name: datadog-agent + app.kubernetes.io/component: agent + app.kubernetes.io/instance: datadog-agent-agent + app.kubernetes.io/managed-by: datadog-operator + app.kubernetes.io/name: datadog-agent-deployment + app.kubernetes.io/part-of: -datadog--agent + app.kubernetes.io/version: "" + name: datadog-agent-agent + ownerReferences: + - apiVersion: datadoghq.com/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: DatadogAgentInternal + name: datadog-agent + uid: "" +spec: + selector: + matchLabels: + agent.datadoghq.com/component: agent + app.kubernetes.io/instance: datadog-agent-agent + template: + metadata: + annotations: + agent.datadoghq.com/configmapshash: 2e0fb9e7949d41a5 + checksum/dca-token-custom-config: 3f6998966e6de63b16d45512e01ccc84 + container.apparmor.security.beta.kubernetes.io/system-probe: unconfined + labels: + agent.datadoghq.com/component: agent + agent.datadoghq.com/name: datadog-agent + app.kubernetes.io/component: agent + app.kubernetes.io/instance: datadog-agent-agent + app.kubernetes.io/managed-by: datadog-operator + app.kubernetes.io/name: datadog-agent-deployment + app.kubernetes.io/part-of: -datadog--agent + app.kubernetes.io/version: "" + spec: + containers: + - command: + - agent + - run + env: + - name: DD_HEALTH_PORT + value: "5555" + - name: DD_CONTAINER_IMAGE_ENABLED + value: "true" + - name: KUBERNETES + value: "yes" + - name: DD_CLUSTER_AGENT_ENABLED + value: "false" + - name: DD_CLUSTER_AGENT_KUBERNETES_SERVICE_NAME + value: datadog-agent-cluster-agent + - name: DD_KUBERNETES_USE_ENDPOINT_SLICES + value: "true" + - name: DD_CLUSTER_AGENT_TOKEN_NAME + value: datadog-agent-token + - name: DD_AUTH_TOKEN_FILE_PATH + value: /etc/datadog-agent/auth/token + - name: DD_KUBERNETES_KUBELET_HOST + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: DD_CLUSTER_NAME + value: test-cluster + - name: DD_SITE + value: datadoghq.com + - name: DD_LOG_LEVEL + value: info + - name: DD_API_KEY + valueFrom: + secretKeyRef: + key: api-key + name: datadog-secret + - name: DD_APP_KEY + valueFrom: + secretKeyRef: + key: app-key + name: datadog-secret + - name: DD_KUBELET_TLS_VERIFY + value: "false" + - name: DD_ORCHESTRATOR_EXPLORER_ENABLED + value: "false" + - name: DD_LANGUAGE_DETECTION_REPORTING_ENABLED + value: "false" + - name: DD_DOGSTATSD_NON_LOCAL_TRAFFIC + value: "true" + - name: DD_DOGSTATSD_SOCKET + value: /var/run/datadog/dsd.socket + - name: DD_PROCESS_CONFIG_RUN_IN_CORE_AGENT_ENABLED + value: "true" + - name: DD_PROCESS_CONFIG_CONTAINER_COLLECTION_ENABLED + value: "true" + - name: DD_PROCESS_CONFIG_PROCESS_DISCOVERY_ENABLED + value: "true" + - name: DD_REMOTE_CONFIGURATION_ENABLED + value: "true" + - name: DD_DISCOVERY_ENABLED + value: "true" + - name: DD_SYSPROBE_SOCKET + value: /var/run/sysprobe/sysprobe.sock + image: registry.datadoghq.com/agent:7.80.0 + livenessProbe: + failureThreshold: 6 + httpGet: + path: /live + port: 5555 + initialDelaySeconds: 15 + periodSeconds: 15 + successThreshold: 1 + timeoutSeconds: 5 + name: agent + ports: + - containerPort: 8125 + name: dogstatsdport + protocol: UDP + readinessProbe: + failureThreshold: 6 + httpGet: + path: /ready + port: 5555 + initialDelaySeconds: 15 + periodSeconds: 15 + successThreshold: 1 + timeoutSeconds: 5 + resources: {} + securityContext: + readOnlyRootFilesystem: true + startupProbe: + failureThreshold: 6 + httpGet: + path: /startup + port: 5555 + initialDelaySeconds: 15 + periodSeconds: 15 + successThreshold: 1 + timeoutSeconds: 5 + volumeMounts: + - mountPath: /var/log/datadog + name: logdatadog + - mountPath: /etc/datadog-agent/auth + name: datadog-agent-auth + - mountPath: /etc/datadog-agent/install_info + name: installinfo + readOnly: true + subPath: install_info + - mountPath: /etc/datadog-agent + name: config + - mountPath: /host/proc + name: procdir + readOnly: true + - mountPath: /host/sys/fs/cgroup + name: cgroups + readOnly: true + - mountPath: /var/run/datadog + name: dsdsocket + - mountPath: /host/var/run + name: runtimesocketdir + readOnly: true + - mountPath: /opt/datadog-agent/run + name: datadogrun + - mountPath: /tmp + name: tmpdir + - mountPath: /etc/passwd + name: passwd + readOnly: true + - mountPath: /var/run/sysprobe + name: sysprobe-socket-dir + readOnly: true + - command: + - trace-loader + - /etc/datadog-agent/datadog.yaml + - trace-agent + - --config=/etc/datadog-agent/datadog.yaml + env: + - name: DD_INSTRUMENTATION_INSTALL_ID + valueFrom: + configMapKeyRef: + key: install_id + name: datadog-apm-telemetry-kpi + - name: DD_INSTRUMENTATION_INSTALL_TIME + valueFrom: + configMapKeyRef: + key: install_time + name: datadog-apm-telemetry-kpi + - name: DD_INSTRUMENTATION_INSTALL_TYPE + valueFrom: + configMapKeyRef: + key: install_type + name: datadog-apm-telemetry-kpi + - name: KUBERNETES + value: "yes" + - name: DD_CLUSTER_AGENT_ENABLED + value: "false" + - name: DD_CLUSTER_AGENT_KUBERNETES_SERVICE_NAME + value: datadog-agent-cluster-agent + - name: DD_KUBERNETES_USE_ENDPOINT_SLICES + value: "true" + - name: DD_CLUSTER_AGENT_TOKEN_NAME + value: datadog-agent-token + - name: DD_AUTH_TOKEN_FILE_PATH + value: /etc/datadog-agent/auth/token + - name: DD_KUBERNETES_KUBELET_HOST + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: DD_CLUSTER_NAME + value: test-cluster + - name: DD_SITE + value: datadoghq.com + - name: DD_LOG_LEVEL + value: info + - name: DD_API_KEY + valueFrom: + secretKeyRef: + key: api-key + name: datadog-secret + - name: DD_APP_KEY + valueFrom: + secretKeyRef: + key: app-key + name: datadog-secret + - name: DD_KUBELET_TLS_VERIFY + value: "false" + - name: DD_APM_ENABLED + value: "true" + - name: DD_APM_NON_LOCAL_TRAFFIC + value: "true" + - name: DD_APM_RECEIVER_SOCKET + value: /var/run/datadog/apm.socket + - name: DD_DOGSTATSD_SOCKET + value: /var/run/datadog/dsd.socket + - name: DD_REMOTE_CONFIGURATION_ENABLED + value: "true" + image: registry.datadoghq.com/agent:7.80.0 + livenessProbe: + initialDelaySeconds: 15 + periodSeconds: 15 + tcpSocket: + port: 8126 + timeoutSeconds: 5 + name: trace-agent + ports: + - containerPort: 8126 + name: traceport + protocol: TCP + resources: {} + securityContext: + readOnlyRootFilesystem: true + volumeMounts: + - mountPath: /var/log/datadog + name: logdatadog + - mountPath: /host/proc + name: procdir + readOnly: true + - mountPath: /host/sys/fs/cgroup + name: cgroups + readOnly: true + - mountPath: /etc/datadog-agent/auth + name: datadog-agent-auth + readOnly: true + - mountPath: /etc/datadog-agent + name: config + - mountPath: /var/run/datadog + name: apmsocket + - mountPath: /host/var/run + name: runtimesocketdir + readOnly: true + - mountPath: /tmp + name: tmpdir + - command: + - system-probe + - --config=/etc/datadog-agent/system-probe.yaml + env: + - name: KUBERNETES + value: "yes" + - name: DD_CLUSTER_AGENT_ENABLED + value: "false" + - name: DD_CLUSTER_AGENT_KUBERNETES_SERVICE_NAME + value: datadog-agent-cluster-agent + - name: DD_KUBERNETES_USE_ENDPOINT_SLICES + value: "true" + - name: DD_CLUSTER_AGENT_TOKEN_NAME + value: datadog-agent-token + - name: DD_AUTH_TOKEN_FILE_PATH + value: /etc/datadog-agent/auth/token + - name: DD_KUBERNETES_KUBELET_HOST + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: DD_CLUSTER_NAME + value: test-cluster + - name: DD_SITE + value: datadoghq.com + - name: DD_LOG_LEVEL + value: info + - name: DD_API_KEY + valueFrom: + secretKeyRef: + key: api-key + name: datadog-secret + - name: DD_APP_KEY + valueFrom: + secretKeyRef: + key: app-key + name: datadog-secret + - name: DD_KUBELET_TLS_VERIFY + value: "false" + - name: DD_DOGSTATSD_SOCKET + value: /var/run/datadog/dsd.socket + - name: DD_REMOTE_CONFIGURATION_ENABLED + value: "true" + - name: DD_DISCOVERY_ENABLED + value: "true" + - name: DD_DISCOVERY_USE_SYSTEM_PROBE_LITE + value: "true" + - name: DD_SYSPROBE_SOCKET + value: /var/run/sysprobe/sysprobe.sock + image: registry.datadoghq.com/agent:7.80.0 + name: system-probe + resources: {} + securityContext: + capabilities: + add: + - CHOWN + - DAC_READ_SEARCH + - IPC_LOCK + - NET_ADMIN + - NET_BROADCAST + - NET_RAW + - SYS_ADMIN + - SYS_PTRACE + - SYS_RESOURCE + readOnlyRootFilesystem: true + seccompProfile: + localhostProfile: system-probe + type: Localhost + volumeMounts: + - mountPath: /var/log/datadog + name: logdatadog + - mountPath: /etc/datadog-agent/auth + name: datadog-agent-auth + readOnly: true + - mountPath: /etc/datadog-agent + name: config + - mountPath: /host/proc + name: procdir + readOnly: true + - mountPath: /opt/datadog-agent/run + name: datadogrun + - mountPath: /tmp + name: tmpdir + - mountPath: /var/run/datadog + name: dsdsocket + - mountPath: /host/sys/fs/cgroup + name: cgroups + readOnly: true + - mountPath: /var/run/sysprobe + name: sysprobe-socket-dir + initContainers: + - args: + - cp -vnr /etc/datadog-agent /opt + command: + - bash + - -c + image: registry.datadoghq.com/agent:7.80.0 + name: init-volume + resources: {} + volumeMounts: + - mountPath: /opt/datadog-agent + name: config + - args: + - for script in $(find /etc/cont-init.d/ -type f -name '*.sh' | sort) ; do + bash $script ; done + command: + - bash + - -c + env: + - name: DD_HEALTH_PORT + value: "5555" + - name: DD_CONTAINER_IMAGE_ENABLED + value: "true" + - name: KUBERNETES + value: "yes" + - name: DD_CLUSTER_AGENT_ENABLED + value: "false" + - name: DD_CLUSTER_AGENT_KUBERNETES_SERVICE_NAME + value: datadog-agent-cluster-agent + - name: DD_KUBERNETES_USE_ENDPOINT_SLICES + value: "true" + - name: DD_CLUSTER_AGENT_TOKEN_NAME + value: datadog-agent-token + - name: DD_AUTH_TOKEN_FILE_PATH + value: /etc/datadog-agent/auth/token + - name: DD_KUBERNETES_KUBELET_HOST + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: DD_DISCOVERY_ENABLED + value: "true" + image: registry.datadoghq.com/agent:7.80.0 + name: init-config + resources: {} + volumeMounts: + - mountPath: /var/log/datadog + name: logdatadog + - mountPath: /checks.d + name: checksd + readOnly: true + - mountPath: /etc/datadog-agent/auth + name: datadog-agent-auth + - mountPath: /conf.d + name: confd + readOnly: true + - mountPath: /etc/datadog-agent + name: config + - mountPath: /host/proc + name: procdir + readOnly: true + - mountPath: /host/var/run + name: runtimesocketdir + readOnly: true + - command: + - cp + - /etc/config/system-probe-seccomp.json + - /host/var/lib/kubelet/seccomp/system-probe + image: registry.datadoghq.com/agent:7.80.0 + name: seccomp-setup + resources: {} + volumeMounts: + - mountPath: /etc/config + name: datadog-agent-security + readOnly: true + - mountPath: /host/var/lib/kubelet/seccomp + name: seccomp-root + securityContext: + runAsUser: 0 + serviceAccountName: datadog-agent-agent + volumes: + - emptyDir: {} + name: logdatadog + - emptyDir: {} + name: datadog-agent-auth + - configMap: + name: datadog-agent-install-info + name: installinfo + - emptyDir: {} + name: checksd + - emptyDir: {} + name: confd + - emptyDir: {} + name: config + - hostPath: + path: /proc + name: procdir + - hostPath: + path: /sys/fs/cgroup + name: cgroups + - hostPath: + path: /var/run/datadog + type: DirectoryOrCreate + name: dsdsocket + - hostPath: + path: /var/run + name: runtimesocketdir + - emptyDir: {} + name: datadogrun + - emptyDir: {} + name: tmpdir + - configMap: + name: datadog-agent-system-probe-seccomp + name: datadog-agent-security + - hostPath: + path: /var/lib/kubelet/seccomp + name: seccomp-root + - hostPath: + path: /var/run/datadog + type: DirectoryOrCreate + name: apmsocket + - hostPath: + path: /etc/passwd + name: passwd + - emptyDir: {} + name: sysprobe-socket-dir + updateStrategy: {} diff --git a/internal/controller/testutils/renderer/testdata/no-cluster-agent-dda.yaml b/internal/controller/testutils/renderer/testdata/no-cluster-agent-dda.yaml new file mode 100644 index 0000000000..19b5abd5e1 --- /dev/null +++ b/internal/controller/testutils/renderer/testdata/no-cluster-agent-dda.yaml @@ -0,0 +1,31 @@ +apiVersion: datadoghq.com/v2alpha1 +kind: DatadogAgent +metadata: + name: datadog-agent +spec: + global: + credentials: + apiSecret: + secretName: datadog-secret + keyName: api-key + appSecret: + secretName: datadog-secret + keyName: app-key + clusterName: test-cluster + # Fixed so the generated cluster-agent token Secret is deterministic for golden files. + clusterAgentToken: golden-fixed-cluster-agent-token-0000000000 + kubelet: + tlsVerify: false + features: + # Enabled on top of the cluster agent being disabled, to lock in that these + # features self-disable (or keep working node-side) instead of silently + # requiring Cluster Agent resources that will never be created. + kubeStateMetricsCore: + enabled: true + orchestratorExplorer: + enabled: true + serviceDiscovery: + enabled: true + override: + clusterAgent: + disabled: true