Skip to content

Commit 501fb37

Browse files
authored
[AGENTONB-2555][DatadogAgentInternal] Fix DDAI metric forwaders errors (#2214)
* Ensure we determine type before fallback to last-applied-config annotation * Initialize error to nil in metricsforwader * update tests based on new behaviour * refactor in single if statement + remove unknown fallback + use unstructured to properly test annotation fallback
1 parent 920f95a commit 501fb37

5 files changed

Lines changed: 43 additions & 30 deletions

File tree

internal/controller/datadogagent/ddai.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,16 @@ func (r *Reconciler) generateDDAIFromDDA(dda *v2alpha1.DatadogAgent) (*v1alpha1.
4646
}
4747

4848
func generateObjMetaFromDDA(dda *v2alpha1.DatadogAgent, ddai *v1alpha1.DatadogAgentInternal, scheme *runtime.Scheme) error {
49+
// Copy ddaiAnnotations but strip kubectl last-applied-configuration to avoid confusing kind detection for metrics forwarder
50+
// Moreover, the applied configuration is the one for DDA, not DDAI, so it doesn't make sense.
51+
ddaiAnnotations := maps.Clone(dda.Annotations)
52+
delete(ddaiAnnotations, "kubectl.kubernetes.io/last-applied-configuration")
53+
4954
ddai.ObjectMeta = metav1.ObjectMeta{
5055
Name: dda.Name,
5156
Namespace: dda.Namespace,
5257
Labels: getDDAILabels(dda),
53-
Annotations: dda.Annotations,
58+
Annotations: ddaiAnnotations,
5459
}
5560
if err := object.SetOwnerReference(dda, ddai, scheme); err != nil {
5661
return err

pkg/controller/utils/datadog/common.go

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"encoding/json"
1010
"fmt"
1111

12+
v1alpha1 "github.com/DataDog/datadog-operator/api/datadoghq/v1alpha1"
13+
v2alpha1 "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1"
1214
"k8s.io/apimachinery/pkg/types"
1315
"sigs.k8s.io/controller-runtime/pkg/client"
1416
logf "sigs.k8s.io/controller-runtime/pkg/log"
@@ -21,27 +23,32 @@ func getObjKind(obj client.Object) string {
2123
// First try to get the kind from GVK
2224
objKind := obj.GetObjectKind().GroupVersionKind().Kind
2325

24-
// There is a known bug where the object frequently has empty GVK info. This is a workaround to get object Kind if that happens.
26+
// There is a known bug where the object frequently has empty GVK info.
2527
// Ref: https://github.com/kubernetes-sigs/controller-runtime/issues/1735
28+
// If GVK is empty, prefer inspecting the concrete type to avoid annotation-induced misclassification
2629
if objKind == "" {
27-
// Try to get it from the last-applied-configuration annotation
28-
if annotations := obj.GetAnnotations(); annotations != nil {
29-
if lastConfig, exists := annotations["kubectl.kubernetes.io/last-applied-configuration"]; exists {
30-
var config map[string]any
31-
if err := json.Unmarshal([]byte(lastConfig), &config); err == nil {
32-
if kind, ok := config["kind"].(string); ok {
33-
objKind = kind
30+
switch obj.(type) {
31+
case *v2alpha1.DatadogAgent:
32+
objKind = datadogAgentKind
33+
case *v1alpha1.DatadogAgentInternal:
34+
objKind = datadogAgentInternalKind
35+
case *v1alpha1.DatadogMonitor:
36+
objKind = datadogMonitorKind
37+
default:
38+
// As a fallback, get it from the last-applied-configuration annotation.
39+
if annotations := obj.GetAnnotations(); annotations != nil {
40+
if lastConfig, exists := annotations["kubectl.kubernetes.io/last-applied-configuration"]; exists {
41+
var config map[string]any
42+
if err := json.Unmarshal([]byte(lastConfig), &config); err == nil {
43+
if kind, ok := config["kind"].(string); ok {
44+
objKind = kind
45+
}
3446
}
3547
}
3648
}
3749
}
3850
}
3951

40-
// Last fallback after GVK is empty and last-applied-configuration annotation is not present
41-
if objKind == "" {
42-
objKind = "Unknown"
43-
}
44-
4552
return objKind
4653
}
4754

pkg/controller/utils/datadog/common_test.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1"
1313
"github.com/DataDog/datadog-operator/pkg/kubernetes/rbac"
1414
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1516
"k8s.io/apimachinery/pkg/runtime/schema"
1617
"sigs.k8s.io/controller-runtime/pkg/client"
1718
)
@@ -66,17 +67,15 @@ func TestGetObjKind(t *testing.T) {
6667
expected: datadogAgentInternalKind,
6768
},
6869
{
69-
name: "DatadogAgent with last-applied-configuration annotation - no GVK set",
70+
name: "Generic object with last-applied-configuration annotation - no GVK set",
7071
obj: func() client.Object {
71-
return &v2alpha1.DatadogAgent{
72-
ObjectMeta: metav1.ObjectMeta{
73-
Name: testAgentName,
74-
Namespace: fooNamespace,
75-
Annotations: map[string]string{
76-
"kubectl.kubernetes.io/last-applied-configuration": `{"kind":"` + datadogAgentKind + `"}`,
77-
},
78-
},
79-
}
72+
obj := &unstructured.Unstructured{}
73+
obj.SetName(testAgentName)
74+
obj.SetNamespace(fooNamespace)
75+
obj.SetAnnotations(map[string]string{
76+
"kubectl.kubernetes.io/last-applied-configuration": `{"kind":"` + datadogAgentKind + `"}`,
77+
})
78+
return obj
8079
},
8180
expected: datadogAgentKind,
8281
},

pkg/controller/utils/datadog/metrics_forwarder.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"fmt"
1212
"hash/fnv"
1313
"os"
14-
"reflect"
1514
"strings"
1615
"sync"
1716
"time"
@@ -389,6 +388,11 @@ func (mf *metricsForwarder) connectToDatadogAPI() (bool, error) {
389388
mf.logger.Error(err, "cannot retrieve Datadog metrics forwarder to send deployment metrics, will retry later...")
390389
return false, nil
391390
}
391+
// Initialize lastReconcileErr to nil after successful setup so the first
392+
// reconcile metric reports success instead of an initialization error.
393+
if errors.Is(mf.getLastReconcileError(), errInitValue) {
394+
mf.setLastReconcileError(nil)
395+
}
392396
return true, nil
393397
}
394398

@@ -452,7 +456,7 @@ func (mf *metricsForwarder) forwardMetrics() error {
452456
// processReconcileError updates lastReconcileErr
453457
// and sends reconcile metrics based on the reconcile errors
454458
func (mf *metricsForwarder) processReconcileError(reconcileErr error) error {
455-
if reflect.DeepEqual(mf.getLastReconcileError(), reconcileErr) {
459+
if errors.Is(reconcileErr, mf.getLastReconcileError()) {
456460
// Error didn't change
457461
return nil
458462
}

pkg/controller/utils/datadog/metrics_forwarder_test.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -714,19 +714,17 @@ func Test_metricsForwarder_processReconcileError(t *testing.T) {
714714
},
715715
},
716716
{
717-
name: "last error not nil and not init value, new error equals last error => don't send metric",
717+
name: "last error not nil and not init value, new error equals last error => send unsuccess metric",
718718
loadFunc: func() (*metricsForwarder, *fakeMetricsForwarder) {
719719
f := &fakeMetricsForwarder{}
720+
f.On("delegatedSendReconcileMetric", ctx, 0.0, []string{"kube_namespace:foo", "resource_name:bar", "reconcile_err:Unauthorized", "cr_preferred_version:null"}).Once()
720721
mf.delegator = f
721722
mf.lastReconcileErr = apierrors.NewUnauthorized("Auth error")
722723
return mf, f
723724
},
724725
err: apierrors.NewUnauthorized("Auth error"),
725726
wantErr: false,
726727
wantFunc: func(f *fakeMetricsForwarder) error {
727-
if !f.AssertNumberOfCalls(t, "delegatedSendReconcileMetric", 0) {
728-
return errors.New("Wrong number of calls")
729-
}
730728
f.AssertExpectations(t)
731729
return nil
732730
},

0 commit comments

Comments
 (0)