Skip to content

Commit

Permalink
[Backport 7.64.x] fix(autoinstrumentation): enable language-detection…
Browse files Browse the repository at this point in the history
… when pinned versions are defaults (#34506)

Co-authored-by: stanistan <[email protected]>
  • Loading branch information
agent-platform-auto-pr[bot] and stanistan authored Feb 27, 2025
1 parent 1be916c commit eb84b0f
Show file tree
Hide file tree
Showing 6 changed files with 261 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -452,46 +452,25 @@ func TestInjectAutoInstruConfigV2(t *testing.T) {
}

func TestExtractLibInfo(t *testing.T) {
defaultLibImageVersions := map[string]string{
"java": "registry/dd-lib-java-init:v1",
"js": "registry/dd-lib-js-init:v5",
"python": "registry/dd-lib-python-init:v2",
"dotnet": "registry/dd-lib-dotnet-init:v3",
"ruby": "registry/dd-lib-ruby-init:v2",
}

// TODO: Add new entry when a new language is supported
allLatestDefaultLibs := []libInfo{
{
lang: "java",
image: defaultLibImageVersions["java"],
},
{
lang: "js",
image: defaultLibImageVersions["js"],
},
{
lang: "python",
image: defaultLibImageVersions["python"],
},
{
lang: "dotnet",
image: defaultLibImageVersions["dotnet"],
},
{
lang: "ruby",
image: defaultLibImageVersions["ruby"],
},
defaultLibInfo(java),
defaultLibInfo(js),
defaultLibInfo(python),
defaultLibInfo(dotnet),
defaultLibInfo(ruby),
}

var mockConfig model.Config
tests := []struct {
name string
pod *corev1.Pod
containerRegistry string
expectedLibsToInject []libInfo
expectedPodEligible *bool
setupConfig func()
name string
pod *corev1.Pod
deployments []common.MockDeployment
assertExtractedLibInfo func(*testing.T, extractedPodLibInfo)
containerRegistry string
expectedLibsToInject []libInfo
expectedPodEligible *bool
setupConfig func()
}{
{
name: "java",
Expand Down Expand Up @@ -785,10 +764,7 @@ func TestExtractLibInfo(t *testing.T) {
pod: common.FakePodWithNamespaceAndLabel("ns", "", ""),
containerRegistry: "registry",
expectedLibsToInject: []libInfo{
{
lang: "java",
image: defaultLibImageVersions["java"],
},
defaultLibInfo(java),
},
setupConfig: func() {
mockConfig.SetWithoutSource("apm_config.instrumentation.enabled", true)
Expand Down Expand Up @@ -830,6 +806,74 @@ func TestExtractLibInfo(t *testing.T) {
mockConfig.SetWithoutSource("admission_controller.mutate_unlabelled", true)
},
},
{
name: "pod with lang-detection deployment and default libs",
pod: common.FakePodSpec{
ParentKind: "replicaset",
ParentName: "deployment-123",
}.Create(),
deployments: []common.MockDeployment{
{
ContainerName: "pod",
DeploymentName: "deployment",
Namespace: "ns",
Languages: languageSetOf("python"),
},
},
containerRegistry: "registry",
assertExtractedLibInfo: func(t *testing.T, i extractedPodLibInfo) {
t.Helper()
require.Equal(t, &libInfoLanguageDetection{
libs: []libInfo{
python.defaultLibInfo("registry", "pod"),
},
injectionEnabled: true,
}, i.languageDetection)
},
expectedLibsToInject: []libInfo{
python.defaultLibInfo("registry", "pod"),
},
setupConfig: func() {
mockConfig.SetWithoutSource("apm_config.instrumentation.enabled", true)
mockConfig.SetWithoutSource("apm_config.instrumentation.lib_versions", defaultLibraries)
mockConfig.SetWithoutSource("language_detection.enabled", true)
mockConfig.SetWithoutSource("language_detection.reporting.enabled", true)
mockConfig.SetWithoutSource("admission_controller.auto_instrumentation.inject_auto_detected_libraries", true)
},
},
{
name: "pod with lang-detection deployment and libs set",
pod: common.FakePodSpec{
ParentKind: "replicaset",
ParentName: "deployment-123",
}.Create(),
deployments: []common.MockDeployment{
{
ContainerName: "pod",
DeploymentName: "deployment",
Namespace: "ns",
Languages: languageSetOf("python"),
},
},
containerRegistry: "registry",
assertExtractedLibInfo: func(t *testing.T, i extractedPodLibInfo) {
t.Helper()
require.Equal(t, &libInfoLanguageDetection{
libs: []libInfo{python.defaultLibInfo("registry", "pod")},
injectionEnabled: true,
}, i.languageDetection)
},
expectedLibsToInject: []libInfo{
java.defaultLibInfo("registry", ""),
},
setupConfig: func() {
mockConfig.SetWithoutSource("apm_config.instrumentation.enabled", true)
mockConfig.SetWithoutSource("apm_config.instrumentation.lib_versions", defaultLibrariesFor("java"))
mockConfig.SetWithoutSource("language_detection.enabled", true)
mockConfig.SetWithoutSource("language_detection.reporting.enabled", true)
mockConfig.SetWithoutSource("admission_controller.auto_instrumentation.inject_auto_detected_libraries", true)
},
},
{
name: "php (opt-in)",
pod: common.FakePodWithAnnotation("admission.datadoghq.com/php-lib.version", "v1"),
Expand All @@ -856,10 +900,7 @@ func TestExtractLibInfo(t *testing.T) {
mockConfig.SetWithoutSource(k, v)
}

wmeta := fxutil.Test[workloadmeta.Component](t,
core.MockBundle(),
workloadmetafxmock.MockModule(workloadmeta.NewParams()),
)
wmeta := common.FakeStoreWithDeployment(t, tt.deployments)
mockConfig = configmock.New(t)
for k, v := range overrides {
mockConfig.SetWithoutSource(k, v)
Expand All @@ -879,6 +920,9 @@ func TestExtractLibInfo(t *testing.T) {
}

extracted := mutator.extractLibInfo(tt.pod)
if tt.assertExtractedLibInfo != nil {
tt.assertExtractedLibInfo(t, extracted)
}
require.ElementsMatch(t, tt.expectedLibsToInject, extracted.libs)
})
}
Expand Down
31 changes: 24 additions & 7 deletions pkg/clusteragent/admission/mutate/autoinstrumentation/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,27 +346,44 @@ func getOptionalStringValue(datadogConfig config.Component, key string) *string
return value
}

type pinnedLibraries struct {
// libs are the pinned libraries themselves.
libs []libInfo
// areSetToDefaults is true when the libs coming from the configuration
// are equivalent to what would be set if there was no configuration at all.
areSetToDefaults bool
}

// getPinnedLibraries returns tracing libraries to inject as configured by apm_config.instrumentation.lib_versions
// given a registry.
func getPinnedLibraries(libVersions map[string]string, registry string) []libInfo {
var res []libInfo
func getPinnedLibraries(libVersions map[string]string, registry string, checkDefaults bool) pinnedLibraries {
libs := []libInfo{}
allDefaults := true

for lang, version := range libVersions {
l := language(lang)
if !l.isSupported() {
log.Warnf("APM Instrumentation detected configuration for unsupported language: %s. Tracing library for %s will not be injected", lang, lang)
continue
}

log.Infof("Library version %s is specified for language %s", version, lang)
res = append(res, l.libInfo("", l.libImageName(registry, version)))
info := l.libInfo("", l.libImageName(registry, version))
log.Infof("Library version %s is specified for language %s, going to use %s", version, lang, info.image)
libs = append(libs, info)

if info.image != l.libImageName(registry, l.defaultLibVersion()) {
allDefaults = false
}
}

return res
return pinnedLibraries{
libs: libs,
areSetToDefaults: checkDefaults && allDefaults && len(libs) == len(defaultSupportedLanguagesMap()),
}
}

func initDefaultResources(datadogConfig config.Component) (initResourceRequirementConfiguration, error) {

var conf = initResourceRequirementConfiguration{}
conf := initResourceRequirementConfiguration{}

if datadogConfig.IsSet("admission_controller.auto_instrumentation.init_resources.cpu") {
quantity, err := resource.ParseQuantity(datadogConfig.GetString("admission_controller.auto_instrumentation.init_resources.cpu"))
Expand Down
131 changes: 131 additions & 0 deletions pkg/clusteragent/admission/mutate/autoinstrumentation/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,3 +259,134 @@ func TestTargetEnvVar(t *testing.T) {
})
}
}

func TestGetPinnedLibraries(t *testing.T) {
tests := []struct {
name string
libVersions map[string]string
checkDefaults bool
expected pinnedLibraries
}{
{
name: "no pinned library versions",
expected: pinnedLibraries{areSetToDefaults: false},
},
{
name: "no pinned library versions, checkDefaults",
checkDefaults: true,
expected: pinnedLibraries{areSetToDefaults: false},
},
{
name: "default libs, not checking defaults always false",
libVersions: defaultLibraries,
expected: pinnedLibraries{
libs: []libInfo{
defaultLibInfo(java),
defaultLibInfo(python),
defaultLibInfo(js),
defaultLibInfo(dotnet),
defaultLibInfo(ruby),
},
},
},
{
name: "default libs",
libVersions: defaultLibraries,
checkDefaults: true,
expected: pinnedLibraries{
libs: []libInfo{
defaultLibInfo(java),
defaultLibInfo(python),
defaultLibInfo(js),
defaultLibInfo(dotnet),
defaultLibInfo(ruby),
},
areSetToDefaults: true,
},
},
{
name: "default libs, one missing",
libVersions: defaultLibrariesFor("java", "python", "js", "dotnet"),
checkDefaults: true,
expected: pinnedLibraries{
libs: []libInfo{
defaultLibInfo(java),
defaultLibInfo(python),
defaultLibInfo(js),
defaultLibInfo(dotnet),
},
},
},
{
name: "explicitly default libs",
libVersions: map[string]string{
"java": "default",
"python": "default",
"js": "default",
"dotnet": "default",
"ruby": "default",
},
checkDefaults: true,
expected: pinnedLibraries{
libs: []libInfo{
defaultLibInfo(java),
defaultLibInfo(python),
defaultLibInfo(js),
defaultLibInfo(dotnet),
defaultLibInfo(ruby),
},
areSetToDefaults: true,
},
},
{
name: "default libs (major versions)",
libVersions: map[string]string{
"java": "v1",
"python": "v2",
"js": "v5",
"dotnet": "v3",
"ruby": "v2",
},
checkDefaults: true,
expected: pinnedLibraries{
libs: []libInfo{
defaultLibInfo(java),
defaultLibInfo(python),
defaultLibInfo(js),
defaultLibInfo(dotnet),
defaultLibInfo(ruby),
},
areSetToDefaults: true,
},
},
{
name: "default libs (major versions mismatch)",
libVersions: map[string]string{
"java": "v1",
"python": "v2",
"js": "v3",
"dotnet": "v3",
"ruby": "v2",
},
checkDefaults: true,
expected: pinnedLibraries{
libs: []libInfo{
defaultLibInfo(java),
defaultLibInfo(python),
js.libInfo("", "registry/dd-lib-js-init:v3"),
defaultLibInfo(dotnet),
defaultLibInfo(ruby),
},
areSetToDefaults: false,
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pinned := getPinnedLibraries(tt.libVersions, "registry", tt.checkDefaults)
require.ElementsMatch(t, tt.expected.libs, pinned.libs, "libs match")
require.Equal(t, tt.expected.areSetToDefaults, pinned.areSetToDefaults, "areSetToDefaults match")
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@ var supportedLanguages = []language{
php, // PHP only works with injection v2, no environment variables are set in any case
}

func defaultSupportedLanguagesMap() map[language]bool {
m := map[language]bool{}
for _, l := range supportedLanguages {
if l.isEnabledByDefault() {
m[l] = true
}
}

return m
}

func (l language) isSupported() bool {
return slices.Contains(supportedLanguages, l)
}
Expand Down
Loading

0 comments on commit eb84b0f

Please sign in to comment.