Skip to content

Commit

Permalink
pkg/clusteragent/admission: add unit tests (#15044)
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmed-mez authored and val06 committed Jan 16, 2023
1 parent a6f3da0 commit 6dbb17f
Show file tree
Hide file tree
Showing 8 changed files with 329 additions and 14 deletions.
12 changes: 12 additions & 0 deletions pkg/clusteragent/admission/common/lib_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ type TracingHeaderTagEntry struct {
// ToEnvs converts the config fields into environment variables
func (lc LibConfig) ToEnvs() []corev1.EnvVar {
var envs []corev1.EnvVar
if lc.ServiceName != nil {
envs = append(envs, corev1.EnvVar{
Name: "DD_SERVICE",
Value: *lc.ServiceName,
})
}
if lc.Env != nil {
envs = append(envs, corev1.EnvVar{
Name: "DD_ENV",
Value: *lc.Env,
})
}
if val, defined := checkFormatVal(lc.Tracing); defined {
envs = append(envs, corev1.EnvVar{
Name: "DD_TRACE_ENABLED",
Expand Down
154 changes: 154 additions & 0 deletions pkg/clusteragent/admission/common/lib_config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.

//go:build kubeapiserver
// +build kubeapiserver

package common

import (
"testing"

"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
)

func TestLibConfig_ToEnvs(t *testing.T) {
type fields struct {
ServiceName *string
Env *string
Tracing *bool
LogInjection *bool
HealthMetrics *bool
RuntimeMetrics *bool
TracingSamplingRate *float64
TracingRateLimit *int
TracingTags []string

/*
TracingServiceMapping []TracingServiceMapEntry
TracingAgentTimeout *int
TracingHeaderTags []TracingHeaderTagEntry
TracingPartialFlushMinSpans *int
TracingDebug *bool
TracingLogLevel *string
TracingMethods []string
TracingPropagationStyleInject []string
TracingPropagationStyleExtract []string
*/
}
tests := []struct {
name string
fields fields
want []corev1.EnvVar
}{
{
name: "all",
fields: fields{
ServiceName: ptr("svc"),
Env: ptr("dev"),
Tracing: ptr(true),
LogInjection: ptr(true),
HealthMetrics: ptr(true),
RuntimeMetrics: ptr(true),
TracingSamplingRate: ptr(0.5),
TracingRateLimit: ptr(50),
TracingTags: []string{"k1:v1", "k2:v2"},
},
want: []corev1.EnvVar{
{
Name: "DD_SERVICE",
Value: "svc",
},
{
Name: "DD_ENV",
Value: "dev",
},
{
Name: "DD_TRACE_ENABLED",
Value: "true",
},
{
Name: "DD_LOGS_INJECTION",
Value: "true",
},
{
Name: "DD_TRACE_HEALTH_METRICS_ENABLED",
Value: "true",
},
{
Name: "DD_RUNTIME_METRICS_ENABLED",
Value: "true",
},
{
Name: "DD_TRACE_SAMPLE_RATE",
Value: "0.50",
},
{
Name: "DD_TRACE_RATE_LIMIT",
Value: "50",
},
{
Name: "DD_TAGS",
Value: "k1:v1,k2:v2",
},
},
},
{
name: "only service and env",
fields: fields{
ServiceName: ptr("svc"),
Env: ptr("dev"),
},
want: []corev1.EnvVar{
{
Name: "DD_SERVICE",
Value: "svc",
},
{
Name: "DD_ENV",
Value: "dev",
},
},
},
{
name: "empty",
fields: fields{},
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
lc := LibConfig{
ServiceName: tt.fields.ServiceName,
Env: tt.fields.Env,
Tracing: tt.fields.Tracing,
LogInjection: tt.fields.LogInjection,
HealthMetrics: tt.fields.HealthMetrics,
RuntimeMetrics: tt.fields.RuntimeMetrics,
TracingSamplingRate: tt.fields.TracingSamplingRate,
TracingRateLimit: tt.fields.TracingRateLimit,
TracingTags: tt.fields.TracingTags,

/*
TracingServiceMapping: tt.fields.TracingServiceMapping,
TracingAgentTimeout: tt.fields.TracingAgentTimeout,
TracingHeaderTags: tt.fields.TracingHeaderTags,
TracingPartialFlushMinSpans: tt.fields.TracingPartialFlushMinSpans,
TracingDebug: tt.fields.TracingDebug,
TracingLogLevel: tt.fields.TracingLogLevel,
TracingMethods: tt.fields.TracingMethods,
TracingPropagationStyleInject: tt.fields.TracingPropagationStyleInject,
TracingPropagationStyleExtract: tt.fields.TracingPropagationStyleExtract,
*/
}
require.EqualValues(t, tt.want, lc.ToEnvs())
})
}
}

func ptr[T int | bool | string | float64](val T) *T {
return &val
}
8 changes: 1 addition & 7 deletions pkg/clusteragent/admission/patch/file_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,17 @@ import (
type filePatchProvider struct {
file string
pollInterval time.Duration
isLeader func() bool
subscribers map[TargetObjKind]chan PatchRequest
lastSuccessfulRefresh time.Time
clusterName string
}

var _ patchProvider = &filePatchProvider{}

func newfileProvider(isLeaderFunc func() bool, clusterName string) *filePatchProvider {
func newfileProvider(clusterName string) *filePatchProvider {
return &filePatchProvider{
file: "/etc/datadog-agent/auto-instru.json",
pollInterval: 15 * time.Second,
isLeader: isLeaderFunc,
subscribers: make(map[TargetObjKind]chan PatchRequest),
clusterName: clusterName,
}
Expand Down Expand Up @@ -61,10 +59,6 @@ func (fpp *filePatchProvider) start(stopCh <-chan struct{}) {
}

func (fpp *filePatchProvider) refresh() error {
if !fpp.isLeader() {
log.Debug("Not leader, skipping")
return nil
}
requests, err := fpp.poll()
if err != nil {
return err
Expand Down
93 changes: 93 additions & 0 deletions pkg/clusteragent/admission/patch/patch_request_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016-present Datadog, Inc.

//go:build kubeapiserver
// +build kubeapiserver

package patch

import (
"testing"

"github.com/DataDog/datadog-agent/pkg/clusteragent/admission/common"
"github.com/stretchr/testify/require"
)

func TestPatchRequestValidate(t *testing.T) {
tests := []struct {
name string
LibConfig common.LibConfig
K8sTarget K8sTarget
clusterName string
valid bool
}{
{
name: "valid",
LibConfig: common.LibConfig{Language: "lang", Version: "latest"},
K8sTarget: K8sTarget{Cluster: "cluster", Kind: "deployment", Name: "name", Namespace: "ns"},
clusterName: "cluster",
valid: true,
},
{
name: "empty version",
LibConfig: common.LibConfig{Language: "lang"},
K8sTarget: K8sTarget{Cluster: "cluster", Kind: "deployment", Name: "name", Namespace: "ns"},
clusterName: "cluster",
valid: false,
},
{
name: "empty language",
LibConfig: common.LibConfig{Version: "latest"},
K8sTarget: K8sTarget{Cluster: "cluster", Kind: "deployment", Name: "name", Namespace: "ns"},
clusterName: "cluster",
valid: false,
},
{
name: "empty cluster",
LibConfig: common.LibConfig{Language: "lang", Version: "latest"},
K8sTarget: K8sTarget{Kind: "deployment", Name: "name", Namespace: "ns"},
clusterName: "cluster",
valid: false,
},
{
name: "wrong cluster",
LibConfig: common.LibConfig{Language: "lang", Version: "latest"},
K8sTarget: K8sTarget{Cluster: "wrong-cluster", Kind: "deployment", Name: "name", Namespace: "ns"},
clusterName: "cluster",
valid: false,
},
{
name: "empty kind",
LibConfig: common.LibConfig{Language: "lang", Version: "latest"},
K8sTarget: K8sTarget{Cluster: "cluster", Name: "name", Namespace: "ns"},
clusterName: "cluster",
valid: false,
},
{
name: "empty name",
LibConfig: common.LibConfig{Language: "lang", Version: "latest"},
K8sTarget: K8sTarget{Cluster: "cluster", Kind: "deployment", Namespace: "ns"},
clusterName: "cluster",
valid: false,
},
{
name: "empty namesapce",
LibConfig: common.LibConfig{Language: "lang", Version: "latest"},
K8sTarget: K8sTarget{Cluster: "cluster", Kind: "deployment", Name: "name"},
clusterName: "cluster",
valid: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pr := PatchRequest{
LibConfig: tt.LibConfig,
K8sTarget: tt.K8sTarget,
}
err := pr.Validate(tt.clusterName)
require.True(t, (err == nil) == tt.valid)
})
}
}
6 changes: 3 additions & 3 deletions pkg/clusteragent/admission/patch/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ type patchProvider interface {
subscribe(kind TargetObjKind) chan PatchRequest
}

func newPatchProvider(rcClient *remote.Client, isLeaderFunc func() bool, clusterName string) (patchProvider, error) {
func newPatchProvider(rcClient *remote.Client, clusterName string) (patchProvider, error) {
if config.Datadog.GetBool("remote_configuration.enabled") {
return newRemoteConfigProvider(rcClient, isLeaderFunc, clusterName)
return newRemoteConfigProvider(rcClient, clusterName)
}
if config.Datadog.GetBool("admission_controller.auto_instrumentation.patcher.fallback_to_file_provider") {
// Use the file config provider for e2e testing only (it replaces RC as a source of configs)
return newfileProvider(isLeaderFunc, clusterName), nil
return newfileProvider(clusterName), nil
}
return nil, errors.New("remote config is disabled")
}
4 changes: 1 addition & 3 deletions pkg/clusteragent/admission/patch/rc_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,18 @@ import (
// remoteConfigProvider consumes tracing configs from RC and delivers them to the patcher
type remoteConfigProvider struct {
client *remote.Client
isLeader func() bool
subscribers map[TargetObjKind]chan PatchRequest
clusterName string
}

var _ patchProvider = &remoteConfigProvider{}

func newRemoteConfigProvider(client *remote.Client, isLeaderFunc func() bool, clusterName string) (*remoteConfigProvider, error) {
func newRemoteConfigProvider(client *remote.Client, clusterName string) (*remoteConfigProvider, error) {
if client == nil {
return nil, errors.New("remote config client not initialized")
}
return &remoteConfigProvider{
client: client,
isLeader: isLeaderFunc,
subscribers: make(map[TargetObjKind]chan PatchRequest),
clusterName: clusterName,
}, nil
Expand Down
Loading

0 comments on commit 6dbb17f

Please sign in to comment.