diff --git a/README.md b/README.md index 6a10a962f3..bd7930ba42 100644 --- a/README.md +++ b/README.md @@ -215,6 +215,14 @@ The possible values for the annotation can be * `"my-instrumentation"` - name of `Instrumentation` CR instance. * `"false"` - do not inject +It as also possible in case of multiple-containers Pods (like Istio sidecars) to specify the name of the container in which you want to inject OTEL auto-instrumentation (by default the first container is choosen) + +For this add this annotation to your Pod Specification with target container name : + +```bash +instrumentation.opentelemetry.io/container-name: "name_of_your_target_container" +``` + ## Compatibility matrix ### OpenTelemetry Operator vs. OpenTelemetry Collector diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go index d21b1f660a..5ea87e5479 100644 --- a/apis/v1alpha1/zz_generated.deepcopy.go +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated // Copyright The OpenTelemetry Authors diff --git a/pkg/instrumentation/annotation.go b/pkg/instrumentation/annotation.go index 8ce17a7c6f..c3036126f2 100644 --- a/pkg/instrumentation/annotation.go +++ b/pkg/instrumentation/annotation.go @@ -23,9 +23,10 @@ import ( const ( // annotationInjectJava indicates whether java auto-instrumentation should be injected or not. // Possible values are "true", "false" or "" name. - annotationInjectJava = "instrumentation.opentelemetry.io/inject-java" - annotationInjectNodeJS = "instrumentation.opentelemetry.io/inject-nodejs" - annotationInjectPython = "instrumentation.opentelemetry.io/inject-python" + annotationInjectJava = "instrumentation.opentelemetry.io/inject-java" + annotationInjectNodeJS = "instrumentation.opentelemetry.io/inject-nodejs" + annotationInjectPython = "instrumentation.opentelemetry.io/inject-python" + annotationInjectContainerName = "instrumentation.opentelemetry.io/container-name" ) // annotationValue returns the effective annotationInjectJava value, based on the annotations from the pod and namespace. diff --git a/pkg/instrumentation/javaagent.go b/pkg/instrumentation/javaagent.go index aba5501100..8c935255c9 100644 --- a/pkg/instrumentation/javaagent.go +++ b/pkg/instrumentation/javaagent.go @@ -26,9 +26,9 @@ const ( javaJVMArgument = " -javaagent:/otel-auto-instrumentation/javaagent.jar" ) -func injectJavaagent(logger logr.Logger, javaSpec v1alpha1.Java, pod corev1.Pod) corev1.Pod { +func injectJavaagent(logger logr.Logger, javaSpec v1alpha1.Java, pod corev1.Pod, index int) corev1.Pod { // caller checks if there is at least one container - container := &pod.Spec.Containers[0] + container := &pod.Spec.Containers[index] // inject env vars for _, env := range javaSpec.Env { diff --git a/pkg/instrumentation/javaagent_test.go b/pkg/instrumentation/javaagent_test.go index 28573d34fa..d97853bbfb 100644 --- a/pkg/instrumentation/javaagent_test.go +++ b/pkg/instrumentation/javaagent_test.go @@ -174,7 +174,7 @@ func TestInjectJavaagent(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - pod := injectJavaagent(logr.Discard(), test.Java, test.pod) + pod := injectJavaagent(logr.Discard(), test.Java, test.pod, 0) assert.Equal(t, test.expected, pod) }) } diff --git a/pkg/instrumentation/nodejs.go b/pkg/instrumentation/nodejs.go index 810866a0af..7a893cf445 100644 --- a/pkg/instrumentation/nodejs.go +++ b/pkg/instrumentation/nodejs.go @@ -26,9 +26,9 @@ const ( nodeRequireArgument = " --require /otel-auto-instrumentation/autoinstrumentation.js" ) -func injectNodeJSSDK(logger logr.Logger, nodeJSSpec v1alpha1.NodeJS, pod corev1.Pod) corev1.Pod { +func injectNodeJSSDK(logger logr.Logger, nodeJSSpec v1alpha1.NodeJS, pod corev1.Pod, index int) corev1.Pod { // caller checks if there is at least one container - container := &pod.Spec.Containers[0] + container := &pod.Spec.Containers[index] // inject env vars for _, env := range nodeJSSpec.Env { diff --git a/pkg/instrumentation/nodejs_test.go b/pkg/instrumentation/nodejs_test.go index f5a8bf93ad..e0a187f0ab 100644 --- a/pkg/instrumentation/nodejs_test.go +++ b/pkg/instrumentation/nodejs_test.go @@ -174,7 +174,7 @@ func TestInjectNodeJSSDK(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - pod := injectNodeJSSDK(logr.Discard(), test.NodeJS, test.pod) + pod := injectNodeJSSDK(logr.Discard(), test.NodeJS, test.pod, 0) assert.Equal(t, test.expected, pod) }) } diff --git a/pkg/instrumentation/podmutator.go b/pkg/instrumentation/podmutator.go index ba40d73b51..03e6267fc9 100644 --- a/pkg/instrumentation/podmutator.go +++ b/pkg/instrumentation/podmutator.go @@ -94,9 +94,12 @@ func (pm *instPodMutator) Mutate(ctx context.Context, ns corev1.Namespace, pod c return pod, nil } + // We retrieve the annotation for podname + var containerTarget = annotationValue(ns.ObjectMeta, pod.ObjectMeta, annotationInjectContainerName) + // once it's been determined that instrumentation is desired, none exists yet, and we know which instance it should talk to, // we should inject the instrumentation. - return pm.sdkInjector.inject(ctx, insts, ns, pod), nil + return pm.sdkInjector.inject(ctx, insts, ns, pod, containerTarget), nil } func (pm *instPodMutator) getInstrumentationInstance(ctx context.Context, ns corev1.Namespace, pod corev1.Pod, instAnnotation string) (*v1alpha1.Instrumentation, error) { diff --git a/pkg/instrumentation/python.go b/pkg/instrumentation/python.go index d6ebdddb97..92bb0ddf49 100644 --- a/pkg/instrumentation/python.go +++ b/pkg/instrumentation/python.go @@ -30,9 +30,9 @@ const ( pythonPathSuffix = "/otel-auto-instrumentation" ) -func injectPythonSDK(logger logr.Logger, pythonSpec v1alpha1.Python, pod corev1.Pod) corev1.Pod { +func injectPythonSDK(logger logr.Logger, pythonSpec v1alpha1.Python, pod corev1.Pod, index int) corev1.Pod { // caller checks if there is at least one container - container := &pod.Spec.Containers[0] + container := &pod.Spec.Containers[index] // inject env vars for _, env := range pythonSpec.Env { diff --git a/pkg/instrumentation/python_test.go b/pkg/instrumentation/python_test.go index 3fa6d68b2a..2d510fca38 100644 --- a/pkg/instrumentation/python_test.go +++ b/pkg/instrumentation/python_test.go @@ -244,7 +244,7 @@ func TestInjectPythonSDK(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - pod := injectPythonSDK(logr.Discard(), test.Python, test.pod) + pod := injectPythonSDK(logr.Discard(), test.Python, test.pod, 0) assert.Equal(t, test.expected, pod) }) } diff --git a/pkg/instrumentation/sdk.go b/pkg/instrumentation/sdk.go index 161e08ad29..eb94fafe3f 100644 --- a/pkg/instrumentation/sdk.go +++ b/pkg/instrumentation/sdk.go @@ -56,39 +56,48 @@ type sdkInjector struct { client client.Client } -func (i *sdkInjector) inject(ctx context.Context, insts languageInstrumentations, ns corev1.Namespace, pod corev1.Pod) corev1.Pod { +func (i *sdkInjector) inject(ctx context.Context, insts languageInstrumentations, ns corev1.Namespace, pod corev1.Pod, containerName string) corev1.Pod { if len(pod.Spec.Containers) < 1 { return pod } + // We search for specific container to inject variables and if no one is found + // We fallback to first container + var index = 0 + for idx, ctnair := range pod.Spec.Containers { + if ctnair.Name == containerName { + index = idx + } + } + // inject only to the first container for now // in the future we can define an annotation to configure this if insts.Java != nil { otelinst := *insts.Java i.logger.V(1).Info("injecting java instrumentation into pod", "otelinst-namespace", otelinst.Namespace, "otelinst-name", otelinst.Name) - pod = injectJavaagent(i.logger, otelinst.Spec.Java, pod) - pod = i.injectCommonEnvVar(otelinst, pod) - pod = i.injectCommonSDKConfig(ctx, otelinst, ns, pod) + pod = injectJavaagent(i.logger, otelinst.Spec.Java, pod, index) + pod = i.injectCommonEnvVar(otelinst, pod, index) + pod = i.injectCommonSDKConfig(ctx, otelinst, ns, pod, index) } if insts.NodeJS != nil { otelinst := *insts.NodeJS i.logger.V(1).Info("injecting nodejs instrumentation into pod", "otelinst-namespace", otelinst.Namespace, "otelinst-name", otelinst.Name) - pod = injectNodeJSSDK(i.logger, otelinst.Spec.NodeJS, pod) - pod = i.injectCommonEnvVar(otelinst, pod) - pod = i.injectCommonSDKConfig(ctx, otelinst, ns, pod) + pod = injectNodeJSSDK(i.logger, otelinst.Spec.NodeJS, pod, index) + pod = i.injectCommonEnvVar(otelinst, pod, index) + pod = i.injectCommonSDKConfig(ctx, otelinst, ns, pod, index) } if insts.Python != nil { otelinst := *insts.Python i.logger.V(1).Info("injecting python instrumentation into pod", "otelinst-namespace", otelinst.Namespace, "otelinst-name", otelinst.Name) - pod = injectPythonSDK(i.logger, otelinst.Spec.Python, pod) - pod = i.injectCommonEnvVar(otelinst, pod) - pod = i.injectCommonSDKConfig(ctx, otelinst, ns, pod) + pod = injectPythonSDK(i.logger, otelinst.Spec.Python, pod, index) + pod = i.injectCommonEnvVar(otelinst, pod, index) + pod = i.injectCommonSDKConfig(ctx, otelinst, ns, pod, index) } return pod } -func (i *sdkInjector) injectCommonEnvVar(otelinst v1alpha1.Instrumentation, pod corev1.Pod) corev1.Pod { - container := &pod.Spec.Containers[0] +func (i *sdkInjector) injectCommonEnvVar(otelinst v1alpha1.Instrumentation, pod corev1.Pod, index int) corev1.Pod { + container := &pod.Spec.Containers[index] for _, env := range otelinst.Spec.Env { idx := getIndexOfEnv(container.Env, env.Name) if idx == -1 { @@ -98,8 +107,8 @@ func (i *sdkInjector) injectCommonEnvVar(otelinst v1alpha1.Instrumentation, pod return pod } -func (i *sdkInjector) injectCommonSDKConfig(ctx context.Context, otelinst v1alpha1.Instrumentation, ns corev1.Namespace, pod corev1.Pod) corev1.Pod { - container := &pod.Spec.Containers[0] +func (i *sdkInjector) injectCommonSDKConfig(ctx context.Context, otelinst v1alpha1.Instrumentation, ns corev1.Namespace, pod corev1.Pod, index int) corev1.Pod { + container := &pod.Spec.Containers[index] resourceMap := i.createResourceMap(ctx, otelinst, ns, pod) idx := getIndexOfEnv(container.Env, envOTELServiceName) if idx == -1 { diff --git a/pkg/instrumentation/sdk_test.go b/pkg/instrumentation/sdk_test.go index 4ee0e63c0f..4b9659439f 100644 --- a/pkg/instrumentation/sdk_test.go +++ b/pkg/instrumentation/sdk_test.go @@ -364,7 +364,7 @@ func TestSDKInjection(t *testing.T) { inj := sdkInjector{ client: k8sClient, } - pod := inj.injectCommonSDKConfig(context.Background(), test.inst, corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: test.pod.Namespace}}, test.pod) + pod := inj.injectCommonSDKConfig(context.Background(), test.inst, corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: test.pod.Namespace}}, test.pod, 0) _, err = json.MarshalIndent(pod, "", " ") assert.NoError(t, err) assert.Equal(t, test.expected, pod) @@ -399,7 +399,7 @@ func TestInjectJava(t *testing.T) { }, }, }, - }) + }, "") assert.Equal(t, corev1.Pod{ Spec: corev1.PodSpec{ Volumes: []corev1.Volume{ @@ -497,7 +497,7 @@ func TestInjectNodeJS(t *testing.T) { }, }, }, - }) + }, "") assert.Equal(t, corev1.Pod{ Spec: corev1.PodSpec{ Volumes: []corev1.Volume{ @@ -596,7 +596,7 @@ func TestInjectPython(t *testing.T) { }, }, }, - }) + }, "") assert.Equal(t, corev1.Pod{ Spec: corev1.PodSpec{ Volumes: []corev1.Volume{