Skip to content

Commit

Permalink
[introspection] Fix override name combining (#1049)
Browse files Browse the repository at this point in the history
* Fix override name combining

* Add a test for the change

---------

Co-authored-by: Levan Machablishvili <[email protected]>
  • Loading branch information
khewonc and levan-m authored Jan 23, 2024
1 parent 586942a commit 19c1776
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 23 deletions.
11 changes: 11 additions & 0 deletions apis/datadoghq/v2alpha1/test/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -494,3 +494,14 @@ func (builder *DatadogAgentBuilder) WithCredentials(apiKey, appKey string) *Data
}
return builder
}

// Override

func (builder *DatadogAgentBuilder) WithComponentOverride(componentName v2alpha1.ComponentName, override v2alpha1.DatadogAgentComponentOverride) *DatadogAgentBuilder {
if builder.datadogAgent.Spec.Override == nil {
builder.datadogAgent.Spec.Override = map[v2alpha1.ComponentName]*v2alpha1.DatadogAgentComponentOverride{}
}

builder.datadogAgent.Spec.Override[componentName] = &v2alpha1.DatadogAgentComponentOverride{}
return builder
}
26 changes: 14 additions & 12 deletions controllers/datadogagent/controller_reconcile_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func (r *Reconciler) reconcileV2Agent(logger logr.Logger, requiredComponents fea

// If Override is defined for the node agent component, apply the override on the PodTemplateSpec, it will cascade to container.
componentOverride, overriden := dda.Spec.Override[datadoghqv2alpha1.NodeAgentComponentName]
componentOverrideCopy := componentOverride.DeepCopy()
if r.options.IntrospectionEnabled {
// Add provider-specific label
eds.Labels[apicommon.MD5AgentDeploymentProviderLabelKey] = provider
Expand All @@ -73,21 +74,21 @@ func (r *Reconciler) reconcileV2Agent(logger logr.Logger, requiredComponents fea
eds.Spec.Template.Spec.Affinity = combinedAffinity
if overriden {
agentNameWithProvider := kubernetes.GetAgentNameWithProvider(eds.Name, provider, componentOverride.Name)
componentOverride.Name = &agentNameWithProvider
componentOverrideCopy.Name = &agentNameWithProvider
} else {
overrideFromProvider := kubernetes.ComponentOverrideFromProvider(eds.Name, provider)
componentOverride = &overrideFromProvider
componentOverrideCopy = &overrideFromProvider
}
} else {
eds.Labels[apicommon.MD5AgentDeploymentProviderLabelKey] = kubernetes.LegacyProvider
}

if componentOverride != nil {
if apiutils.BoolValue(componentOverride.Disabled) {
if componentOverrideCopy != nil {
if apiutils.BoolValue(componentOverrideCopy.Disabled) {
disabledByOverride = true
}
override.PodTemplateSpec(logger, podManagers, componentOverride, datadoghqv2alpha1.NodeAgentComponentName, dda.Name)
override.ExtendedDaemonSet(eds, componentOverride)
override.PodTemplateSpec(logger, podManagers, componentOverrideCopy, datadoghqv2alpha1.NodeAgentComponentName, dda.Name)
override.ExtendedDaemonSet(eds, componentOverrideCopy)
}

if disabledByOverride {
Expand Down Expand Up @@ -129,6 +130,7 @@ func (r *Reconciler) reconcileV2Agent(logger logr.Logger, requiredComponents fea

// If Override is defined for the node agent component, apply the override on the PodTemplateSpec, it will cascade to container.
componentOverride, overriden := dda.Spec.Override[datadoghqv2alpha1.NodeAgentComponentName]
componentOverrideCopy := componentOverride.DeepCopy()
if r.options.IntrospectionEnabled {
// Add provider-specific label
daemonset.Labels[apicommon.MD5AgentDeploymentProviderLabelKey] = provider
Expand All @@ -138,21 +140,21 @@ func (r *Reconciler) reconcileV2Agent(logger logr.Logger, requiredComponents fea
daemonset.Spec.Template.Spec.Affinity = combinedAffinity
if overriden {
agentNameWithProvider := kubernetes.GetAgentNameWithProvider(daemonset.Name, provider, componentOverride.Name)
componentOverride.Name = &agentNameWithProvider
componentOverrideCopy.Name = &agentNameWithProvider
} else {
overrideFromProvider := kubernetes.ComponentOverrideFromProvider(daemonset.Name, provider)
componentOverride = &overrideFromProvider
componentOverrideCopy = &overrideFromProvider
}
} else {
daemonset.Labels[apicommon.MD5AgentDeploymentProviderLabelKey] = kubernetes.LegacyProvider
}

if componentOverride != nil {
if apiutils.BoolValue(componentOverride.Disabled) {
if componentOverrideCopy != nil {
if apiutils.BoolValue(componentOverrideCopy.Disabled) {
disabledByOverride = true
}
override.PodTemplateSpec(logger, podManagers, componentOverride, datadoghqv2alpha1.NodeAgentComponentName, dda.Name)
override.DaemonSet(daemonset, componentOverride)
override.PodTemplateSpec(logger, podManagers, componentOverrideCopy, datadoghqv2alpha1.NodeAgentComponentName, dda.Name)
override.DaemonSet(daemonset, componentOverrideCopy)
}

if disabledByOverride {
Expand Down
158 changes: 147 additions & 11 deletions controllers/datadogagent/controller_v2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import (
"testing"
"time"

apicommon "github.com/DataDog/datadog-operator/apis/datadoghq/common"
apicommonv1 "github.com/DataDog/datadog-operator/apis/datadoghq/common/v1"
"github.com/DataDog/datadog-operator/apis/datadoghq/v2alpha1"
v2alpha1test "github.com/DataDog/datadog-operator/apis/datadoghq/v2alpha1/test"
testutils "github.com/DataDog/datadog-operator/controllers/datadogagent/testutils"
assert "github.com/stretchr/testify/require"
Expand All @@ -24,6 +26,7 @@ import (
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"

"k8s.io/apimachinery/pkg/runtime"
Expand All @@ -36,6 +39,17 @@ import (
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

type fields struct {
client client.Client
scheme *runtime.Scheme
platformInfo kubernetes.PlatformInfo
recorder record.EventRecorder
}
type args struct {
request reconcile.Request
loadFunc func(c client.Client)
}

func TestReconcileDatadogAgentV2_Reconcile(t *testing.T) {
const resourcesName = "foo"
const resourcesNamespace = "bar"
Expand All @@ -52,17 +66,6 @@ func TestReconcileDatadogAgentV2_Reconcile(t *testing.T) {

defaultRequeueDuration := 15 * time.Second

type fields struct {
client client.Client
scheme *runtime.Scheme
platformInfo kubernetes.PlatformInfo
recorder record.EventRecorder
}
type args struct {
request reconcile.Request
loadFunc func(c client.Client)
}

tests := []struct {
name string
fields fields
Expand Down Expand Up @@ -375,6 +378,123 @@ func TestReconcileDatadogAgentV2_Reconcile(t *testing.T) {
}
}

func Test_Introspection(t *testing.T) {
const resourcesName = "foo"
const resourcesNamespace = "bar"
const dsName = "foo-agent"

eventBroadcaster := record.NewBroadcaster()
recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: "TestReconcileDatadogAgent_Reconcile"})
forwarders := dummyManager{}

logf.SetLogger(zap.New(zap.UseDevMode(true)))

// Register operator types with the runtime scheme.
s := testutils.TestScheme(true)

defaultRequeueDuration := 15 * time.Second

tests := []struct {
name string
fields fields
args args
want reconcile.Result
wantErr bool
wantFunc func(t *testing.T, c client.Client) error
}{
{
name: "[introspection] Daemonset names with affinity override",
fields: fields{
client: fake.NewFakeClient(),
scheme: s,
recorder: recorder,
},
args: args{
request: newRequest(resourcesNamespace, resourcesName),
loadFunc: func(c client.Client) {
dda := v2alpha1test.NewInitializedDatadogAgentBuilder(resourcesNamespace, resourcesName).
WithComponentOverride(v2alpha1.NodeAgentComponentName, v2alpha1.DatadogAgentComponentOverride{
Affinity: &corev1.Affinity{
PodAntiAffinity: &corev1.PodAntiAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: []corev1.PodAffinityTerm{
{
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"foo": "bar",
},
},
TopologyKey: "baz",
},
},
},
},
}).
Build()
_ = c.Create(context.TODO(), dda)
},
},
want: reconcile.Result{RequeueAfter: defaultRequeueDuration},
wantErr: false,
wantFunc: func(t *testing.T, c client.Client) error {
expectedDaemonsets := []string{
string("foo-agent-provider1"),
string("foo-agent-provider2"),
string("foo-agent-provider3"),
}

return verifyDaemonsetNames(t, c, resourcesNamespace, dsName, expectedDaemonsets)
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Reconciler{
client: tt.fields.client,
scheme: tt.fields.scheme,
platformInfo: tt.fields.platformInfo,
recorder: recorder,
log: logf.Log.WithName(tt.name),
forwarders: forwarders,
options: ReconcilerOptions{
ExtendedDaemonsetOptions: componentagent.ExtendedDaemonsetOptions{
Enabled: false,
},
SupportCilium: false,
V2Enabled: true,
IntrospectionEnabled: true,
},
}

p := kubernetes.NewProviderStore(logf.Log.WithName("test_generateNodeAffinity"))
r.providerStore = &p
existingProviders := map[string]struct{}{
"provider1": {},
"provider2": {},
"provider3": {},
}
r.providerStore.Reset(existingProviders)

if tt.args.loadFunc != nil {
tt.args.loadFunc(r.client)
}
got, err := r.Reconcile(context.TODO(), tt.args.request)
if tt.wantErr {
assert.Error(t, err, "ReconcileDatadogAgent.Reconcile() expected an error")
} else {
assert.NoError(t, err, "ReconcileDatadogAgent.Reconcile() unexpected error: %v", err)
}

assert.Equal(t, tt.want, got, "ReconcileDatadogAgent.Reconcile() unexpected result")

if tt.wantFunc != nil {
err := tt.wantFunc(t, r.client)
assert.NoError(t, err, "ReconcileDatadogAgent.Reconcile() wantFunc validation error: %v", err)
}
})
}
}

func verifyDaemonsetContainers(c client.Client, resourcesNamespace, dsName string, expectedContainers []string) error {
ds := &appsv1.DaemonSet{}
if err := c.Get(context.TODO(), types.NamespacedName{Namespace: resourcesNamespace, Name: dsName}, ds); err != nil {
Expand All @@ -393,3 +513,19 @@ func verifyDaemonsetContainers(c client.Client, resourcesNamespace, dsName strin
return fmt.Errorf("Container don't match, expected %s, actual %s", expectedContainers, dsContainers)
}
}

func verifyDaemonsetNames(t *testing.T, c client.Client, resourcesNamespace, dsName string, expectedDSNames []string) error {
daemonSetList := appsv1.DaemonSetList{}
if err := c.List(context.TODO(), &daemonSetList, client.HasLabels{apicommon.MD5AgentDeploymentProviderLabelKey}); err != nil {
return err
}

actualDSNames := []string{}
for _, ds := range daemonSetList.Items {
actualDSNames = append(actualDSNames, ds.Name)
}
sort.Strings(actualDSNames)
sort.Strings(expectedDSNames)
assert.Equal(t, expectedDSNames, actualDSNames)
return nil
}

0 comments on commit 19c1776

Please sign in to comment.