Skip to content

Commit

Permalink
[Orch] Add CRD RC handler (#1340)
Browse files Browse the repository at this point in the history
* [Orch] Add CRD RC handler

* Remove print statement

* Refactor to separate file

* Move last function

* Use CRD specific status

* Add cluster agent config to RC

* Correctly set product

* Fix product and add logging

* Add fixes for crd nil pointers

* Revert accidental commit

* Update dependencies and add tag getter function

* Go.mod change

* Reset go.mod

* Update remoteconfig/state

* Fix updater package and work sum

* Clean up logs and force restart of DCA on CR changes

* Add a lock around get and update of DDA

* Improve comments and change test to use orchexp for annotation

* Change to not do annotations every single time

* Fill in orchestrator explorer for tests

* Go mod update

* Modify retry logic so it doesn't it for the entire update

* Fix go.mod

* Check in config crd stuff

* Remove hard coded product and update go.mod

* Revert go.mod back and fix errors

* Go.sum update

* overwrite cr by incoming data instead of appending to the old data (#1473)

* feedback

* feedback

* rename to OrchestratorK8sCRDRemoteConfig

---------

Co-authored-by: Kangyi LI <kangyi.li@datadoghq.com>
Co-authored-by: levan-m <116471169+levan-m@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 22, 2024
1 parent 342d9af commit ae5b9e1
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 55 deletions.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/DataDog/datadog-operator

go 1.22
go 1.22.0

toolchain go1.22.7

Expand Down Expand Up @@ -41,7 +41,7 @@ require (
require (
github.com/DataDog/datadog-agent/pkg/config/model v0.55.0-rc.10
github.com/DataDog/datadog-agent/pkg/config/remote v0.55.0-rc.10
github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.55.0-rc.10
github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.59.0-rc.1
github.com/prometheus/client_golang v1.16.0
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
)
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ github.com/DataDog/datadog-agent/pkg/proto v0.55.0-rc.10 h1:ERkVmUoDPttyVKSCJM1f
github.com/DataDog/datadog-agent/pkg/proto v0.55.0-rc.10/go.mod h1:gHkSUTn6H6UEZQHY3XWBIGNjfI3Tdi0IxlrxIFBWDwU=
github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.55.0-rc.10 h1:nwJ2JWfjCmf6tpJD1RYHh4JV5HO2Njg6smxOGi8MyOE=
github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.55.0-rc.10/go.mod h1:3yFk56PJ57yS1GqI9HAsS4PSlAeGCC9RQA7jxKzYj6g=
github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.59.0-rc.1 h1:CIXKFvUsp5zgE+egvx+QrRTw8r54FMPZVu+z25UNqWs=
github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.59.0-rc.1/go.mod h1:c4th0IFaP0Q1ofRa0GcPB9hJWN+cmUoEfOI1Ub0O50A=
github.com/DataDog/datadog-agent/pkg/util/backoff v0.55.0-rc.10 h1:+CizlqZ6JyXqH8KAy8NVTZaeZXu+Rfa/o+FPNxNSTFU=
github.com/DataDog/datadog-agent/pkg/util/backoff v0.55.0-rc.10/go.mod h1:HcSwqoxWLfevi1vuDZuFeRHfSuHGakTN6/u42WbxQHE=
github.com/DataDog/datadog-agent/pkg/util/cache v0.55.0-rc.10 h1:5S75F/6jCSUCqWhDQzPwPmuuOh3wkUPvkiPKnuKMyag=
Expand Down
12 changes: 12 additions & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,8 @@ github.com/DataDog/datadog-agent/pkg/config/remote v0.52.0/go.mod h1:3VjunAU6Chi
github.com/DataDog/datadog-agent/pkg/proto v0.55.0-rc.3/go.mod h1:gHkSUTn6H6UEZQHY3XWBIGNjfI3Tdi0IxlrxIFBWDwU=
github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.43.1/go.mod h1:VVMDDibJxYEkwcLdZBT2g8EHKpbMT4JdOhRbQ9GdjbM=
github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.52.0/go.mod h1:JhAilx32dkIgoDkFXquCTfaWDsAOfe+vfBaxbiZoPI0=
github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.59.0-rc.1 h1:CIXKFvUsp5zgE+egvx+QrRTw8r54FMPZVu+z25UNqWs=
github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.59.0-rc.1/go.mod h1:c4th0IFaP0Q1ofRa0GcPB9hJWN+cmUoEfOI1Ub0O50A=
github.com/DataDog/datadog-agent/pkg/util/backoff v0.55.0-rc.3/go.mod h1:HcSwqoxWLfevi1vuDZuFeRHfSuHGakTN6/u42WbxQHE=
github.com/DataDog/datadog-agent/pkg/util/cache v0.55.0-rc.3/go.mod h1:CyE7vd6fco00C7v3R7Vt0kRg3Pz5Ssb29gV5YiEqsaU=
github.com/DataDog/datadog-agent/pkg/util/grpc v0.55.0-rc.3/go.mod h1:Mp2DgImefU2Xz3Wr3fQjBd8hhEem4zNzf+ofm6mHaco=
Expand Down Expand Up @@ -2673,6 +2675,8 @@ golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
Expand Down Expand Up @@ -2766,6 +2770,8 @@ golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down Expand Up @@ -2855,6 +2861,8 @@ golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457 h1:zf5N6UOrA487eEFacMePxjXAJctxKmyjKUsjA11Uzuk=
Expand All @@ -2867,12 +2875,16 @@ golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ func (f *orchestratorExplorerFeature) ID() feature.IDType {
// Configure is used to configure the feature from a v2alpha1.DatadogAgent instance.
func (f *orchestratorExplorerFeature) Configure(dda *v2alpha1.DatadogAgent) (reqComp feature.RequiredComponents) {
f.owner = dda

// Merge configuration from Status.RemoteConfigConfiguration into the Spec
f.mergeConfigs(&dda.Spec, &dda.Status)

orchestratorExplorer := dda.Spec.Features.OrchestratorExplorer

if orchestratorExplorer != nil && apiutils.BoolValue(orchestratorExplorer.Enabled) {
Expand All @@ -92,9 +96,12 @@ func (f *orchestratorExplorerFeature) Configure(dda *v2alpha1.DatadogAgent) (req
Containers: reqContainers,
}

if orchestratorExplorer.Conf != nil {
if orchestratorExplorer.Conf != nil || len(orchestratorExplorer.CustomResources) > 0 {
f.customConfig = orchestratorExplorer.Conf
hash, err := comparison.GenerateMD5ForSpec(f.customConfig)

// Used to force restart of DCA
// use entire orchestratorExplorer to handle custom config and CRDs
hash, err := comparison.GenerateMD5ForSpec(orchestratorExplorer)
if err != nil {
f.logger.Error(err, "couldn't generate hash for orchestrator explorer custom config")
} else {
Expand All @@ -103,6 +110,7 @@ func (f *orchestratorExplorerFeature) Configure(dda *v2alpha1.DatadogAgent) (req
f.customConfigAnnotationValue = hash
f.customConfigAnnotationKey = object.GetChecksumAnnotationKey(feature.OrchestratorExplorerIDType)
}

f.customResources = dda.Spec.Features.OrchestratorExplorer.CustomResources
f.configConfigMapName = v2alpha1.GetConfName(dda, f.customConfig, v2alpha1.DefaultOrchestratorExplorerConf)
f.scrubContainers = apiutils.BoolValue(orchestratorExplorer.ScrubContainers)
Expand All @@ -125,6 +133,25 @@ func (f *orchestratorExplorerFeature) Configure(dda *v2alpha1.DatadogAgent) (req
return reqComp
}

func (f *orchestratorExplorerFeature) mergeConfigs(ddaSpec *v2alpha1.DatadogAgentSpec, ddaStatus *v2alpha1.DatadogAgentStatus) {
if ddaStatus.RemoteConfigConfiguration == nil ||
ddaStatus.RemoteConfigConfiguration.Features == nil ||
ddaStatus.RemoteConfigConfiguration.Features.OrchestratorExplorer == nil ||
ddaStatus.RemoteConfigConfiguration.Features.OrchestratorExplorer.CustomResources == nil {
return
}

if ddaSpec.Features == nil {
ddaSpec.Features = &v2alpha1.DatadogFeatures{}
}

if ddaSpec.Features.OrchestratorExplorer == nil {
ddaSpec.Features.OrchestratorExplorer = &v2alpha1.OrchestratorExplorerFeatureConfig{}
}

ddaSpec.Features.OrchestratorExplorer.CustomResources = append(ddaSpec.Features.OrchestratorExplorer.CustomResources, ddaStatus.RemoteConfigConfiguration.Features.OrchestratorExplorer.CustomResources...)
}

// ManageDependencies allows a feature to manage its dependencies.
// Feature's dependencies should be added in the store.
func (f *orchestratorExplorerFeature) ManageDependencies(managers feature.ResourceManagers, components feature.RequiredComponents) error {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,17 @@ func orchestratorExplorerClusterAgentWantFuncV2() *test.ComponentTest {
customConfig := v2alpha1.CustomConfig{
ConfigData: apiutils.NewStringPointer(customConfDataV2),
}
hash, err := comparison.GenerateMD5ForSpec(&customConfig)
trueValue := true
url := "https://foo.bar"
orchExp := v2alpha1.OrchestratorExplorerFeatureConfig{
Enabled: &trueValue,
Conf: &customConfig,
ScrubContainers: &trueValue,
CustomResources: []string{},
ExtraTags: []string{"a:z", "b:y", "c:x"},
DDUrl: &url,
}
hash, err := comparison.GenerateMD5ForSpec(&orchExp)
assert.NoError(t, err)
wantAnnotations := map[string]string{
fmt.Sprintf(apicommon.MD5ChecksumAnnotationKey, feature.OrchestratorExplorerIDType): hash,
Expand Down
140 changes: 140 additions & 0 deletions pkg/remoteconfig/orchestrator_k8s_crd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package remoteconfig

import (
"context"
"encoding/json"
"fmt"

apiequality "k8s.io/apimachinery/pkg/api/equality"
apierrors "k8s.io/apimachinery/pkg/api/errors"

"github.com/DataDog/datadog-agent/pkg/remoteconfig/state"
"github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1"
)

// CustomResourceDefinitionURLs defines model for CustomResourceDefinitionURLs.
type CustomResourceDefinitionURLs struct {
Crds *[]string `json:"crds,omitempty"`
}

func (r *RemoteConfigUpdater) crdConfigUpdateCallback(updates map[string]state.RawConfig, applyStatus func(string, state.ApplyStatus)) {
ctx := context.Background()

var configIDs []string
for id := range updates {
applyStatus(id, state.ApplyStatus{State: state.ApplyStateUnacknowledged, Error: ""})
configIDs = append(configIDs, id)
}

mergedUpdate, err := r.parseCRDReceivedUpdates(updates, applyStatus)
if err != nil {
r.logger.Error(err, "Failed to merge updates")
return
}

if err := r.getAndUpdateDatadogAgentWithRetry(ctx, mergedUpdate, r.crdUpdateInstanceStatus); err != nil {
r.logger.Error(err, "Failed to update status")
applyStatus(configIDs[len(configIDs)-1], state.ApplyStatus{State: state.ApplyStateError, Error: err.Error()})
return
}

// Acknowledge that configs were received
for _, id := range configIDs {
applyStatus(id, state.ApplyStatus{State: state.ApplyStateAcknowledged, Error: ""})
}

r.logger.Info("Successfully applied configuration")

}

func (r *RemoteConfigUpdater) parseCRDReceivedUpdates(updates map[string]state.RawConfig, applyStatus func(string, state.ApplyStatus)) (OrchestratorK8sCRDRemoteConfig, error) {
// Unmarshal configs and config order
crds := []string{}
for _, c := range updates {
if c.Metadata.Product == state.ProductOrchestratorK8sCRDs {
rcCRDs := CustomResourceDefinitionURLs{}
err := json.Unmarshal(c.Config, &rcCRDs)
if err != nil {
return OrchestratorK8sCRDRemoteConfig{}, err
}
if rcCRDs.Crds != nil {
crds = append(crds, *rcCRDs.Crds...)
}
}
}

if len(crds) == 0 {
r.logger.Info("No CRDs received")
return OrchestratorK8sCRDRemoteConfig{}, nil
}

// Merge configs
var finalConfig OrchestratorK8sCRDRemoteConfig

// Cleanup CRD duplicates and add to final config
crds = removeDuplicateStr(crds)

if finalConfig.CRDs == nil {
finalConfig.CRDs = &CustomResourceDefinitionURLs{}
}
finalConfig.CRDs.Crds = &crds

return finalConfig, nil
}

func (r *RemoteConfigUpdater) crdUpdateInstanceStatus(dda v2alpha1.DatadogAgent, config DatadogProductRemoteConfig) error {
cfg, ok := config.(OrchestratorK8sCRDRemoteConfig)
if !ok {
return fmt.Errorf("invalid config type: %T", config)
}

newddaStatus := dda.Status.DeepCopy()
if newddaStatus.RemoteConfigConfiguration == nil {
newddaStatus.RemoteConfigConfiguration = &v2alpha1.RemoteConfigConfiguration{}
}

if newddaStatus.RemoteConfigConfiguration.Features == nil {
newddaStatus.RemoteConfigConfiguration.Features = &v2alpha1.DatadogFeatures{}
}

if newddaStatus.RemoteConfigConfiguration.Features.OrchestratorExplorer == nil {
newddaStatus.RemoteConfigConfiguration.Features.OrchestratorExplorer = &v2alpha1.OrchestratorExplorerFeatureConfig{}
}

// Orchestrator Explorer
if cfg.CRDs != nil {
newddaStatus.RemoteConfigConfiguration.Features.OrchestratorExplorer.CustomResources = []string{}
// Overwrite custom resources by the new ones
if cfg.CRDs.Crds != nil {
newddaStatus.RemoteConfigConfiguration.Features.OrchestratorExplorer.CustomResources = *cfg.CRDs.Crds
}
newddaStatus.RemoteConfigConfiguration.Features.OrchestratorExplorer.CustomResources = removeDuplicateStr(newddaStatus.RemoteConfigConfiguration.Features.OrchestratorExplorer.CustomResources)
}

if !apiequality.Semantic.DeepEqual(&dda.Status, newddaStatus) {
ddaUpdate := dda.DeepCopy()
ddaUpdate.Status = *newddaStatus
if err := r.kubeClient.Status().Update(context.TODO(), ddaUpdate); err != nil {
if apierrors.IsConflict(err) {
r.logger.Info("unable to update DatadogAgent CRD status due to update conflict")
return nil
}
r.logger.Error(err, "unable to update DatadogAgent status")
return err
}
}

return nil
}

func removeDuplicateStr(s []string) []string {
keys := make(map[string]bool)
list := []string{}
for _, item := range s {
if _, value := keys[item]; !value {
keys[item] = true
list = append(list, item)
}
}
return list
}
Loading

0 comments on commit ae5b9e1

Please sign in to comment.