From d5839680197d369d8bc0f3393093cad365618b31 Mon Sep 17 00:00:00 2001 From: Guy Arbitman Date: Sun, 6 Oct 2024 16:51:43 +0300 Subject: [PATCH] service discovery: Add operator support --- LICENSE-3rdparty.csv | 121 ------------------ api/datadoghq/common/envvar.go | 1 + .../v2alpha1/datadogagent_default.go | 7 + .../v2alpha1/datadogagent_default_test.go | 43 +++++++ api/datadoghq/v2alpha1/datadogagent_types.go | 10 ++ .../v2alpha1/zz_generated.deepcopy.go | 25 ++++ .../v2alpha1/zz_generated.openapi.go | 8 +- .../bases/v1/datadoghq.com_datadogagents.yaml | 18 +++ docs/configuration.v2alpha1.md | 1 + examples/datadogagent/datadog-agent-all.yaml | 2 + .../controller/datadogagent/controller.go | 1 + .../controller/datadogagent/feature/ids.go | 2 + .../feature/servicediscovery/feature.go | 100 +++++++++++++++ .../feature/servicediscovery/feature_test.go | 115 +++++++++++++++++ .../datadogagent_controller_test.go | 5 + internal/controller/datadogslo/controller.go | 4 +- internal/controller/testutils/agent.go | 13 ++ 17 files changed, 352 insertions(+), 124 deletions(-) create mode 100644 internal/controller/datadogagent/feature/servicediscovery/feature.go create mode 100644 internal/controller/datadogagent/feature/servicediscovery/feature_test.go diff --git a/LICENSE-3rdparty.csv b/LICENSE-3rdparty.csv index f4b00e3d8f..e69de29bb2 100644 --- a/LICENSE-3rdparty.csv +++ b/LICENSE-3rdparty.csv @@ -1,121 +0,0 @@ -Component,Origin,License -core,github.com/DataDog/datadog-agent/pkg/config/model,Apache-2.0 -core,github.com/DataDog/datadog-agent/pkg/config/remote,Apache-2.0 -core,github.com/DataDog/datadog-agent/pkg/proto,Apache-2.0 -core,github.com/DataDog/datadog-agent/pkg/remoteconfig/state,Apache-2.0 -core,github.com/DataDog/datadog-agent/pkg/util/backoff,Apache-2.0 -core,github.com/DataDog/datadog-agent/pkg/util/cache,Apache-2.0 -core,github.com/DataDog/datadog-agent/pkg/util/grpc,Apache-2.0 -core,github.com/DataDog/datadog-agent/pkg/util/http,Apache-2.0 -core,github.com/DataDog/datadog-agent/pkg/util/log,Apache-2.0 -core,github.com/DataDog/datadog-agent/pkg/util/scrubber,Apache-2.0 -core,github.com/DataDog/datadog-agent/pkg/util/uuid,Apache-2.0 -core,github.com/DataDog/datadog-api-client-go/v2,Apache-2.0 -core,github.com/DataDog/datadog-go/v5/statsd,MIT -core,github.com/DataDog/datadog-operator,Apache-2.0 -core,github.com/DataDog/extendeddaemonset/api/v1alpha1,Apache-2.0 -core,github.com/DataDog/go-tuf,BSD-3-Clause -core,github.com/DataDog/gostackparse,Apache-2.0 -core,github.com/DataDog/viper,MIT -core,github.com/DataDog/zstd,BSD-3-Clause -core,github.com/Masterminds/semver,MIT -core,github.com/Masterminds/semver/v3,MIT -core,github.com/benbjohnson/clock,MIT -core,github.com/beorn7/perks/quantile,MIT -core,github.com/cenkalti/backoff,MIT -core,github.com/cespare/xxhash/v2,MIT -core,github.com/cihub/seelog,BSD-3-Clause -core,github.com/davecgh/go-spew/spew,ISC -core,github.com/emicklei/go-restful/v3,MIT -core,github.com/evanphx/json-patch/v5,BSD-3-Clause -core,github.com/fsnotify/fsnotify,BSD-3-Clause -core,github.com/go-logr/logr,Apache-2.0 -core,github.com/go-logr/zapr,Apache-2.0 -core,github.com/go-openapi/jsonpointer,Apache-2.0 -core,github.com/go-openapi/jsonreference,Apache-2.0 -core,github.com/go-openapi/swag,Apache-2.0 -core,github.com/gobwas/glob,MIT -core,github.com/gogo/protobuf,BSD-3-Clause -core,github.com/golang/groupcache/lru,Apache-2.0 -core,github.com/golang/protobuf,BSD-3-Clause -core,github.com/google/gnostic-models,Apache-2.0 -core,github.com/google/go-cmp/cmp,BSD-3-Clause -core,github.com/google/gofuzz,Apache-2.0 -core,github.com/google/pprof/profile,Apache-2.0 -core,github.com/google/uuid,BSD-3-Clause -core,github.com/grpc-ecosystem/go-grpc-middleware,Apache-2.0 -core,github.com/grpc-ecosystem/grpc-gateway,BSD-3-Clause -core,github.com/hashicorp/hcl,MPL-2.0 -core,github.com/imdario/mergo,BSD-3-Clause -core,github.com/josharian/intern,MIT -core,github.com/json-iterator/go,MIT -core,github.com/magiconair/properties,BSD-2-Clause -core,github.com/mailru/easyjson,MIT -core,github.com/matttproud/golang_protobuf_extensions/pbutil,Apache-2.0 -core,github.com/mitchellh/mapstructure,MIT -core,github.com/modern-go/concurrent,Apache-2.0 -core,github.com/modern-go/reflect2,Apache-2.0 -core,github.com/mohae/deepcopy,MIT -core,github.com/munnerz/goautoneg,BSD-3-Clause -core,github.com/patrickmn/go-cache,MIT -core,github.com/pelletier/go-toml,Apache-2.0 -core,github.com/philhofer/fwd,MIT -core,github.com/pkg/errors,BSD-2-Clause -core,github.com/pmezard/go-difflib/difflib,BSD-3-Clause -core,github.com/prometheus/client_golang/prometheus,Apache-2.0 -core,github.com/prometheus/client_model/go,Apache-2.0 -core,github.com/prometheus/common,Apache-2.0 -core,github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg,BSD-3-Clause -core,github.com/prometheus/procfs,Apache-2.0 -core,github.com/richardartoul/molecule,MIT -core,github.com/richardartoul/molecule/src/codec,Apache-2.0 -core,github.com/richardartoul/molecule/src/protowire,BSD-3-Clause -core,github.com/secure-systems-lab/go-securesystemslib/cjson,MIT -core,github.com/shirou/gopsutil/v3,BSD-3-Clause -core,github.com/spaolacci/murmur3,BSD-3-Clause -core,github.com/spf13/afero,Apache-2.0 -core,github.com/spf13/cast,MIT -core,github.com/spf13/jwalterweatherman,MIT -core,github.com/spf13/pflag,BSD-3-Clause -core,github.com/stretchr/objx,MIT -core,github.com/stretchr/testify,MIT -core,github.com/tinylib/msgp/msgp,MIT -core,github.com/zorkian/go-datadog-api,BSD-3-Clause -core,go.etcd.io/bbolt,MIT -core,go.uber.org/atomic,MIT -core,go.uber.org/multierr,MIT -core,go.uber.org/zap,MIT -core,golang.org/x/exp,BSD-3-Clause -core,golang.org/x/net,BSD-3-Clause -core,golang.org/x/oauth2,BSD-3-Clause -core,golang.org/x/sys/unix,BSD-3-Clause -core,golang.org/x/term,BSD-3-Clause -core,golang.org/x/text,BSD-3-Clause -core,golang.org/x/time/rate,BSD-3-Clause -core,gomodules.xyz/jsonpatch/v2,Apache-2.0 -core,google.golang.org/genproto/googleapis/api,Apache-2.0 -core,google.golang.org/genproto/googleapis/rpc/status,Apache-2.0 -core,google.golang.org/genproto/protobuf/field_mask,Apache-2.0 -core,google.golang.org/grpc,Apache-2.0 -core,google.golang.org/protobuf,BSD-3-Clause -core,gopkg.in/DataDog/dd-trace-go.v1,Apache-2.0 -core,gopkg.in/inf.v0,BSD-3-Clause -core,gopkg.in/yaml.v2,Apache-2.0 -core,gopkg.in/yaml.v3,MIT -core,k8s.io/api,Apache-2.0 -core,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions,Apache-2.0 -core,k8s.io/apimachinery/pkg,Apache-2.0 -core,k8s.io/apimachinery/third_party/forked/golang,BSD-3-Clause -core,k8s.io/client-go,Apache-2.0 -core,k8s.io/component-base/config,Apache-2.0 -core,k8s.io/klog/v2,Apache-2.0 -core,k8s.io/kube-aggregator/pkg/apis/apiregistration,Apache-2.0 -core,k8s.io/kube-openapi/pkg,Apache-2.0 -core,k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json,BSD-3-Clause -core,k8s.io/kube-openapi/pkg/validation/spec,Apache-2.0 -core,k8s.io/utils,Apache-2.0 -core,k8s.io/utils/internal/third_party/forked/golang/net,BSD-3-Clause -core,sigs.k8s.io/controller-runtime,Apache-2.0 -core,sigs.k8s.io/json,Apache-2.0 -core,sigs.k8s.io/structured-merge-diff/v4,Apache-2.0 -core,sigs.k8s.io/yaml,MIT diff --git a/api/datadoghq/common/envvar.go b/api/datadoghq/common/envvar.go index cecab2524c..d17e9204e4 100644 --- a/api/datadoghq/common/envvar.go +++ b/api/datadoghq/common/envvar.go @@ -152,6 +152,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/v2alpha1/datadogagent_default.go b/api/datadoghq/v2alpha1/datadogagent_default.go index 2c641c7bbe..1fe116944a 100644 --- a/api/datadoghq/v2alpha1/datadogagent_default.go +++ b/api/datadoghq/v2alpha1/datadogagent_default.go @@ -36,6 +36,8 @@ const ( defaultEBPFCheckEnabled bool = false + defaultServiceDiscoveryEnabled bool = false + defaultAPMEnabled bool = true defaultAPMHostPortEnabled bool = false defaultAPMHostPort int32 = 8126 @@ -244,6 +246,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 7533de7cb8..0a333f464d 100644 --- a/api/datadoghq/v2alpha1/datadogagent_default_test.go +++ b/api/datadoghq/v2alpha1/datadogagent_default_test.go @@ -194,6 +194,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{ @@ -314,6 +317,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), }, @@ -396,6 +402,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), }, @@ -507,6 +516,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{ @@ -639,6 +651,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{ @@ -766,6 +781,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{ @@ -893,6 +911,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{ @@ -1029,6 +1050,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{ @@ -1156,6 +1180,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{ @@ -1286,6 +1313,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{ @@ -1443,6 +1473,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), }, @@ -1546,6 +1579,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{ @@ -1654,6 +1690,7 @@ func Test_defaultFeatures(t *testing.T) { OOMKill: &OOMKillFeatureConfig{}, TCPQueueLength: &TCPQueueLengthFeatureConfig{}, EBPFCheck: &EBPFCheckFeatureConfig{}, + ServiceDiscovery: &ServiceDiscoveryFeatureConfig{}, APM: &APMFeatureConfig{}, ASM: &ASMFeatureConfig{}, CSPM: &CSPMFeatureConfig{}, @@ -1695,6 +1732,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{ @@ -1825,6 +1865,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 213d2246db..c3a6deb43d 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 discover 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/zz_generated.deepcopy.go b/api/datadoghq/v2alpha1/zz_generated.deepcopy.go index c6b27c8e44..a6cd140780 100644 --- a/api/datadoghq/v2alpha1/zz_generated.deepcopy.go +++ b/api/datadoghq/v2alpha1/zz_generated.deepcopy.go @@ -1115,6 +1115,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) @@ -2461,6 +2466,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 d3bf1a3d2c..40d76650b5 100644 --- a/api/datadoghq/v2alpha1/zz_generated.openapi.go +++ b/api/datadoghq/v2alpha1/zz_generated.openapi.go @@ -623,6 +623,12 @@ func schema__api_datadoghq_v2alpha1_DatadogFeatures(ref common.ReferenceCallback Ref: ref("./api/datadoghq/v2alpha1.SBOMFeatureConfig"), }, }, + "serviceDiscovery": { + SchemaProps: spec.SchemaProps{ + Description: "ServiceDiscovery", + Ref: ref("./api/datadoghq/v2alpha1.ServiceDiscoveryFeatureConfig"), + }, + }, "eventCollection": { SchemaProps: spec.SchemaProps{ Description: "EventCollection configuration.", @@ -681,7 +687,7 @@ func schema__api_datadoghq_v2alpha1_DatadogFeatures(ref common.ReferenceCallback }, }, Dependencies: []string{ - "./api/datadoghq/v2alpha1.APMFeatureConfig", "./api/datadoghq/v2alpha1.ASMFeatureConfig", "./api/datadoghq/v2alpha1.AdmissionControllerFeatureConfig", "./api/datadoghq/v2alpha1.AutoscalingFeatureConfig", "./api/datadoghq/v2alpha1.CSPMFeatureConfig", "./api/datadoghq/v2alpha1.CWSFeatureConfig", "./api/datadoghq/v2alpha1.ClusterChecksFeatureConfig", "./api/datadoghq/v2alpha1.DogstatsdFeatureConfig", "./api/datadoghq/v2alpha1.EBPFCheckFeatureConfig", "./api/datadoghq/v2alpha1.EventCollectionFeatureConfig", "./api/datadoghq/v2alpha1.ExternalMetricsServerFeatureConfig", "./api/datadoghq/v2alpha1.HelmCheckFeatureConfig", "./api/datadoghq/v2alpha1.KubeStateMetricsCoreFeatureConfig", "./api/datadoghq/v2alpha1.LiveContainerCollectionFeatureConfig", "./api/datadoghq/v2alpha1.LiveProcessCollectionFeatureConfig", "./api/datadoghq/v2alpha1.LogCollectionFeatureConfig", "./api/datadoghq/v2alpha1.NPMFeatureConfig", "./api/datadoghq/v2alpha1.OOMKillFeatureConfig", "./api/datadoghq/v2alpha1.OTLPFeatureConfig", "./api/datadoghq/v2alpha1.OrchestratorExplorerFeatureConfig", "./api/datadoghq/v2alpha1.ProcessDiscoveryFeatureConfig", "./api/datadoghq/v2alpha1.PrometheusScrapeFeatureConfig", "./api/datadoghq/v2alpha1.RemoteConfigurationFeatureConfig", "./api/datadoghq/v2alpha1.SBOMFeatureConfig", "./api/datadoghq/v2alpha1.TCPQueueLengthFeatureConfig", "./api/datadoghq/v2alpha1.USMFeatureConfig"}, + "./api/datadoghq/v2alpha1.APMFeatureConfig", "./api/datadoghq/v2alpha1.ASMFeatureConfig", "./api/datadoghq/v2alpha1.AdmissionControllerFeatureConfig", "./api/datadoghq/v2alpha1.AutoscalingFeatureConfig", "./api/datadoghq/v2alpha1.CSPMFeatureConfig", "./api/datadoghq/v2alpha1.CWSFeatureConfig", "./api/datadoghq/v2alpha1.ClusterChecksFeatureConfig", "./api/datadoghq/v2alpha1.DogstatsdFeatureConfig", "./api/datadoghq/v2alpha1.EBPFCheckFeatureConfig", "./api/datadoghq/v2alpha1.EventCollectionFeatureConfig", "./api/datadoghq/v2alpha1.ExternalMetricsServerFeatureConfig", "./api/datadoghq/v2alpha1.HelmCheckFeatureConfig", "./api/datadoghq/v2alpha1.KubeStateMetricsCoreFeatureConfig", "./api/datadoghq/v2alpha1.LiveContainerCollectionFeatureConfig", "./api/datadoghq/v2alpha1.LiveProcessCollectionFeatureConfig", "./api/datadoghq/v2alpha1.LogCollectionFeatureConfig", "./api/datadoghq/v2alpha1.NPMFeatureConfig", "./api/datadoghq/v2alpha1.OOMKillFeatureConfig", "./api/datadoghq/v2alpha1.OTLPFeatureConfig", "./api/datadoghq/v2alpha1.OrchestratorExplorerFeatureConfig", "./api/datadoghq/v2alpha1.ProcessDiscoveryFeatureConfig", "./api/datadoghq/v2alpha1.PrometheusScrapeFeatureConfig", "./api/datadoghq/v2alpha1.RemoteConfigurationFeatureConfig", "./api/datadoghq/v2alpha1.SBOMFeatureConfig", "./api/datadoghq/v2alpha1.ServiceDiscoveryFeatureConfig", "./api/datadoghq/v2alpha1.TCPQueueLengthFeatureConfig", "./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 a9af8f6602..461457bad2 100644 --- a/config/crd/bases/v1/datadoghq.com_datadogagents.yaml +++ b/config/crd/bases/v1/datadoghq.com_datadogagents.yaml @@ -1410,6 +1410,15 @@ spec: type: boolean type: object type: object + serviceDiscovery: + description: ServiceDiscovery + properties: + enabled: + description: |- + Enables the service discover check. + Default: false + type: boolean + type: object tcpQueueLength: description: TCPQueueLength configuration. properties: @@ -7485,6 +7494,15 @@ spec: type: boolean type: object type: object + serviceDiscovery: + description: ServiceDiscovery + properties: + enabled: + description: |- + Enables the service discover 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 9e73bc151e..42228f52d6 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 | 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 discover check. Default: false | | features.tcpQueueLength.enabled | Enables the TCP queue length eBPF-based check. Default: false | | features.usm.enabled | 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/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/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..e3f2f0dc7f --- /dev/null +++ b/internal/controller/datadogagent/feature/servicediscovery/feature.go @@ -0,0 +1,100 @@ +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 { + // 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) + 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..61ad256d55 --- /dev/null +++ b/internal/controller/datadogagent/feature/servicediscovery/feature_test.go @@ -0,0 +1,115 @@ +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.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.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_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/datadogslo/controller.go b/internal/controller/datadogslo/controller.go index 28fd20a3e3..ad47ea877e 100644 --- a/internal/controller/datadogslo/controller.go +++ b/internal/controller/datadogslo/controller.go @@ -56,8 +56,8 @@ func NewReconciler(client client.Client, ddClient datadogclient.DatadogSLOClient client: client, datadogClient: ddClient.Client, datadogAuth: ddClient.Auth, - log: log, - recorder: recorder, + log: log, + recorder: recorder, } } diff --git a/internal/controller/testutils/agent.go b/internal/controller/testutils/agent.go index dceae008c3..3f2b55b596 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(