Repository navigation
Conversation
…covery is disabled Configure() previously left the Agent component unrequired when service discovery resolved to disabled, so ManageNodeAgent never ran and the env var was simply omitted instead of written as "false". The agent defaults service discovery to on for versions >= 7.78.0, so an explicit false was silently overridden by that default. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The instrumentation-checks autodiscovery provider requires a live Cluster Agent to serve configs to the node agent. Configure() only checked agent/cluster-agent version floors, never whether the Cluster Agent was actually going to be deployed (override.clusterAgent.disabled). Without one, the node agent kept registering the provider and spamming connection errors trying to reach a Cluster Agent Service that doesn't exist. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…bled kubeStateMetricsCore only ever runs inside the Cluster Agent or Cluster Check Runners it dispatches to — there's no code path for it to run without one. Configure() gated purely on the feature's own enabled flag, never on override.clusterAgent.disabled, so disabling the cluster agent while the feature stayed enabled created a ClusterRole/ClusterRoleBinding bound to a nonexistent ServiceAccount plus a stray ConfigMap. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… disabled orchestratorExplorer runs inside the Cluster Agent (or Cluster Check Runners it dispatches to). Configure() never checked override.clusterAgent.disabled, so ManageDependencies still created a ClusterRole/ClusterRoleBinding bound to a nonexistent cluster-agent ServiceAccount. The node agent's explicit DD_ORCHESTRATOR_EXPLORER_ENABLED disable write is preserved. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Event collection is configured using the Cluster Agent only, and defaults to enabled. Configure() never checked override.clusterAgent.disabled, so ManageDependencies still created RBAC bound to a nonexistent cluster-agent ServiceAccount. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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. Configure() never checked override.clusterAgent.disabled, so the Service and RBAC were still created and the admission webhooks still registered. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
AppSec injection is configured and served by the Cluster Agent. Configure() never checked override.clusterAgent.disabled, so ManageDependencies still created RBAC bound to a nonexistent cluster-agent ServiceAccount. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CSPM dispatches its checks via the Cluster Agent and already ties its node-side (Agent) requirement to the Cluster Agent requirement. Configure() never checked override.clusterAgent.disabled, so ManageDependencies still created RBAC bound to a nonexistent cluster-agent ServiceAccount. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…abled The external metrics server is served by the Cluster Agent. Configure() never checked override.clusterAgent.disabled, so ManageDependencies still created a Service, RBAC, and an APIService with nothing to back them. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The helm check only ever runs inside the Cluster Agent (or Cluster Check Runners it dispatches to). Configure() never checked override.clusterAgent.disabled, so ManageDependencies still created RBAC bound to a nonexistent cluster-agent ServiceAccount. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Kubernetes Actions runs inside the Cluster Agent. Configure() never checked override.clusterAgent.disabled, so ManageDependencies still created RBAC bound to a nonexistent cluster-agent ServiceAccount. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Autoscaling decisions are computed and served by the Cluster Agent. Configure() never checked override.clusterAgent.disabled, so ManageDependencies still created RBAC bound to a nonexistent cluster-agent ServiceAccount (its RBAC was already tagged for component-scoped cleanup, but creating it at all was still wrong). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…sabled Control plane monitoring is driven by the Cluster Agent. Configure() never checked override.clusterAgent.disabled, so ManageDependencies still created ConfigMaps for a feature that has nothing to run it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The default pod template scaffolding (component/agent/default.go) hardcodes DD_CLUSTER_AGENT_ENABLED to "true" on every agent container and the init-config init container, regardless of whether a Cluster Agent is actually being deployed. This is the switch the node agent uses to decide whether to try reaching a cluster agent at all, and was the likely root cause behind several of the per-feature symptoms already fixed on this branch. The enabledefault feature now overrides it to "false" when the Cluster Agent is disabled via override. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
🎯 Code Coverage (details) 🔗 Commit SHA: 4d3b88e | Docs | View more details | Give us feedback! |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Disabled service discovery is not propagated when using the single-container strategy.
Review effort: Balanced
Findings: 1
What changed in this PR
Adds support for running node agents without a Cluster Agent.
Changes:
- Propagates the disabled Cluster Agent state to node-agent containers.
- Suppresses Cluster Agent-dependent features and resources.
- Adds regression coverage for disabled configurations.
| File | Description |
|---|---|
feature/servicediscovery/feature.go |
Explicitly configures service discovery state. |
feature/servicediscovery/feature_test.go |
Tests explicit disabling. |
feature/orchestratorexplorer/feature.go |
Skips Cluster Agent resources when disabled. |
feature/orchestratorexplorer/feature_test.go |
Tests disabled Cluster Agent behavior. |
feature/kubernetesstatecore/feature.go |
Suppresses KSM Core resources. |
feature/kubernetesstatecore/feature_test.go |
Tests suppression. |
feature/kubernetesactions/feature.go |
Disables Kubernetes Actions. |
feature/kubernetesactions/feature_test.go |
Tests disabling. |
feature/instrumentationcrd/feature.go |
Disables Instrumentation CRD integration. |
feature/instrumentationcrd/feature_test.go |
Tests disabling. |
feature/helmcheck/feature.go |
Suppresses Helm check resources. |
feature/helmcheck/feature_test.go |
Tests suppression. |
feature/externalmetrics/feature.go |
Suppresses external metrics resources. |
feature/externalmetrics/feature_test.go |
Tests suppression. |
feature/eventcollection/feature.go |
Suppresses event collection resources. |
feature/eventcollection/feature_test.go |
Tests suppression. |
feature/enabledefault/feature.go |
Overrides Cluster Agent availability environment variables. |
feature/enabledefault/feature_test.go |
Tests environment overrides. |
feature/cspm/feature.go |
Disables CSPM without a Cluster Agent. |
feature/cspm/feature_test.go |
Tests disabling. |
feature/controlplanemonitoring/feature.go |
Suppresses control-plane monitoring resources. |
feature/controlplanemonitoring/feature_test.go |
Tests suppression. |
feature/autoscaling/feature.go |
Disables Cluster Agent-backed autoscaling. |
feature/autoscaling/feature_test.go |
Tests disabling. |
feature/appsec/feature.go |
Disables AppSec injection. |
feature/appsec/feature_test.go |
Tests disabling. |
feature/admissioncontroller/feature.go |
Prevents unbacked admission webhooks. |
feature/admissioncontroller/feature_test.go |
Tests disabling. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Cluster-side private action runner configuration remains enabled and can create dependencies or block reconciliation when the Cluster Agent is disabled.
Review effort: Balanced
Findings: 1
Resolved since last review (1)
… agent is disabled privateactionrunner's Cluster Agent config is annotation-gated rather than spec.features-gated, so it was missed in the earlier feature audit. It had no clusterAgent.disabled check, so it kept requiring a Cluster Agent and creating its ConfigMap (and optional RBAC) with nothing to deploy them onto. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…t bugs asm, prometheusscrape and remoteconfig still set ClusterAgent.IsRequired unconditionally without checking override.clusterAgent.disabled. Unlike the 20 previously fixed instances, these are currently harmless: none creates orphaned dependencies, and enabledefault's explicit false already wins in the merge. Document the invariant they rely on so a future change to the merge order or to enabledefault doesn't silently reintroduce the override-conflict bug here. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
asm.Configure read admissionController.enabled directly rather than checking override.clusterAgent.disabled, so it kept requiring the Cluster Agent even when disabled. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…abled remoteconfig.Configure set ClusterAgent.IsRequired/Containers unconditionally whenever the feature was enabled, regardless of override.clusterAgent.disabled. The Agent requirement stays, since remote config still runs node-side. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… disabled prometheusscrape.Configure set ClusterAgent.IsRequired unconditionally whenever the feature was enabled, regardless of override.clusterAgent.disabled. The Agent requirement stays, since Prometheus scrape still runs node-side. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ig are gated The merge-priority safety net was documented as something those three features relied on instead of checking the override themselves. Now that they do, reframe the comment as a safety net for future features, not a substitute for the per-feature check. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A Copilot review comment questioned whether APM's single-step instrumentation (language detection in particular) gets left half configured when override.clusterAgent.disabled is set. Verified it doesn't: shouldConfigureSSI already calls validateSSISharedComponentPrerequisites, which rejects SSI when the Cluster Agent is disabled, so singleStepInstrumentation stays nil and shouldEnableLanguageDetection() is false. No production code change; adding a regression test since nothing previously covered this case. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
| 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) |
There was a problem hiding this comment.
minor nit: unsure if the init containers care about this value
| IsRequired: new(true), | ||
| Containers: []apicommon.AgentContainerName{apicommon.CoreAgentContainerName, apicommon.SystemProbeContainerName}, | ||
| } | ||
| } else { |
There was a problem hiding this comment.
I don't think the service discovery feature is related to the Cluster Agent. This feature isn't about k8s services. For whatever reason a service == a process which can be detected on the Agent via system-probe / system-probe-lite. This should remain on without the cluster agent.
| // 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 { |
There was a problem hiding this comment.
edge case: the datadog agent profiles set cluster agent to be disabled on the profiles because we don't want to re-create the DCA. However, the user may still have the DCA enabled in the original DDA. This would result in all Agents in profiles not being able to contact the cluster agent?
#3586 would fix that edge case and needs to be merged alongside (ideally this is before/same day so that nightly images don't bug)... still thinking about other potential solutions.
|
@agagniere, I changed milestone to 1.33 for to have a bit more time for reviewing and possibly changing the approach.
I think handling |
|
@levan-m So if I understand correctly, you would prefer a toggle to disable the cluster agent outside of |


What does this PR do?
When the cluster agent is disabled, others components like the core agent should know about it, to stop trying to contact it.
DD_CLUSTER_AGENT_ENABLEDhardcoded "true" — the foundational switch the node agent uses to decide whether to even try reaching a cluster agent. Wrong on every single node-agent container and the init-config init container, regardless of config. Root cause behind several of the symptoms below.ManageNodeAgent;ManageSingleContainerNodeAgentwas still a no-op, so underSingleContainerStrategya disabled config never reached the unprivileged-single-agent container and the agent's own ≥7.78.0 auto-on default won anyway.manageDDADependenciesWithDDAIregardless ofoverride.clusterAgent.disabled, left behind with no consumer.DD_CLUSTER_AGENT_AUTH_TOKEN— written on the node agent based on merged feature requirements only, not the override; after fixing item 16 this left asecretKeyRefpointing at a Secret that no longer exists, which would have broken pod startup.ClusterAgent.IsRequired: true, so merging it withoverride.clusterAgent.disabledmadecheckComponentEnabledWithOverridetreat every no-Cluster-AgentDatadogAgentas a feature/override conflict, persisting anOverrideReconcileConflictstatus condition on an otherwise supported configuration. Found by Copilot/Codex PR review.clusterAgent.disabledgate at all; missed in the original audit. LeftDD_EXTRA_CONFIG_PROVIDERS=clusterchecks endpointscheckson the node agent pointing at a Cluster Agent that would never dispatch those checks. Found by Codex PR review.Motivation
For reInvent we want to provide DD features on top of the DDOT collector, and so require the DD agent, while features that can be done via OTel like k8s explorer are handled by DDOT. In particular this means that the cluster agent should not be present.
OTAGENT-1387
Testing
Added
testdata/no-cluster-agent-dda.yaml+ a golden-file fixture (internal/controller/testutils/renderer) that renders a DatadogAgent with the cluster agent disabled and several cluster-agent-dependent features (kubeStateMetricsCore, orchestratorExplorer, serviceDiscovery) also enabled, to lock in that no Cluster Agent Deployment/Service/RBAC/token Secret is produced and that the node agent resolves correctly on its own.Docs
Added a "Running without the Cluster Agent" section to
docs/cluster_agent_setup.mdplus an example manifest (examples/datadogagent/datadog-agent-without-clusteragent.yaml) — previouslyoverride.clusterAgent.disabledwas undocumented.Checklist
bug,enhancement,refactoring,documentation,tooling, and/ordependenciesqa/skip-qalabel