diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3ee9473887..6fd87fba22 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -529,12 +529,11 @@ publish_nightly_workflow: CONDUCTOR_TARGET: $CONDUCTOR_TARGET DDR_WORKFLOW_ID: $DDR_WORKFLOW_ID -# On success, this will cause CNAB to trigger a Deployment to Release Candidate clusters +# On success, this will cause CNAB to trigger a Deployment to Release Candidate clusters and open a corresponding pull request publish_release_candidate_workflow: stage: deploy rules: - if: $CI_COMMIT_TAG - when: manual # TODO: change this to on_success when feeling confident - when: never needs: - trigger_internal_operator_image diff --git a/api/datadoghq/common/envvar.go b/api/datadoghq/common/envvar.go index 1101239c94..ab1324f757 100644 --- a/api/datadoghq/common/envvar.go +++ b/api/datadoghq/common/envvar.go @@ -154,6 +154,7 @@ const ( DDSecretBackendCommand = "DD_SECRET_BACKEND_COMMAND" DDSecretBackendArguments = "DD_SECRET_BACKEND_ARGUMENTS" DDSecretBackendTimeout = "DD_SECRET_BACKEND_TIMEOUT" + DDServiceDiscoveryEnabled = "DD_DISCOVERY_ENABLED" DDSite = "DD_SITE" DDSystemProbeAgentEnabled = "DD_SYSTEM_PROBE_ENABLED" DDSystemProbeBPFDebugEnabled = DDSystemProbeEnvPrefix + "BPF_DEBUG" diff --git a/api/datadoghq/common/types.go b/api/datadoghq/common/types.go index 74242d6cdc..f8426742f0 100644 --- a/api/datadoghq/common/types.go +++ b/api/datadoghq/common/types.go @@ -60,6 +60,8 @@ const ( SystemProbeContainerName AgentContainerName = "system-probe" // OtelAgent is the name of the OTel container OtelAgent AgentContainerName = "otel-agent" + // AgentDataPlaneContainerName is the name of the Agent Data Plane container + AgentDataPlaneContainerName AgentContainerName = "agent-data-plane" // AllContainers is used internally to reference all containers in the pod AllContainers AgentContainerName = "all" // ClusterAgentContainerName is the name of the Cluster Agent container diff --git a/api/datadoghq/v2alpha1/const.go b/api/datadoghq/v2alpha1/const.go index 7fe87e8f97..3c26823cb1 100644 --- a/api/datadoghq/v2alpha1/const.go +++ b/api/datadoghq/v2alpha1/const.go @@ -52,6 +52,21 @@ const ( DefaultStartupProbeFailureThreshold int32 = 6 DefaultStartupProbeHTTPPath = "/startup" + // Agent Data plane default liveness/readiness probe configs + DefaultADPLivenessProbeInitialDelaySeconds int32 = 5 + DefaultADPLivenessProbePeriodSeconds int32 = 5 + DefaultADPLivenessProbeTimeoutSeconds int32 = 5 + DefaultADPLivenessProbeSuccessThreshold int32 = 1 + DefaultADPLivenessProbeFailureThreshold int32 = 12 + + DefaultADPReadinessProbeInitialDelaySeconds int32 = 5 + DefaultADPReadinessProbePeriodSeconds int32 = 5 + DefaultADPReadinessProbeTimeoutSeconds int32 = 5 + DefaultADPReadinessProbeSuccessThreshold int32 = 1 + DefaultADPReadinessProbeFailureThreshold int32 = 12 + + DefaultADPHealthPort = 5100 + // DefaultApmPort default apm port DefaultApmPort = 8126 // DefaultApmPortName default apm port name diff --git a/api/datadoghq/v2alpha1/datadogagent_default.go b/api/datadoghq/v2alpha1/datadogagent_default.go index b925468948..dbbe956ca1 100644 --- a/api/datadoghq/v2alpha1/datadogagent_default.go +++ b/api/datadoghq/v2alpha1/datadogagent_default.go @@ -35,6 +35,8 @@ const ( defaultEBPFCheckEnabled bool = false + defaultServiceDiscoveryEnabled bool = false + defaultAPMEnabled bool = true defaultAPMHostPortEnabled bool = false defaultAPMHostPort int32 = 8126 @@ -243,6 +245,11 @@ func defaultFeaturesConfig(ddaSpec *DatadogAgentSpec) { } apiutils.DefaultBooleanIfUnset(&ddaSpec.Features.EBPFCheck.Enabled, defaultEBPFCheckEnabled) + if ddaSpec.Features.ServiceDiscovery == nil { + ddaSpec.Features.ServiceDiscovery = &ServiceDiscoveryFeatureConfig{} + } + apiutils.DefaultBooleanIfUnset(&ddaSpec.Features.ServiceDiscovery.Enabled, defaultServiceDiscoveryEnabled) + // APM Feature // APM is enabled by default if ddaSpec.Features.APM == nil { diff --git a/api/datadoghq/v2alpha1/datadogagent_default_test.go b/api/datadoghq/v2alpha1/datadogagent_default_test.go index 24399d94ae..2239645e64 100644 --- a/api/datadoghq/v2alpha1/datadogagent_default_test.go +++ b/api/datadoghq/v2alpha1/datadogagent_default_test.go @@ -195,6 +195,9 @@ func Test_defaultFeatures(t *testing.T) { EBPFCheck: &EBPFCheckFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultEBPFCheckEnabled), }, + ServiceDiscovery: &ServiceDiscoveryFeatureConfig{ + Enabled: apiutils.NewBoolPointer(defaultServiceDiscoveryEnabled), + }, APM: &APMFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultAPMEnabled), HostPortConfig: &HostPortConfig{ @@ -315,6 +318,9 @@ func Test_defaultFeatures(t *testing.T) { EBPFCheck: &EBPFCheckFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultEBPFCheckEnabled), }, + ServiceDiscovery: &ServiceDiscoveryFeatureConfig{ + Enabled: apiutils.NewBoolPointer(defaultServiceDiscoveryEnabled), + }, APM: &APMFeatureConfig{ Enabled: apiutils.NewBoolPointer(valueFalse), }, @@ -397,6 +403,9 @@ func Test_defaultFeatures(t *testing.T) { EBPFCheck: &EBPFCheckFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultEBPFCheckEnabled), }, + ServiceDiscovery: &ServiceDiscoveryFeatureConfig{ + Enabled: apiutils.NewBoolPointer(defaultServiceDiscoveryEnabled), + }, APM: &APMFeatureConfig{ Enabled: apiutils.NewBoolPointer(valueFalse), }, @@ -508,6 +517,9 @@ func Test_defaultFeatures(t *testing.T) { EBPFCheck: &EBPFCheckFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultEBPFCheckEnabled), }, + ServiceDiscovery: &ServiceDiscoveryFeatureConfig{ + Enabled: apiutils.NewBoolPointer(defaultServiceDiscoveryEnabled), + }, APM: &APMFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultAPMEnabled), HostPortConfig: &HostPortConfig{ @@ -640,6 +652,9 @@ func Test_defaultFeatures(t *testing.T) { EBPFCheck: &EBPFCheckFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultEBPFCheckEnabled), }, + ServiceDiscovery: &ServiceDiscoveryFeatureConfig{ + Enabled: apiutils.NewBoolPointer(defaultServiceDiscoveryEnabled), + }, APM: &APMFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultAPMEnabled), HostPortConfig: &HostPortConfig{ @@ -767,6 +782,9 @@ func Test_defaultFeatures(t *testing.T) { EBPFCheck: &EBPFCheckFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultEBPFCheckEnabled), }, + ServiceDiscovery: &ServiceDiscoveryFeatureConfig{ + Enabled: apiutils.NewBoolPointer(defaultServiceDiscoveryEnabled), + }, APM: &APMFeatureConfig{ Enabled: apiutils.NewBoolPointer(valueTrue), HostPortConfig: &HostPortConfig{ @@ -894,6 +912,9 @@ func Test_defaultFeatures(t *testing.T) { EBPFCheck: &EBPFCheckFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultEBPFCheckEnabled), }, + ServiceDiscovery: &ServiceDiscoveryFeatureConfig{ + Enabled: apiutils.NewBoolPointer(defaultServiceDiscoveryEnabled), + }, APM: &APMFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultAPMEnabled), HostPortConfig: &HostPortConfig{ @@ -1030,6 +1051,9 @@ func Test_defaultFeatures(t *testing.T) { EBPFCheck: &EBPFCheckFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultEBPFCheckEnabled), }, + ServiceDiscovery: &ServiceDiscoveryFeatureConfig{ + Enabled: apiutils.NewBoolPointer(defaultServiceDiscoveryEnabled), + }, APM: &APMFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultAPMEnabled), HostPortConfig: &HostPortConfig{ @@ -1157,6 +1181,9 @@ func Test_defaultFeatures(t *testing.T) { EBPFCheck: &EBPFCheckFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultEBPFCheckEnabled), }, + ServiceDiscovery: &ServiceDiscoveryFeatureConfig{ + Enabled: apiutils.NewBoolPointer(defaultServiceDiscoveryEnabled), + }, APM: &APMFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultAPMEnabled), HostPortConfig: &HostPortConfig{ @@ -1287,6 +1314,9 @@ func Test_defaultFeatures(t *testing.T) { EBPFCheck: &EBPFCheckFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultEBPFCheckEnabled), }, + ServiceDiscovery: &ServiceDiscoveryFeatureConfig{ + Enabled: apiutils.NewBoolPointer(defaultServiceDiscoveryEnabled), + }, APM: &APMFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultAPMEnabled), HostPortConfig: &HostPortConfig{ @@ -1444,6 +1474,9 @@ func Test_defaultFeatures(t *testing.T) { EBPFCheck: &EBPFCheckFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultEBPFCheckEnabled), }, + ServiceDiscovery: &ServiceDiscoveryFeatureConfig{ + Enabled: apiutils.NewBoolPointer(defaultServiceDiscoveryEnabled), + }, CSPM: &CSPMFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultCSPMEnabled), }, @@ -1547,6 +1580,9 @@ func Test_defaultFeatures(t *testing.T) { EBPFCheck: &EBPFCheckFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultEBPFCheckEnabled), }, + ServiceDiscovery: &ServiceDiscoveryFeatureConfig{ + Enabled: apiutils.NewBoolPointer(defaultServiceDiscoveryEnabled), + }, APM: &APMFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultAPMEnabled), HostPortConfig: &HostPortConfig{ @@ -1655,6 +1691,7 @@ func Test_defaultFeatures(t *testing.T) { OOMKill: &OOMKillFeatureConfig{}, TCPQueueLength: &TCPQueueLengthFeatureConfig{}, EBPFCheck: &EBPFCheckFeatureConfig{}, + ServiceDiscovery: &ServiceDiscoveryFeatureConfig{}, APM: &APMFeatureConfig{}, ASM: &ASMFeatureConfig{}, CSPM: &CSPMFeatureConfig{}, @@ -1696,6 +1733,9 @@ func Test_defaultFeatures(t *testing.T) { EBPFCheck: &EBPFCheckFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultEBPFCheckEnabled), }, + ServiceDiscovery: &ServiceDiscoveryFeatureConfig{ + Enabled: apiutils.NewBoolPointer(defaultServiceDiscoveryEnabled), + }, APM: &APMFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultAPMEnabled), HostPortConfig: &HostPortConfig{ @@ -1826,6 +1866,9 @@ func Test_defaultFeatures(t *testing.T) { EBPFCheck: &EBPFCheckFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultEBPFCheckEnabled), }, + ServiceDiscovery: &ServiceDiscoveryFeatureConfig{ + Enabled: apiutils.NewBoolPointer(defaultServiceDiscoveryEnabled), + }, APM: &APMFeatureConfig{ Enabled: apiutils.NewBoolPointer(defaultAPMEnabled), HostPortConfig: &HostPortConfig{ diff --git a/api/datadoghq/v2alpha1/datadogagent_types.go b/api/datadoghq/v2alpha1/datadogagent_types.go index c50e104ed8..edfd716210 100644 --- a/api/datadoghq/v2alpha1/datadogagent_types.go +++ b/api/datadoghq/v2alpha1/datadogagent_types.go @@ -78,6 +78,8 @@ type DatadogFeatures struct { RemoteConfiguration *RemoteConfigurationFeatureConfig `json:"remoteConfiguration,omitempty"` // SBOM collection configuration. SBOM *SBOMFeatureConfig `json:"sbom,omitempty"` + // ServiceDiscovery + ServiceDiscovery *ServiceDiscoveryFeatureConfig `json:"serviceDiscovery,omitempty"` // Cluster-level features @@ -486,6 +488,14 @@ type USMFeatureConfig struct { Enabled *bool `json:"enabled,omitempty"` } +// ServiceDiscoveryFeatureConfig configures the service discovery check feature. +type ServiceDiscoveryFeatureConfig struct { + // Enables the service discovery check. + // Default: false + // +optional + Enabled *bool `json:"enabled,omitempty"` +} + // DogstatsdFeatureConfig contains the Dogstatsd configuration parameters. // +k8s:openapi-gen=true type DogstatsdFeatureConfig struct { diff --git a/api/datadoghq/v2alpha1/utils.go b/api/datadoghq/v2alpha1/utils.go index ce2a29b35f..ba3b106850 100644 --- a/api/datadoghq/v2alpha1/utils.go +++ b/api/datadoghq/v2alpha1/utils.go @@ -188,6 +188,42 @@ func GetDefaultTraceAgentProbe() *corev1.Probe { return probe } +// GetDefaultAgentDataPlaneLivenessProbe creates a defaulted liveness probe for Agent Data Plane +func GetDefaultAgentDataPlaneLivenessProbe() *corev1.Probe { + livenessProbe := &corev1.Probe{ + InitialDelaySeconds: DefaultADPLivenessProbeInitialDelaySeconds, + PeriodSeconds: DefaultADPLivenessProbePeriodSeconds, + TimeoutSeconds: DefaultADPLivenessProbeTimeoutSeconds, + SuccessThreshold: DefaultADPLivenessProbeSuccessThreshold, + FailureThreshold: DefaultADPLivenessProbeFailureThreshold, + } + livenessProbe.HTTPGet = &corev1.HTTPGetAction{ + Path: DefaultLivenessProbeHTTPPath, + Port: intstr.IntOrString{ + IntVal: DefaultADPHealthPort, + }, + } + return livenessProbe +} + +// GetDefaultAgentDataPlaneReadinessProbe creates a defaulted readiness probe for Agent Data Plane +func GetDefaultAgentDataPlaneReadinessProbe() *corev1.Probe { + readinessProbe := &corev1.Probe{ + InitialDelaySeconds: DefaultADPReadinessProbeInitialDelaySeconds, + PeriodSeconds: DefaultADPReadinessProbePeriodSeconds, + TimeoutSeconds: DefaultADPReadinessProbeTimeoutSeconds, + SuccessThreshold: DefaultADPReadinessProbeSuccessThreshold, + FailureThreshold: DefaultADPReadinessProbeFailureThreshold, + } + readinessProbe.HTTPGet = &corev1.HTTPGetAction{ + Path: DefaultReadinessProbeHTTPPath, + Port: intstr.IntOrString{ + IntVal: DefaultADPHealthPort, + }, + } + return readinessProbe +} + // GetImage builds the image string based on ImageConfig and the registry configuration. func GetImage(imageSpec *AgentImageConfig, registry *string) string { if defaulting.IsImageNameContainsTag(imageSpec.Name) { diff --git a/api/datadoghq/v2alpha1/zz_generated.deepcopy.go b/api/datadoghq/v2alpha1/zz_generated.deepcopy.go index 9c10b4637d..fe9b044371 100644 --- a/api/datadoghq/v2alpha1/zz_generated.deepcopy.go +++ b/api/datadoghq/v2alpha1/zz_generated.deepcopy.go @@ -1127,6 +1127,11 @@ func (in *DatadogFeatures) DeepCopyInto(out *DatadogFeatures) { *out = new(SBOMFeatureConfig) (*in).DeepCopyInto(*out) } + if in.ServiceDiscovery != nil { + in, out := &in.ServiceDiscovery, &out.ServiceDiscovery + *out = new(ServiceDiscoveryFeatureConfig) + (*in).DeepCopyInto(*out) + } if in.EventCollection != nil { in, out := &in.EventCollection, &out.EventCollection *out = new(EventCollectionFeatureConfig) @@ -2509,6 +2514,26 @@ func (in *Selector) DeepCopy() *Selector { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceDiscoveryFeatureConfig) DeepCopyInto(out *ServiceDiscoveryFeatureConfig) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceDiscoveryFeatureConfig. +func (in *ServiceDiscoveryFeatureConfig) DeepCopy() *ServiceDiscoveryFeatureConfig { + if in == nil { + return nil + } + out := new(ServiceDiscoveryFeatureConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SingleStepInstrumentation) DeepCopyInto(out *SingleStepInstrumentation) { *out = *in diff --git a/api/datadoghq/v2alpha1/zz_generated.openapi.go b/api/datadoghq/v2alpha1/zz_generated.openapi.go index 669628077e..2d6b3e7390 100644 --- a/api/datadoghq/v2alpha1/zz_generated.openapi.go +++ b/api/datadoghq/v2alpha1/zz_generated.openapi.go @@ -621,6 +621,12 @@ func schema_datadog_operator_api_datadoghq_v2alpha1_DatadogFeatures(ref common.R Ref: ref("github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.SBOMFeatureConfig"), }, }, + "serviceDiscovery": { + SchemaProps: spec.SchemaProps{ + Description: "ServiceDiscovery", + Ref: ref("github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.ServiceDiscoveryFeatureConfig"), + }, + }, "eventCollection": { SchemaProps: spec.SchemaProps{ Description: "EventCollection configuration.", @@ -679,7 +685,7 @@ func schema_datadog_operator_api_datadoghq_v2alpha1_DatadogFeatures(ref common.R }, }, Dependencies: []string{ - "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.APMFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.ASMFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.AdmissionControllerFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.AutoscalingFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.CSPMFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.CWSFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.ClusterChecksFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.DogstatsdFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.EBPFCheckFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.EventCollectionFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.ExternalMetricsServerFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.HelmCheckFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.KubeStateMetricsCoreFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.LiveContainerCollectionFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.LiveProcessCollectionFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.LogCollectionFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.NPMFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.OOMKillFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.OTLPFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.OrchestratorExplorerFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.ProcessDiscoveryFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.PrometheusScrapeFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.RemoteConfigurationFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.SBOMFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.TCPQueueLengthFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.USMFeatureConfig"}, + "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.APMFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.ASMFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.AdmissionControllerFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.AutoscalingFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.CSPMFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.CWSFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.ClusterChecksFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.DogstatsdFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.EBPFCheckFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.EventCollectionFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.ExternalMetricsServerFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.HelmCheckFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.KubeStateMetricsCoreFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.LiveContainerCollectionFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.LiveProcessCollectionFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.LogCollectionFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.NPMFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.OOMKillFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.OTLPFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.OrchestratorExplorerFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.ProcessDiscoveryFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.PrometheusScrapeFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.RemoteConfigurationFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.SBOMFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.ServiceDiscoveryFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.TCPQueueLengthFeatureConfig", "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1.USMFeatureConfig"}, } } diff --git a/config/crd/bases/v1/datadoghq.com_datadogagents.yaml b/config/crd/bases/v1/datadoghq.com_datadogagents.yaml index bf21fc9822..20040fc1be 100644 --- a/config/crd/bases/v1/datadoghq.com_datadogagents.yaml +++ b/config/crd/bases/v1/datadoghq.com_datadogagents.yaml @@ -1423,6 +1423,15 @@ spec: type: boolean type: object type: object + serviceDiscovery: + description: ServiceDiscovery + properties: + enabled: + description: |- + Enables the service discovery check. + Default: false + type: boolean + type: object tcpQueueLength: description: TCPQueueLength configuration. properties: @@ -7964,6 +7973,15 @@ spec: type: boolean type: object type: object + serviceDiscovery: + description: ServiceDiscovery + properties: + enabled: + description: |- + Enables the service discovery check. + Default: false + type: boolean + type: object tcpQueueLength: description: TCPQueueLength configuration. properties: diff --git a/docs/configuration.v2alpha1.md b/docs/configuration.v2alpha1.md index 70d875db95..0a49996053 100644 --- a/docs/configuration.v2alpha1.md +++ b/docs/configuration.v2alpha1.md @@ -160,6 +160,7 @@ spec: | features.sbom.enabled | Enable this option to activate SBOM collection. Default: false | | features.sbom.host.analyzers | To use for SBOM collection. | | features.sbom.host.enabled | Enable this option to activate SBOM collection. Default: false | +| features.serviceDiscovery.enabled | Enables the service discovery check. Default: false | | features.tcpQueueLength.enabled | Enables the TCP queue length eBPF-based check. Default: false | | features.usm.enabled | Enables Universal Service Monitoring. Default: false | | global.clusterAgentToken | ClusterAgentToken is the token for communication between the NodeAgent and ClusterAgent. | diff --git a/examples/datadogagent/datadog-agent-all.yaml b/examples/datadogagent/datadog-agent-all.yaml index aefb68ea51..ea0cff3c00 100644 --- a/examples/datadogagent/datadog-agent-all.yaml +++ b/examples/datadogagent/datadog-agent-all.yaml @@ -45,6 +45,8 @@ spec: enabled: true sbom: enabled: true + serviceDiscovery: + enabled: true eventCollection: collectKubernetesEvents: true orchestratorExplorer: diff --git a/internal/controller/datadogagent/component/agent/default.go b/internal/controller/datadogagent/component/agent/default.go index 089c4b9fab..5a99b6566f 100644 --- a/internal/controller/datadogagent/component/agent/default.go +++ b/internal/controller/datadogagent/component/agent/default.go @@ -152,6 +152,8 @@ func agentOptimizedContainers(dda metav1.Object, requiredContainers []apicommon. containers = append(containers, systemProbeContainer(dda)) case apicommon.OtelAgent: containers = append(containers, otelAgentContainer(dda)) + case apicommon.AgentDataPlaneContainerName: + containers = append(containers, agentDataPlaneContainer(dda)) } } @@ -257,6 +259,21 @@ func systemProbeContainer(dda metav1.Object) corev1.Container { } } +func agentDataPlaneContainer(dda metav1.Object) corev1.Container { + return corev1.Container{ + Name: string(apicommon.AgentDataPlaneContainerName), + Image: agentImage(), + Command: []string{ + "agent-data-plane", + fmt.Sprintf("--config=%s", apicommon.AgentCustomConfigVolumePath), + }, + Env: commonEnvVars(dda), + VolumeMounts: volumeMountsForAgentDataPlane(), + LivenessProbe: v2alpha1.GetDefaultAgentDataPlaneLivenessProbe(), + ReadinessProbe: v2alpha1.GetDefaultAgentDataPlaneReadinessProbe(), + } +} + func initVolumeContainer() corev1.Container { return corev1.Container{ Name: "init-volume", @@ -498,6 +515,18 @@ func volumeMountsForOtelAgent() []corev1.VolumeMount { } } +func volumeMountsForAgentDataPlane() []corev1.VolumeMount { + return []corev1.VolumeMount{ + common.GetVolumeMountForLogs(), + common.GetVolumeMountForAuth(true), + common.GetVolumeMountForConfig(), + common.GetVolumeMountForDogstatsdSocket(false), + common.GetVolumeMountForRuntimeSocket(true), + common.GetVolumeMountForProc(), + common.GetVolumeMountForCgroups(), + } +} + func GetDefaultMetadata(owner metav1.Object, componentKind, componentName, version string, selector *metav1.LabelSelector) (map[string]string, map[string]string, *metav1.LabelSelector) { labels := common.GetDefaultLabels(owner, componentKind, componentName, version) annotations := object.GetDefaultAnnotations(owner) diff --git a/internal/controller/datadogagent/controller.go b/internal/controller/datadogagent/controller.go index 25af3d1ec8..e7bf62c6d2 100644 --- a/internal/controller/datadogagent/controller.go +++ b/internal/controller/datadogagent/controller.go @@ -47,6 +47,7 @@ import ( _ "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature/prometheusscrape" _ "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature/remoteconfig" _ "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature/sbom" + _ "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature/servicediscovery" _ "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature/tcpqueuelength" _ "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature/usm" ) diff --git a/internal/controller/datadogagent/feature/dogstatsd/feature.go b/internal/controller/datadogagent/feature/dogstatsd/feature.go index d19be704d2..180cf41f0d 100644 --- a/internal/controller/datadogagent/feature/dogstatsd/feature.go +++ b/internal/controller/datadogagent/feature/dogstatsd/feature.go @@ -18,6 +18,7 @@ import ( 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" "github.com/DataDog/datadog-operator/internal/controller/datadogagent/merger" "github.com/DataDog/datadog-operator/internal/controller/datadogagent/object/volume" ) @@ -50,6 +51,8 @@ type dogstatsdFeature struct { forceEnableLocalService bool localServiceName string + adpEnabled bool + owner metav1.Object } @@ -87,6 +90,8 @@ func (f *dogstatsdFeature) Configure(dda *v2alpha1.DatadogAgent) (reqComp featur } f.localServiceName = v2alpha1.GetLocalAgentServiceName(dda) + f.adpEnabled = featureutils.HasAgentDataPlaneAnnotation(dda) + reqComp = feature.RequiredComponents{ Agent: feature.RequiredComponent{ IsRequired: apiutils.NewBoolPointer(true), @@ -137,13 +142,45 @@ func (f *dogstatsdFeature) ManageClusterAgent(managers feature.PodTemplateManage // It should do nothing if the feature doesn't need to configure it. func (f *dogstatsdFeature) ManageSingleContainerNodeAgent(managers feature.PodTemplateManagers, provider string) error { f.manageNodeAgent(apicommon.UnprivilegedSingleAgentContainerName, managers, provider) + + // When ADP is enabled, we set `DD_USE_DOGSTATSD` to `false`, and `DD_ADP_ENABLED` to `true`. + // + // This disables DSD in the Core Agent, and additionally informs it that DSD is disabled because ADP is enabled and + // taking over responsibilities, rather than DSD simply being disabled intentionally, such as in the case of the + // Cluster Checks Runner. + if f.adpEnabled { + managers.EnvVar().AddEnvVarToContainer(apicommon.CoreAgentContainerName, &corev1.EnvVar{ + Name: apicommon.DDDogstatsdEnabled, + Value: "false", + }) + } + return nil } // 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 *dogstatsdFeature) ManageNodeAgent(managers feature.PodTemplateManagers, provider string) error { - f.manageNodeAgent(apicommon.CoreAgentContainerName, managers, provider) + // When ADP is enabled, we apply the DSD configuration to the ADP container instead, and set `DD_USE_DOGSTATSD` to + // `false`, and `DD_ADP_ENABLED` to `true`, on the Core Agent container. + // + // This disables DSD in the Core Agent, and additionally informs it that DSD is disabled because ADP is enabled and + // taking over responsibilities, rather than DSD simply being disabled intentionally, such as in the case of the + // Cluster Checks Runner. + // + // While we _could_ leave the DSD-specific configuration set on the Core Agent -- it doesn't so matter as long as + // DSD is disabled -- it's cleaner to remote it entirely to avoid confusion. + if f.adpEnabled { + f.manageNodeAgent(apicommon.AgentDataPlaneContainerName, managers, provider) + + managers.EnvVar().AddEnvVarToContainer(apicommon.CoreAgentContainerName, &corev1.EnvVar{ + Name: apicommon.DDDogstatsdEnabled, + Value: "false", + }) + } else { + f.manageNodeAgent(apicommon.CoreAgentContainerName, managers, provider) + } + return nil } @@ -209,7 +246,7 @@ func (f *dogstatsdFeature) manageNodeAgent(agentContainerName apicommon.AgentCon // Tag cardinality is only configured if origin detection is enabled. // The value validation happens at the Agent level - if the lower(string) is not `low`, `orchestrator` or `high`, the Agent defaults to `low`. if f.tagCardinality != "" { - managers.EnvVar().AddEnvVarToContainer(apicommon.CoreAgentContainerName, &corev1.EnvVar{ + managers.EnvVar().AddEnvVarToContainer(agentContainerName, &corev1.EnvVar{ Name: apicommon.DDDogstatsdTagCardinality, Value: f.tagCardinality, }) @@ -220,7 +257,7 @@ func (f *dogstatsdFeature) manageNodeAgent(agentContainerName apicommon.AgentCon if f.mapperProfiles != nil { // configdata if f.mapperProfiles.ConfigData != nil { - managers.EnvVar().AddEnvVarToContainer(apicommon.CoreAgentContainerName, &corev1.EnvVar{ + managers.EnvVar().AddEnvVarToContainer(agentContainerName, &corev1.EnvVar{ Name: apicommon.DDDogstatsdMapperProfiles, Value: apiutils.YAMLToJSONString(*f.mapperProfiles.ConfigData), }) @@ -232,7 +269,7 @@ func (f *dogstatsdFeature) manageNodeAgent(agentContainerName apicommon.AgentCon cmSelector := corev1.ConfigMapKeySelector{} cmSelector.Name = f.mapperProfiles.ConfigMap.Name cmSelector.Key = f.mapperProfiles.ConfigMap.Items[0].Key - managers.EnvVar().AddEnvVarToContainer(apicommon.CoreAgentContainerName, &corev1.EnvVar{ + managers.EnvVar().AddEnvVarToContainer(agentContainerName, &corev1.EnvVar{ Name: apicommon.DDDogstatsdMapperProfiles, ValueFrom: &corev1.EnvVarSource{ConfigMapKeyRef: &cmSelector}, }) diff --git a/internal/controller/datadogagent/feature/enabledefault/feature.go b/internal/controller/datadogagent/feature/enabledefault/feature.go index 7ffd5b4d1f..7d3f1a619a 100644 --- a/internal/controller/datadogagent/feature/enabledefault/feature.go +++ b/internal/controller/datadogagent/feature/enabledefault/feature.go @@ -16,6 +16,7 @@ import ( componentagent "github.com/DataDog/datadog-operator/internal/controller/datadogagent/component/agent" componentdca "github.com/DataDog/datadog-operator/internal/controller/datadogagent/component/clusteragent" "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature" + featureutils "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature/utils" "github.com/DataDog/datadog-operator/internal/controller/datadogagent/object" "github.com/DataDog/datadog-operator/pkg/controller/utils/comparison" "github.com/DataDog/datadog-operator/pkg/kubernetes" @@ -27,10 +28,6 @@ import ( "k8s.io/apimachinery/pkg/util/errors" ) -const ( - enableOtelAnnotation = "agent.datadoghq.com/otel-agent-enabled" -) - func init() { err := feature.Register(feature.DefaultIDType, buildDefaultFeature) if err != nil { @@ -71,6 +68,7 @@ type defaultFeature struct { logger logr.Logger disableNonResourceRules bool otelAgentEnabled bool + adpEnabled bool customConfigAnnotationKey string customConfigAnnotationValue string @@ -131,7 +129,11 @@ func (f *defaultFeature) Configure(dda *v2alpha1.DatadogAgent) feature.RequiredC f.clusterChecksRunner.serviceAccountAnnotations = v2alpha1.GetClusterChecksRunnerServiceAccountAnnotations(dda) if dda.ObjectMeta.Annotations != nil { - f.otelAgentEnabled = f.otelAgentEnabled || dda.ObjectMeta.Annotations[enableOtelAnnotation] == "true" + f.otelAgentEnabled = f.otelAgentEnabled || featureutils.HasOtelAgentAnnotation(dda) + } + + if dda.ObjectMeta.Annotations != nil { + f.adpEnabled = featureutils.HasAgentDataPlaneAnnotation(dda) } if dda.Spec.Global != nil { @@ -197,30 +199,29 @@ func (f *defaultFeature) Configure(dda *v2alpha1.DatadogAgent) feature.RequiredC f.customConfigAnnotationKey = object.GetChecksumAnnotationKey(string(feature.DefaultIDType)) } + agentContainers := make([]apicommon.AgentContainerName, 0) + + // If the OpenTelemetry Agent is enabled, add the OTel Agent to the list of required containers for the Agent + // feature. // - // In Operator 1.9 OTel Agent will be configured through a feature. - // In the meantime we add the OTel Agent as a required component here, if the flag is enabled. + // NOTE: This is a temporary solution until the OTel Agent is fully integrated into the Operator via a dedicated feature. if f.otelAgentEnabled { - return feature.RequiredComponents{ - ClusterAgent: feature.RequiredComponent{ - IsRequired: &trueValue, - }, - Agent: feature.RequiredComponent{ - IsRequired: &trueValue, - Containers: []apicommon.AgentContainerName{ - apicommon.OtelAgent, - }, - }, - } - } else { - return feature.RequiredComponents{ - ClusterAgent: feature.RequiredComponent{ - IsRequired: &trueValue, - }, - Agent: feature.RequiredComponent{ - IsRequired: &trueValue, - }, - } + agentContainers = append(agentContainers, apicommon.OtelAgent) + } + + // If Agent Data Plane is enabled, add the ADP container to the list of required containers for the Agent feature. + if f.adpEnabled { + agentContainers = append(agentContainers, apicommon.AgentDataPlaneContainerName) + } + + return feature.RequiredComponents{ + ClusterAgent: feature.RequiredComponent{ + IsRequired: &trueValue, + }, + Agent: feature.RequiredComponent{ + IsRequired: &trueValue, + Containers: agentContainers, + }, } } diff --git a/internal/controller/datadogagent/feature/ids.go b/internal/controller/datadogagent/feature/ids.go index ec383d7d6a..812a00a7b7 100644 --- a/internal/controller/datadogagent/feature/ids.go +++ b/internal/controller/datadogagent/feature/ids.go @@ -67,4 +67,6 @@ const ( HelmCheckIDType = "helm_check" // DummyIDType Dummy feature. DummyIDType = "dummy" + // ServiceDiscoveryType service discovery feature. + ServiceDiscoveryType = "service_discovery" ) diff --git a/internal/controller/datadogagent/feature/servicediscovery/feature.go b/internal/controller/datadogagent/feature/servicediscovery/feature.go new file mode 100644 index 0000000000..44396d4cf0 --- /dev/null +++ b/internal/controller/datadogagent/feature/servicediscovery/feature.go @@ -0,0 +1,107 @@ +package servicediscovery + +import ( + corev1 "k8s.io/api/core/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/component/agent" + "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature" + "github.com/DataDog/datadog-operator/internal/controller/datadogagent/object/volume" +) + +func init() { + if err := feature.Register(feature.ServiceDiscoveryType, buildFeature); err != nil { + panic(err) + } +} + +func buildFeature(*feature.Options) feature.Feature { + return &serviceDiscoveryFeature{} +} + +type serviceDiscoveryFeature struct{} + +// ID returns the ID of the Feature +func (f *serviceDiscoveryFeature) ID() feature.IDType { + return feature.ServiceDiscoveryType +} + +// Configure is used to configure the feature from a v2alpha1.DatadogAgent instance. +func (f *serviceDiscoveryFeature) Configure(dda *v2alpha1.DatadogAgent) (reqComp feature.RequiredComponents) { + if dda.Spec.Features != nil && dda.Spec.Features.ServiceDiscovery != nil && apiutils.BoolValue(dda.Spec.Features.ServiceDiscovery.Enabled) { + reqComp.Agent = feature.RequiredComponent{ + IsRequired: apiutils.NewBoolPointer(true), + Containers: []apicommon.AgentContainerName{apicommon.CoreAgentContainerName, apicommon.SystemProbeContainerName}, + } + } + + return reqComp +} + +// ManageDependencies allows a feature to manage its dependencies. +// Feature's dependencies should be added in the store. +func (f *serviceDiscoveryFeature) ManageDependencies(feature.ResourceManagers, feature.RequiredComponents) error { + return nil +} + +// ManageClusterAgent allows a feature to configure the ClusterAgent's corev1.PodTemplateSpec +// It should do nothing if the feature doesn't need to configure it. +func (f *serviceDiscoveryFeature) ManageClusterAgent(feature.PodTemplateManagers) error { + return nil +} + +// 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, _ string) error { + // annotations + managers.Annotation().AddAnnotation(apicommon.SystemProbeAppArmorAnnotationKey, apicommon.SystemProbeAppArmorAnnotationValue) + + // security context capabilities + managers.SecurityContext().AddCapabilitiesToContainer(agent.DefaultCapabilitiesForSystemProbe(), apicommon.SystemProbeContainerName) + + // socket volume mount (needs write perms for the system probe container but not the others) + procdirVol, procdirMount := volume.GetVolumes(apicommon.ProcdirVolumeName, apicommon.ProcdirHostPath, apicommon.ProcdirMountPath, true) + managers.VolumeMount().AddVolumeMountToContainer(&procdirMount, apicommon.SystemProbeContainerName) + managers.Volume().AddVolume(&procdirVol) + + socketVol, socketVolMount := volume.GetVolumesEmptyDir(apicommon.SystemProbeSocketVolumeName, apicommon.SystemProbeSocketVolumePath, false) + managers.Volume().AddVolume(&socketVol) + managers.VolumeMount().AddVolumeMountToContainer(&socketVolMount, apicommon.SystemProbeContainerName) + + _, socketVolMountReadOnly := volume.GetVolumesEmptyDir(apicommon.SystemProbeSocketVolumeName, apicommon.SystemProbeSocketVolumePath, true) + managers.VolumeMount().AddVolumeMountToContainer(&socketVolMountReadOnly, apicommon.CoreAgentContainerName) + + // env vars + enableEnvVar := &corev1.EnvVar{ + Name: apicommon.DDServiceDiscoveryEnabled, + Value: "true", + } + + managers.EnvVar().AddEnvVarToContainers([]apicommon.AgentContainerName{apicommon.CoreAgentContainerName, apicommon.SystemProbeContainerName}, enableEnvVar) + managers.EnvVar().AddEnvVarToInitContainer(apicommon.InitConfigContainerName, enableEnvVar) + + socketEnvVar := &corev1.EnvVar{ + Name: apicommon.DDSystemProbeSocket, + Value: v2alpha1.DefaultSystemProbeSocketPath, + } + + managers.EnvVar().AddEnvVarToContainer(apicommon.CoreAgentContainerName, socketEnvVar) + managers.EnvVar().AddEnvVarToContainer(apicommon.SystemProbeContainerName, socketEnvVar) + + return nil +} + +// 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, string) error { + return nil +} + +// 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 { + return nil +} diff --git a/internal/controller/datadogagent/feature/servicediscovery/feature_test.go b/internal/controller/datadogagent/feature/servicediscovery/feature_test.go new file mode 100644 index 0000000000..cdd00f70b3 --- /dev/null +++ b/internal/controller/datadogagent/feature/servicediscovery/feature_test.go @@ -0,0 +1,128 @@ +package servicediscovery + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "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/api/datadoghq/v2alpha1" + apiutils "github.com/DataDog/datadog-operator/api/utils" + "github.com/DataDog/datadog-operator/internal/controller/datadogagent/component/agent" + "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature" + "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature/fake" + "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature/test" +) + +func Test_serviceDiscoveryFeature_Configure(t *testing.T) { + ddaServiceDiscoveryDisabled := v2alpha1.DatadogAgent{ + Spec: v2alpha1.DatadogAgentSpec{ + Features: &v2alpha1.DatadogFeatures{ + ServiceDiscovery: &v2alpha1.ServiceDiscoveryFeatureConfig{ + Enabled: apiutils.NewBoolPointer(false), + }, + }, + }, + } + ddaServiceDiscoveryEnabled := ddaServiceDiscoveryDisabled.DeepCopy() + { + ddaServiceDiscoveryEnabled.Spec.Features.ServiceDiscovery.Enabled = apiutils.NewBoolPointer(true) + } + + serviceDiscoveryAgentNodeWantFunc := func(t testing.TB, mgrInterface feature.PodTemplateManagers) { + mgr := mgrInterface.(*fake.PodTemplateManagers) + + // check security context capabilities + sysProbeCapabilities := mgr.SecurityContextMgr.CapabilitiesByC[apicommon.SystemProbeContainerName] + assert.True( + t, + apiutils.IsEqualStruct(sysProbeCapabilities, agent.DefaultCapabilitiesForSystemProbe()), + "System Probe security context capabilities \ndiff = %s", + cmp.Diff(sysProbeCapabilities, agent.DefaultCapabilitiesForSystemProbe()), + ) + + // check volume mounts + wantCoreAgentVolMounts := []corev1.VolumeMount{ + { + Name: apicommon.SystemProbeSocketVolumeName, + MountPath: apicommon.SystemProbeSocketVolumePath, + ReadOnly: true, + }, + } + + wantSystemProbeVolMounts := []corev1.VolumeMount{ + { + Name: apicommon.ProcdirVolumeName, + MountPath: apicommon.ProcdirMountPath, + ReadOnly: true, + }, + { + Name: apicommon.SystemProbeSocketVolumeName, + MountPath: apicommon.SystemProbeSocketVolumePath, + ReadOnly: false, + }, + } + + coreAgentVolumeMounts := mgr.VolumeMountMgr.VolumeMountsByC[apicommon.CoreAgentContainerName] + assert.True(t, apiutils.IsEqualStruct(coreAgentVolumeMounts, wantCoreAgentVolMounts), "Core agent volume mounts \ndiff = %s", cmp.Diff(coreAgentVolumeMounts, wantCoreAgentVolMounts)) + + systemProbeVolumeMounts := mgr.VolumeMountMgr.VolumeMountsByC[apicommon.SystemProbeContainerName] + assert.True(t, apiutils.IsEqualStruct(systemProbeVolumeMounts, wantSystemProbeVolMounts), "System Probe volume mounts \ndiff = %s", cmp.Diff(systemProbeVolumeMounts, wantSystemProbeVolMounts)) + + // check volumes + wantVolumes := []corev1.Volume{ + { + Name: apicommon.ProcdirVolumeName, + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: apicommon.ProcdirHostPath, + }, + }, + }, + { + Name: apicommon.SystemProbeSocketVolumeName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + } + + volumes := mgr.VolumeMgr.Volumes + assert.True(t, apiutils.IsEqualStruct(volumes, wantVolumes), "Volumes \ndiff = %s", cmp.Diff(volumes, wantVolumes)) + + // check env vars + wantEnvVars := []*corev1.EnvVar{ + { + Name: apicommon.DDServiceDiscoveryEnabled, + Value: "true", + }, + { + Name: apicommon.DDSystemProbeSocket, + Value: v2alpha1.DefaultSystemProbeSocketPath, + }, + } + agentEnvVars := mgr.EnvVarMgr.EnvVarsByC[apicommon.CoreAgentContainerName] + assert.True(t, apiutils.IsEqualStruct(agentEnvVars, wantEnvVars), "Agent envvars \ndiff = %s", cmp.Diff(agentEnvVars, wantEnvVars)) + + systemProbeEnvVars := mgr.EnvVarMgr.EnvVarsByC[apicommon.SystemProbeContainerName] + assert.True(t, apiutils.IsEqualStruct(systemProbeEnvVars, wantEnvVars), "System Probe envvars \ndiff = %s", cmp.Diff(systemProbeEnvVars, wantEnvVars)) + } + + tests := test.FeatureTestSuite{ + { + Name: "service discovery not enabled", + DDA: ddaServiceDiscoveryDisabled.DeepCopy(), + WantConfigure: false, + }, + { + Name: "service discovery enabled", + DDA: ddaServiceDiscoveryEnabled, + WantConfigure: true, + Agent: test.NewDefaultComponentTest().WithWantFunc(serviceDiscoveryAgentNodeWantFunc), + }, + } + + tests.Run(t, buildFeature) +} diff --git a/internal/controller/datadogagent/feature/test/factory_test.go b/internal/controller/datadogagent/feature/test/factory_test.go index 69d96f2e52..0ef867e9db 100644 --- a/internal/controller/datadogagent/feature/test/factory_test.go +++ b/internal/controller/datadogagent/feature/test/factory_test.go @@ -39,6 +39,7 @@ func TestBuilder(t *testing.T) { common.SystemProbeContainerName: false, common.SecurityAgentContainerName: false, common.OtelAgent: false, + common.AgentDataPlaneContainerName: false, }, }, { @@ -54,6 +55,7 @@ func TestBuilder(t *testing.T) { common.SystemProbeContainerName: false, common.SecurityAgentContainerName: false, common.OtelAgent: false, + common.AgentDataPlaneContainerName: false, }, }, { @@ -69,6 +71,7 @@ func TestBuilder(t *testing.T) { common.SystemProbeContainerName: false, common.SecurityAgentContainerName: false, common.OtelAgent: false, + common.AgentDataPlaneContainerName: false, }, }, { @@ -85,6 +88,7 @@ func TestBuilder(t *testing.T) { common.SystemProbeContainerName: false, common.SecurityAgentContainerName: false, common.OtelAgent: false, + common.AgentDataPlaneContainerName: false, }, }, { @@ -101,6 +105,7 @@ func TestBuilder(t *testing.T) { common.SystemProbeContainerName: true, common.SecurityAgentContainerName: false, common.OtelAgent: false, + common.AgentDataPlaneContainerName: false, }, }, { @@ -118,6 +123,7 @@ func TestBuilder(t *testing.T) { common.SystemProbeContainerName: true, common.SecurityAgentContainerName: false, common.OtelAgent: false, + common.AgentDataPlaneContainerName: false, }, }, { @@ -135,6 +141,7 @@ func TestBuilder(t *testing.T) { common.SystemProbeContainerName: true, common.SecurityAgentContainerName: true, common.OtelAgent: false, + common.AgentDataPlaneContainerName: false, }, }, { @@ -153,6 +160,7 @@ func TestBuilder(t *testing.T) { common.SystemProbeContainerName: true, common.SecurityAgentContainerName: true, common.OtelAgent: false, + common.AgentDataPlaneContainerName: false, }, }, { @@ -168,6 +176,7 @@ func TestBuilder(t *testing.T) { common.SystemProbeContainerName: false, common.SecurityAgentContainerName: false, common.OtelAgent: true, + common.AgentDataPlaneContainerName: false, }, }, { @@ -183,6 +192,7 @@ func TestBuilder(t *testing.T) { common.SystemProbeContainerName: false, common.SecurityAgentContainerName: false, common.OtelAgent: false, + common.AgentDataPlaneContainerName: false, }, }, { @@ -201,6 +211,39 @@ func TestBuilder(t *testing.T) { common.SystemProbeContainerName: false, common.SecurityAgentContainerName: false, common.OtelAgent: true, + common.AgentDataPlaneContainerName: false, + }, + }, + { + name: "Default DDA, default feature Option, adp-enabled annotation true", + dda: v2alpha1test.NewDatadogAgentBuilder(). + WithAnnotations(map[string]string{"agent.datadoghq.com/adp-enabled": "true"}). + BuildWithDefaults(), + wantAgentContainer: map[common.AgentContainerName]bool{ + common.UnprivilegedSingleAgentContainerName: false, + common.CoreAgentContainerName: true, + common.ProcessAgentContainerName: true, + common.TraceAgentContainerName: true, + common.SystemProbeContainerName: false, + common.SecurityAgentContainerName: false, + common.OtelAgent: false, + common.AgentDataPlaneContainerName: true, + }, + }, + { + name: "Default DDA, default feature Option, adp-enabled annotation false", + dda: v2alpha1test.NewDatadogAgentBuilder(). + WithAnnotations(map[string]string{"agent.datadoghq.com/adp-enabled": "false"}). + BuildWithDefaults(), + wantAgentContainer: map[common.AgentContainerName]bool{ + common.UnprivilegedSingleAgentContainerName: false, + common.CoreAgentContainerName: true, + common.ProcessAgentContainerName: true, + common.TraceAgentContainerName: true, + common.SystemProbeContainerName: false, + common.SecurityAgentContainerName: false, + common.OtelAgent: false, + common.AgentDataPlaneContainerName: false, }, }, } diff --git a/internal/controller/datadogagent/feature/utils/utils.go b/internal/controller/datadogagent/feature/utils/utils.go index 65b2b25942..d298f5ff9a 100644 --- a/internal/controller/datadogagent/feature/utils/utils.go +++ b/internal/controller/datadogagent/feature/utils/utils.go @@ -16,9 +16,9 @@ import ( "github.com/DataDog/datadog-operator/internal/controller/datadogagent/common" ) -// Process Checks utils - const RunInCoreAgentMinVersion = "7.57.0-0" +const enableOtelAnnotation = "agent.datadoghq.com/otel-agent-enabled" +const enableAdpAnnotation = "agent.datadoghq.com/adp-enabled" func agentSupportsRunInCoreAgent(dda *v2alpha1.DatadogAgent) bool { // Agent version must >= 7.53.0 to run feature in core agent @@ -50,3 +50,21 @@ func OverrideRunInCoreAgent(dda *v2alpha1.DatadogAgent, currentVal bool) bool { return currentVal } + +func hasFeatureEnableAnnotation(dda *v2alpha1.DatadogAgent, annotation string) bool { + if value, ok := dda.ObjectMeta.Annotations[annotation]; ok { + return value == "true" + } + return false +} + +// HasOtelAgentAnnotation returns true if the OpenTelemetry Agent is enabled via the dedicated +// `agent.datadoghq.com/otel-agent-enabled` annotation +func HasOtelAgentAnnotation(dda *v2alpha1.DatadogAgent) bool { + return hasFeatureEnableAnnotation(dda, enableOtelAnnotation) +} + +// HasAgentDataPlaneAnnotation returns true if the Agent Data Plane is enabled via the dedicated `agent.datadoghq.com/adp-enabled` annotation +func HasAgentDataPlaneAnnotation(dda *v2alpha1.DatadogAgent) bool { + return hasFeatureEnableAnnotation(dda, enableAdpAnnotation) +} diff --git a/internal/controller/datadogagent/merger/utils.go b/internal/controller/datadogagent/merger/utils.go index 9963d432a5..712a093c2e 100644 --- a/internal/controller/datadogagent/merger/utils.go +++ b/internal/controller/datadogagent/merger/utils.go @@ -10,12 +10,13 @@ import "github.com/DataDog/datadog-operator/api/datadoghq/common" // AllAgentContainers is a map of all agent containers var AllAgentContainers = map[common.AgentContainerName]struct{}{ // Node agent containers - common.CoreAgentContainerName: {}, - common.TraceAgentContainerName: {}, - common.ProcessAgentContainerName: {}, - common.SecurityAgentContainerName: {}, - common.SystemProbeContainerName: {}, - common.OtelAgent: {}, + common.CoreAgentContainerName: {}, + common.TraceAgentContainerName: {}, + common.ProcessAgentContainerName: {}, + common.SecurityAgentContainerName: {}, + common.SystemProbeContainerName: {}, + common.OtelAgent: {}, + common.AgentDataPlaneContainerName: {}, // DCA containers common.ClusterAgentContainerName: {}, // CCR container name is equivalent to core agent container name diff --git a/internal/controller/datadogagent_controller_test.go b/internal/controller/datadogagent_controller_test.go index ffe89b27a3..b8442043aa 100644 --- a/internal/controller/datadogagent_controller_test.go +++ b/internal/controller/datadogagent_controller_test.go @@ -89,6 +89,11 @@ var _ = Describe("V2 Controller - DatadogAgent Deployment", func() { testFunction(testutils.NewDatadogAgentWithEBPFCheck(namespace, "with-ebpfcheck")), ) + Context( + "with service discovery enabled", + testFunction(testutils.NewDatadogAgentWithServiceDiscovery(namespace, "with-service-discovery")), + ) + Context( "with Event Collection", testFunction(testutils.NewDatadogAgentWithEventCollection(namespace, "with-event-collection")), diff --git a/internal/controller/testutils/agent.go b/internal/controller/testutils/agent.go index a8a98b17d8..1c71ae106f 100644 --- a/internal/controller/testutils/agent.go +++ b/internal/controller/testutils/agent.go @@ -155,6 +155,19 @@ func NewDatadogAgentWithEBPFCheck(namespace string, name string) v2alpha1.Datado ) } +// NewDatadogAgentWithServiceDiscovery returns an agent with Service Discovery enabled +func NewDatadogAgentWithServiceDiscovery(namespace, name string) v2alpha1.DatadogAgent { + return newDatadogAgentWithFeatures( + namespace, + name, + &v2alpha1.DatadogFeatures{ + ServiceDiscovery: &v2alpha1.ServiceDiscoveryFeatureConfig{ + Enabled: apiutils.NewBoolPointer(true), + }, + }, + ) +} + // NewDatadogAgentWithEventCollection returns an agent with event collection enabled func NewDatadogAgentWithEventCollection(namespace string, name string) v2alpha1.DatadogAgent { return newDatadogAgentWithFeatures(