Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Choose target container injection with annotation #689

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,4 +324,4 @@ Thanks to all the people who already contributed!
[godoc-img]: https://godoc.org/github.com/open-telemetry/opentelemetry-operator?status.svg
[godoc]: https://godoc.org/github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1#OpenTelemetryCollector
[contributors]: https://github.com/open-telemetry/opentelemetry-operator/graphs/contributors
[contributors-img]: https://contributors-img.web.app/image?repo=open-telemetry/opentelemetry-operator
[contributors-img]: https://contributors-img.web.app/image?repo=open-telemetry/opentelemetry-operator
2 changes: 1 addition & 1 deletion config/manager/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
resources:
- manager.yaml
- manager.yaml
2 changes: 1 addition & 1 deletion kuttl-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ commands:
- command: sleep 5s
testDirs:
- ./tests/e2e/
timeout: 150
timeout: 150
7 changes: 4 additions & 3 deletions pkg/instrumentation/annotation.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ import (
const (
// annotationInjectJava indicates whether java auto-instrumentation should be injected or not.
// Possible values are "true", "false" or "<Instrumentation>" 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-names"
)

// annotationValue returns the effective annotationInjectJava value, based on the annotations from the pod and namespace.
Expand Down
27 changes: 27 additions & 0 deletions pkg/instrumentation/helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package instrumentation

import corev1 "k8s.io/api/core/v1"

// Calculate if we already inject InitContainers.
func IsInitContainerMissing(pod corev1.Pod) bool {
for _, initContainer := range pod.Spec.InitContainers {
if initContainer.Name == initContainerName {
return false
}
}
return true
}
74 changes: 74 additions & 0 deletions pkg/instrumentation/helper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package instrumentation

import (
"testing"

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

func TestInitContainerMissing(t *testing.T) {
tests := []struct {
name string
pod corev1.Pod
expected bool
}{
{
name: "InitContainer_Already_Inject",
pod: corev1.Pod{
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{
{
Name: "istio-init",
},
{
Name: initContainerName,
},
},
},
},
expected: false,
},
{
name: "InitContainer_Absent_1",
pod: corev1.Pod{
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{
{
Name: "istio-init",
},
},
},
},
expected: true,
},
{
name: "InitContainer_Absent_2",
pod: corev1.Pod{
Spec: corev1.PodSpec{},
},
expected: true,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
result := IsInitContainerMissing(test.pod)
assert.Equal(t, test.expected, result)
})
}
}
35 changes: 19 additions & 16 deletions pkg/instrumentation/javaagent.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -57,21 +57,24 @@ func injectJavaagent(logger logr.Logger, javaSpec v1alpha1.Java, pod corev1.Pod)
MountPath: "/otel-auto-instrumentation",
})

pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{
Name: volumeName,
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
}})
// We just inject Volumes and init containers for the first processed container
if IsInitContainerMissing(pod) {
pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{
Name: volumeName,
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
}})

pod.Spec.InitContainers = append(pod.Spec.InitContainers, corev1.Container{
Name: initContainerName,
Image: javaSpec.Image,
Command: []string{"cp", "/javaagent.jar", "/otel-auto-instrumentation/javaagent.jar"},
VolumeMounts: []corev1.VolumeMount{{
Name: volumeName,
MountPath: "/otel-auto-instrumentation",
}},
})
pod.Spec.InitContainers = append(pod.Spec.InitContainers, corev1.Container{
Name: initContainerName,
Image: javaSpec.Image,
Command: []string{"cp", "/javaagent.jar", "/otel-auto-instrumentation/javaagent.jar"},
VolumeMounts: []corev1.VolumeMount{{
Name: volumeName,
MountPath: "/otel-auto-instrumentation",
}},
})
}

return pod
}
2 changes: 1 addition & 1 deletion pkg/instrumentation/javaagent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
}
Expand Down
35 changes: 19 additions & 16 deletions pkg/instrumentation/nodejs.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -57,21 +57,24 @@ func injectNodeJSSDK(logger logr.Logger, nodeJSSpec v1alpha1.NodeJS, pod corev1.
MountPath: "/otel-auto-instrumentation",
})

pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{
Name: volumeName,
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
}})
// We just inject Volumes and init containers for the first processed container
if IsInitContainerMissing(pod) {
pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{
Name: volumeName,
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
}})

pod.Spec.InitContainers = append(pod.Spec.InitContainers, corev1.Container{
Name: initContainerName,
Image: nodeJSSpec.Image,
Command: []string{"cp", "-a", "/autoinstrumentation/.", "/otel-auto-instrumentation/"},
VolumeMounts: []corev1.VolumeMount{{
Name: volumeName,
MountPath: "/otel-auto-instrumentation",
}},
})
pod.Spec.InitContainers = append(pod.Spec.InitContainers, corev1.Container{
Name: initContainerName,
Image: nodeJSSpec.Image,
Command: []string{"cp", "-a", "/autoinstrumentation/.", "/otel-auto-instrumentation/"},
VolumeMounts: []corev1.VolumeMount{{
Name: volumeName,
MountPath: "/otel-auto-instrumentation",
}},
})
}

return pod
}
2 changes: 1 addition & 1 deletion pkg/instrumentation/nodejs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
}
Expand Down
10 changes: 9 additions & 1 deletion pkg/instrumentation/podmutator.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,17 @@ func (pm *instPodMutator) Mutate(ctx context.Context, ns corev1.Namespace, pod c
return pod, nil
}

// We retrieve the annotation for podname
var targetContainers = 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
modifiedPod := pod
for _, currentContainer := range strings.Split(targetContainers, ",") {
modifiedPod = pm.sdkInjector.inject(ctx, insts, ns, modifiedPod, strings.TrimSpace(currentContainer))
}

return modifiedPod, nil
}

func (pm *instPodMutator) getInstrumentationInstance(ctx context.Context, ns corev1.Namespace, pod corev1.Pod, instAnnotation string) (*v1alpha1.Instrumentation, error) {
Expand Down
35 changes: 19 additions & 16 deletions pkg/instrumentation/python.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -71,21 +71,24 @@ func injectPythonSDK(logger logr.Logger, pythonSpec v1alpha1.Python, pod corev1.
MountPath: "/otel-auto-instrumentation",
})

pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{
Name: volumeName,
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
}})
// We just inject Volumes and init containers for the first processed container
if IsInitContainerMissing(pod) {
pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{
Name: volumeName,
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
}})

pod.Spec.InitContainers = append(pod.Spec.InitContainers, corev1.Container{
Name: initContainerName,
Image: pythonSpec.Image,
Command: []string{"cp", "-a", "/autoinstrumentation/.", "/otel-auto-instrumentation/"},
VolumeMounts: []corev1.VolumeMount{{
Name: volumeName,
MountPath: "/otel-auto-instrumentation",
}},
})
pod.Spec.InitContainers = append(pod.Spec.InitContainers, corev1.Container{
Name: initContainerName,
Image: pythonSpec.Image,
Command: []string{"cp", "-a", "/autoinstrumentation/.", "/otel-auto-instrumentation/"},
VolumeMounts: []corev1.VolumeMount{{
Name: volumeName,
MountPath: "/otel-auto-instrumentation",
}},
})
}

return pod
}
2 changes: 1 addition & 1 deletion pkg/instrumentation/python_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
}
Expand Down
Loading