From 2b36f0d6f9498e3c82185a4a18f0c855c4da4a57 Mon Sep 17 00:00:00 2001
From: Pavol Loffay
Date: Fri, 25 Oct 2024 19:07:23 +0200
Subject: [PATCH] Support configuring java runtime from configmap or secret
(env.valueFrom) (#3379)
Signed-off-by: Pavol Loffay
---
.chloggen/1814-java-configmap.yaml | 19 +++++++
config/manager/kustomization.yaml | 1 -
pkg/instrumentation/javaagent.go | 26 ++++------
pkg/instrumentation/javaagent_test.go | 49 +++++++++++++++----
pkg/instrumentation/sdk.go | 13 ++---
.../01-assert.yaml | 4 +-
.../02-assert.yaml | 2 +-
.../03-assert.yaml | 2 +-
.../instrumentation-java-tls/01-assert.yaml | 2 +-
.../instrumentation-java/01-assert.yaml | 7 ++-
.../instrumentation-java/01-install-app.yaml | 13 +++++
.../01-assert.yaml | 2 +-
12 files changed, 97 insertions(+), 43 deletions(-)
create mode 100755 .chloggen/1814-java-configmap.yaml
diff --git a/.chloggen/1814-java-configmap.yaml b/.chloggen/1814-java-configmap.yaml
new file mode 100755
index 0000000000..dbdddd5786
--- /dev/null
+++ b/.chloggen/1814-java-configmap.yaml
@@ -0,0 +1,19 @@
+# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
+change_type: enhancement
+
+# The name of the component, or a single word describing the area of concern, (e.g. collector, target allocator, auto-instrumentation, opamp, github action)
+component: auto-instrumentation
+
+# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
+note: Support configuring Java auto-instrumentation when runtime configuration is provided from configmap or secret.
+
+# One or more tracking issues related to the change
+issues: [1814]
+
+# (Optional) One or more lines of additional information to render under the primary note.
+# These lines will be padded with 2 spaces and then inserted directly into the document.
+# Use pipe (|) for multiline entries.
+subtext: |
+ This change allows users to configure JAVA_TOOL_OPTIONS in config map or secret.
+ The operator in this case set another JAVA_TOOL_OPTIONS that references the original value
+ e.g. `JAVA_TOOL_OPTIONS=$(JAVA_TOOL_OPTIONS) -javaagent:/otel-auto-instrumentation-java/javaagent.jar`.
diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml
index 372a75ae43..5c5f0b84cb 100644
--- a/config/manager/kustomization.yaml
+++ b/config/manager/kustomization.yaml
@@ -1,3 +1,2 @@
resources:
- manager.yaml
-
diff --git a/pkg/instrumentation/javaagent.go b/pkg/instrumentation/javaagent.go
index ef91d296d8..1dafcd9cd7 100644
--- a/pkg/instrumentation/javaagent.go
+++ b/pkg/instrumentation/javaagent.go
@@ -24,23 +24,17 @@ import (
const (
envJavaToolsOptions = "JAVA_TOOL_OPTIONS"
- javaAgent = " -javaagent:/otel-auto-instrumentation-java/javaagent.jar"
+ javaAgent = "-javaagent:/otel-auto-instrumentation-java/javaagent.jar"
javaInitContainerName = initContainerName + "-java"
javaVolumeName = volumeName + "-java"
javaInstrMountPath = "/otel-auto-instrumentation-java"
)
-func injectJavaagent(javaSpec v1alpha1.Java, pod corev1.Pod, index int) (corev1.Pod, error) {
+func injectJavaagent(javaSpec v1alpha1.Java, pod corev1.Pod, index int) corev1.Pod {
volume := instrVolume(javaSpec.VolumeClaimTemplate, javaVolumeName, javaSpec.VolumeSizeLimit)
-
// caller checks if there is at least one container.
container := &pod.Spec.Containers[index]
- err := validateContainerEnv(container.Env, envJavaToolsOptions)
- if err != nil {
- return pod, err
- }
-
// inject Java instrumentation spec env vars.
for _, env := range javaSpec.Env {
idx := getIndexOfEnv(container.Env, env.Name)
@@ -55,14 +49,14 @@ func injectJavaagent(javaSpec v1alpha1.Java, pod corev1.Pod, index int) (corev1.
}
idx := getIndexOfEnv(container.Env, envJavaToolsOptions)
- if idx == -1 {
- container.Env = append(container.Env, corev1.EnvVar{
- Name: envJavaToolsOptions,
- Value: javaJVMArgument,
- })
- } else {
- container.Env[idx].Value = container.Env[idx].Value + javaJVMArgument
+ if idx != -1 {
+ // https://kubernetes.io/docs/tasks/inject-data-application/define-interdependent-environment-variables/
+ javaJVMArgument = fmt.Sprintf("$(%s) %s", envJavaToolsOptions, javaJVMArgument)
}
+ container.Env = append(container.Env, corev1.EnvVar{
+ Name: envJavaToolsOptions,
+ Value: javaJVMArgument,
+ })
container.VolumeMounts = append(container.VolumeMounts, corev1.VolumeMount{
Name: volume.Name,
@@ -97,5 +91,5 @@ func injectJavaagent(javaSpec v1alpha1.Java, pod corev1.Pod, index int) (corev1.
}
}
- return pod, err
+ return pod
}
diff --git a/pkg/instrumentation/javaagent_test.go b/pkg/instrumentation/javaagent_test.go
index ea8d81305d..f52beb20a3 100644
--- a/pkg/instrumentation/javaagent_test.go
+++ b/pkg/instrumentation/javaagent_test.go
@@ -15,7 +15,6 @@
package instrumentation
import (
- "fmt"
"testing"
"github.com/stretchr/testify/assert"
@@ -30,7 +29,6 @@ func TestInjectJavaagent(t *testing.T) {
v1alpha1.Java
pod corev1.Pod
expected corev1.Pod
- err error
}{
{
name: "JAVA_TOOL_OPTIONS not defined",
@@ -83,7 +81,6 @@ func TestInjectJavaagent(t *testing.T) {
},
},
},
- err: nil,
},
{
name: "add extensions to JAVA_TOOL_OPTIONS",
@@ -157,7 +154,6 @@ func TestInjectJavaagent(t *testing.T) {
},
},
},
- err: nil,
},
{
name: "JAVA_TOOL_OPTIONS defined",
@@ -211,18 +207,21 @@ func TestInjectJavaagent(t *testing.T) {
Env: []corev1.EnvVar{
{
Name: "JAVA_TOOL_OPTIONS",
- Value: "-Dbaz=bar" + javaAgent,
+ Value: "-Dbaz=bar",
+ },
+ {
+ Name: "JAVA_TOOL_OPTIONS",
+ Value: "$(JAVA_TOOL_OPTIONS) " + javaAgent,
},
},
},
},
},
},
- err: nil,
},
{
name: "JAVA_TOOL_OPTIONS defined as ValueFrom",
- Java: v1alpha1.Java{Image: "foo/bar:1"},
+ Java: v1alpha1.Java{Image: "foo/bar:1", Resources: testResourceRequirements},
pod: corev1.Pod{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
@@ -239,27 +238,57 @@ func TestInjectJavaagent(t *testing.T) {
},
expected: corev1.Pod{
Spec: corev1.PodSpec{
+ Volumes: []corev1.Volume{
+ {
+ Name: "opentelemetry-auto-instrumentation-java",
+ VolumeSource: corev1.VolumeSource{
+ EmptyDir: &corev1.EmptyDirVolumeSource{
+ SizeLimit: &defaultVolumeLimitSize,
+ },
+ },
+ },
+ },
+ InitContainers: []corev1.Container{
+ {
+ Name: "opentelemetry-auto-instrumentation-java",
+ Image: "foo/bar:1",
+ Command: []string{"cp", "/javaagent.jar", "/otel-auto-instrumentation-java/javaagent.jar"},
+ VolumeMounts: []corev1.VolumeMount{{
+ Name: "opentelemetry-auto-instrumentation-java",
+ MountPath: "/otel-auto-instrumentation-java",
+ }},
+ Resources: testResourceRequirements,
+ },
+ },
Containers: []corev1.Container{
{
+ VolumeMounts: []corev1.VolumeMount{
+ {
+ Name: "opentelemetry-auto-instrumentation-java",
+ MountPath: "/otel-auto-instrumentation-java",
+ },
+ },
Env: []corev1.EnvVar{
{
Name: "JAVA_TOOL_OPTIONS",
ValueFrom: &corev1.EnvVarSource{},
},
+ {
+ Name: "JAVA_TOOL_OPTIONS",
+ Value: "$(JAVA_TOOL_OPTIONS) " + javaAgent,
+ },
},
},
},
},
},
- err: fmt.Errorf("the container defines env var value via ValueFrom, envVar: %s", envJavaToolsOptions),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
- pod, err := injectJavaagent(test.Java, test.pod, 0)
+ pod := injectJavaagent(test.Java, test.pod, 0)
assert.Equal(t, test.expected, pod)
- assert.Equal(t, test.err, err)
})
}
}
diff --git a/pkg/instrumentation/sdk.go b/pkg/instrumentation/sdk.go
index 0033f70566..e47c358fb0 100644
--- a/pkg/instrumentation/sdk.go
+++ b/pkg/instrumentation/sdk.go
@@ -59,7 +59,6 @@ func (i *sdkInjector) inject(ctx context.Context, insts languageInstrumentations
}
if insts.Java.Instrumentation != nil {
otelinst := *insts.Java.Instrumentation
- var err error
i.logger.V(1).Info("injecting Java instrumentation into pod", "otelinst-namespace", otelinst.Namespace, "otelinst-name", otelinst.Name)
if len(insts.Java.Containers) == 0 {
@@ -68,14 +67,10 @@ func (i *sdkInjector) inject(ctx context.Context, insts languageInstrumentations
for _, container := range insts.Java.Containers {
index := getContainerIndex(container, pod)
- pod, err = injectJavaagent(otelinst.Spec.Java, pod, index)
- if err != nil {
- i.logger.Info("Skipping javaagent injection", "reason", err.Error(), "container", pod.Spec.Containers[index].Name)
- } else {
- pod = i.injectCommonEnvVar(otelinst, pod, index)
- pod = i.injectCommonSDKConfig(ctx, otelinst, ns, pod, index, index)
- pod = i.setInitContainerSecurityContext(pod, pod.Spec.Containers[index].SecurityContext, javaInitContainerName)
- }
+ pod = injectJavaagent(otelinst.Spec.Java, pod, index)
+ pod = i.injectCommonEnvVar(otelinst, pod, index)
+ pod = i.injectCommonSDKConfig(ctx, otelinst, ns, pod, index, index)
+ pod = i.setInitContainerSecurityContext(pod, pod.Spec.Containers[index].SecurityContext, javaInitContainerName)
}
}
if insts.NodeJS.Instrumentation != nil {
diff --git a/tests/e2e-instrumentation/instrumentation-java-multicontainer/01-assert.yaml b/tests/e2e-instrumentation/instrumentation-java-multicontainer/01-assert.yaml
index a4dca94976..09b2a5687b 100644
--- a/tests/e2e-instrumentation/instrumentation-java-multicontainer/01-assert.yaml
+++ b/tests/e2e-instrumentation/instrumentation-java-multicontainer/01-assert.yaml
@@ -25,7 +25,7 @@ spec:
- name: SPLUNK_PROFILER_ENABLED
value: "false"
- name: JAVA_TOOL_OPTIONS
- value: ' -javaagent:/otel-auto-instrumentation-java/javaagent.jar'
+ value: '-javaagent:/otel-auto-instrumentation-java/javaagent.jar'
- name: OTEL_TRACES_EXPORTER
value: otlp
- name: OTEL_EXPORTER_OTLP_ENDPOINT
@@ -75,7 +75,7 @@ spec:
- name: SPLUNK_PROFILER_ENABLED
value: "false"
- name: JAVA_TOOL_OPTIONS
- value: ' -javaagent:/otel-auto-instrumentation-java/javaagent.jar'
+ value: '-javaagent:/otel-auto-instrumentation-java/javaagent.jar'
- name: OTEL_TRACES_EXPORTER
value: otlp
- name: OTEL_EXPORTER_OTLP_ENDPOINT
diff --git a/tests/e2e-instrumentation/instrumentation-java-multicontainer/02-assert.yaml b/tests/e2e-instrumentation/instrumentation-java-multicontainer/02-assert.yaml
index 03c002d2d8..5bfa1ceff3 100644
--- a/tests/e2e-instrumentation/instrumentation-java-multicontainer/02-assert.yaml
+++ b/tests/e2e-instrumentation/instrumentation-java-multicontainer/02-assert.yaml
@@ -36,7 +36,7 @@ spec:
- name: SPLUNK_PROFILER_ENABLED
value: "false"
- name: JAVA_TOOL_OPTIONS
- value: ' -javaagent:/otel-auto-instrumentation-java/javaagent.jar'
+ value: '-javaagent:/otel-auto-instrumentation-java/javaagent.jar'
- name: OTEL_TRACES_EXPORTER
value: otlp
- name: OTEL_EXPORTER_OTLP_ENDPOINT
diff --git a/tests/e2e-instrumentation/instrumentation-java-other-ns/03-assert.yaml b/tests/e2e-instrumentation/instrumentation-java-other-ns/03-assert.yaml
index 0b6ea1db84..ef36aa4c46 100644
--- a/tests/e2e-instrumentation/instrumentation-java-other-ns/03-assert.yaml
+++ b/tests/e2e-instrumentation/instrumentation-java-other-ns/03-assert.yaml
@@ -24,7 +24,7 @@ spec:
- name: SPLUNK_PROFILER_ENABLED
value: "false"
- name: JAVA_TOOL_OPTIONS
- value: ' -javaagent:/otel-auto-instrumentation-java/javaagent.jar'
+ value: '-javaagent:/otel-auto-instrumentation-java/javaagent.jar'
- name: OTEL_TRACES_EXPORTER
value: otlp
- name: OTEL_EXPORTER_OTLP_ENDPOINT
diff --git a/tests/e2e-instrumentation/instrumentation-java-tls/01-assert.yaml b/tests/e2e-instrumentation/instrumentation-java-tls/01-assert.yaml
index 7ddecadb47..6cb4d2d206 100644
--- a/tests/e2e-instrumentation/instrumentation-java-tls/01-assert.yaml
+++ b/tests/e2e-instrumentation/instrumentation-java-tls/01-assert.yaml
@@ -17,7 +17,7 @@ spec:
fieldRef:
fieldPath: status.podIP
- name: JAVA_TOOL_OPTIONS
- value: ' -javaagent:/otel-auto-instrumentation-java/javaagent.jar'
+ value: '-javaagent:/otel-auto-instrumentation-java/javaagent.jar'
- name: OTEL_SERVICE_NAME
value: my-java
- name: OTEL_EXPORTER_OTLP_ENDPOINT
diff --git a/tests/e2e-instrumentation/instrumentation-java/01-assert.yaml b/tests/e2e-instrumentation/instrumentation-java/01-assert.yaml
index cd8a8a37fe..f1af6b5218 100644
--- a/tests/e2e-instrumentation/instrumentation-java/01-assert.yaml
+++ b/tests/e2e-instrumentation/instrumentation-java/01-assert.yaml
@@ -17,6 +17,11 @@ spec:
valueFrom:
fieldRef:
fieldPath: status.podIP
+ - name: JAVA_TOOL_OPTIONS
+ valueFrom:
+ configMapKeyRef:
+ name: config-java
+ key: system-properties
- name: OTEL_JAVAAGENT_DEBUG
value: "true"
- name: OTEL_INSTRUMENTATION_JDBC_ENABLED
@@ -24,7 +29,7 @@ spec:
- name: SPLUNK_PROFILER_ENABLED
value: "false"
- name: JAVA_TOOL_OPTIONS
- value: ' -javaagent:/otel-auto-instrumentation-java/javaagent.jar'
+ value: '$(JAVA_TOOL_OPTIONS) -javaagent:/otel-auto-instrumentation-java/javaagent.jar'
- name: OTEL_TRACES_EXPORTER
value: otlp
- name: OTEL_EXPORTER_OTLP_ENDPOINT
diff --git a/tests/e2e-instrumentation/instrumentation-java/01-install-app.yaml b/tests/e2e-instrumentation/instrumentation-java/01-install-app.yaml
index 4655644b5b..c3204ec290 100644
--- a/tests/e2e-instrumentation/instrumentation-java/01-install-app.yaml
+++ b/tests/e2e-instrumentation/instrumentation-java/01-install-app.yaml
@@ -1,3 +1,10 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: config-java
+data:
+ system-properties: "-Xmx256m -Xms64m"
+---
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -22,6 +29,12 @@ spec:
containers:
- name: myapp
image: ghcr.io/open-telemetry/opentelemetry-operator/e2e-test-app-java:main
+ env:
+ - name: JAVA_TOOL_OPTIONS
+ valueFrom:
+ configMapKeyRef:
+ name: config-java
+ key: system-properties
securityContext:
allowPrivilegeEscalation: false
capabilities:
diff --git a/tests/e2e-multi-instrumentation/instrumentation-multi-multicontainer/01-assert.yaml b/tests/e2e-multi-instrumentation/instrumentation-multi-multicontainer/01-assert.yaml
index 3ba921ada1..250223271b 100644
--- a/tests/e2e-multi-instrumentation/instrumentation-multi-multicontainer/01-assert.yaml
+++ b/tests/e2e-multi-instrumentation/instrumentation-multi-multicontainer/01-assert.yaml
@@ -89,7 +89,7 @@ spec:
- name: OTEL_SERVICE_NAME
value: javaapp
- name: JAVA_TOOL_OPTIONS
- value: ' -javaagent:/otel-auto-instrumentation-java/javaagent.jar'
+ value: '-javaagent:/otel-auto-instrumentation-java/javaagent.jar'
- name: OTEL_TRACES_SAMPLER
value: parentbased_traceidratio
- name: OTEL_TRACES_SAMPLER_ARG