diff --git a/helm-chart/dash0-operator/README.md b/helm-chart/dash0-operator/README.md index 6ba7d199..b79d6e52 100644 --- a/helm-chart/dash0-operator/README.md +++ b/helm-chart/dash0-operator/README.md @@ -620,11 +620,12 @@ For example, it sets (or appends to) `NODE_OPTIONS` to activate the [Dash0 OpenTelemetry distribution for Node.js](https://github.com/dash0hq/opentelemetry-js-distribution) to collect tracing data from all Node.js workloads. -Additionally, the Dash0 injector will use the values of the `DASH0_POD_UID` and `DASH0_CONTAINER_NAME` environment -variables, added to the instrumented containers by the operator, to populate the resource attributes -`k8s.pod.uid` and `k8s.container.name` via the `OTEL_RESOURCE_ATTRIBUTES` environment variable. -These attributes are appended to the existing attributes specified by the original value of the -`OTEL_RESOURCE_ATTRIBUTES` environment variable, if the latter is set in the environment of the injected process. +Additionally, the Dash0 injector will use the values of the `DASH0_NAMESPACE_NAME`, `DASH0_POD_NAME`, `DASH0_POD_UID` +and `DASH0_CONTAINER_NAME` environment variables, added to the instrumented containers by the operator, to populate +the resource attributes `k8s.namespace.name`, `k8s.pod.name`, `k8s.pod.uid` and `k8s.container.name` via the +`OTEL_RESOURCE_ATTRIBUTES` environment variable. These attributes are appended to the existing attributes specified by +the original value of the `OTEL_RESOURCE_ATTRIBUTES` environment variable, if the latter is set in the environment of +the injected process. If you are curious, the source code for the injector is open source and can be found [here](https://github.com/dash0hq/dash0-operator/blob/main/images/instrumentation/injector/src/dash0_injector.c). diff --git a/images/instrumentation/injector/src/dash0_injector.c b/images/instrumentation/injector/src/dash0_injector.c index c534c4cb..bbd6ce0e 100644 --- a/images/instrumentation/injector/src/dash0_injector.c +++ b/images/instrumentation/injector/src/dash0_injector.c @@ -12,7 +12,9 @@ "--require " \ "/__dash0__/instrumentation/node.js/node_modules/@dash0hq/opentelemetry" #define OTEL_RESOURCE_ATTRIBUTES_ENV_VAR_NAME "OTEL_RESOURCE_ATTRIBUTES" +#define DASH0_NAMESPACE_NAME_ENV_VAR_NAME "DASH0_NAMESPACE_NAME" #define DASH0_POD_UID_ENV_VAR_NAME "DASH0_POD_UID" +#define DASH0_POD_NAME_ENV_VAR_NAME "DASH0_POD_NAME" #define DASH0_POD_CONTAINER_NAME_VAR_NAME "DASH0_CONTAINER_NAME" extern char **__environ; @@ -94,8 +96,6 @@ char val2[1012]; char *getenv(const char *name) { char *origValue = __getenv(name); - char *podUid = __getenv(DASH0_POD_UID_ENV_VAR_NAME); - char *containerName = __getenv(DASH0_POD_CONTAINER_NAME_VAR_NAME); int l = __strlen(name); char *otelResourceAttributesVarName = OTEL_RESOURCE_ATTRIBUTES_ENV_VAR_NAME; @@ -103,9 +103,34 @@ char *getenv(const char *name) { if (__strcmp(name, otelResourceAttributesVarName) == 0) { // If we have not calculated this env var yet if (__strlen(val1) == 0) { + char *namespaceName = __getenv(DASH0_NAMESPACE_NAME_ENV_VAR_NAME); + char *podUid = __getenv(DASH0_POD_UID_ENV_VAR_NAME); + char *podName = __getenv(DASH0_POD_NAME_ENV_VAR_NAME); + char *containerName = __getenv(DASH0_POD_CONTAINER_NAME_VAR_NAME); + int catCount = 0; + if (namespaceName != NULL && __strlen(namespaceName) > 0) { + __strcat(val1, "k8s.namespace.name="); + __strcat(val1, namespaceName); + catCount += 1; + } + + if (podName != NULL && __strlen(podName) > 0) { + if (catCount > 0) { + __strcat(val1, ","); + } + + __strcat(val1, "k8s.pod.name="); + __strcat(val1, podName); + catCount += 1; + } + if (podUid != NULL && __strlen(podUid) > 0) { + if (catCount > 0) { + __strcat(val1, ","); + } + __strcat(val1, "k8s.pod.uid="); __strcat(val1, podUid); catCount += 1; diff --git a/images/instrumentation/injector/test/scripts/run-tests-within-container.sh b/images/instrumentation/injector/test/scripts/run-tests-within-container.sh index a49f7697..2fa08b7e 100755 --- a/images/instrumentation/injector/test/scripts/run-tests-within-container.sh +++ b/images/instrumentation/injector/test/scripts/run-tests-within-container.sh @@ -45,9 +45,9 @@ run_test_case() { existing_otel_resource_attributes=${5:-} set +e if [ "$existing_node_options_value" != "" ]; then - test_output=$(LD_PRELOAD="$injector_binary" TEST_VAR=value DASH0_POD_UID=275ecb36-5aa8-4c2a-9c47-d8bb681b9aff DASH0_CONTAINER_NAME=test-app NODE_OPTIONS="$existing_node_options_value" OTEL_RESOURCE_ATTRIBUTES="${existing_otel_resource_attributes}" node index.js "$command") + test_output=$(LD_PRELOAD="$injector_binary" TEST_VAR=value DASH0_NAMESPACE_NAME=my-namespace DASH0_POD_NAME=my-pod DASH0_POD_UID=275ecb36-5aa8-4c2a-9c47-d8bb681b9aff DASH0_CONTAINER_NAME=test-app NODE_OPTIONS="$existing_node_options_value" OTEL_RESOURCE_ATTRIBUTES="${existing_otel_resource_attributes}" node index.js "$command") else - test_output=$(LD_PRELOAD="$injector_binary" TEST_VAR=value DASH0_POD_UID=275ecb36-5aa8-4c2a-9c47-d8bb681b9aff DASH0_CONTAINER_NAME=test-app OTEL_RESOURCE_ATTRIBUTES="${existing_otel_resource_attributes}" node index.js "$command") + test_output=$(LD_PRELOAD="$injector_binary" TEST_VAR=value DASH0_NAMESPACE_NAME=my-namespace DASH0_POD_NAME=my-pod DASH0_POD_UID=275ecb36-5aa8-4c2a-9c47-d8bb681b9aff DASH0_CONTAINER_NAME=test-app OTEL_RESOURCE_ATTRIBUTES="${existing_otel_resource_attributes}" node index.js "$command") fi test_exit_code=$? set -e @@ -76,8 +76,8 @@ run_test_case "getenv: overrides NODE_OPTIONS if it is not present" node_options run_test_case "getenv: ask for NODE_OPTIONS (unset) twice" node_options_twice "NODE_OPTIONS: --require /__dash0__/instrumentation/node.js/node_modules/@dash0hq/opentelemetry; NODE_OPTIONS: --require /__dash0__/instrumentation/node.js/node_modules/@dash0hq/opentelemetry" run_test_case "getenv: prepends to NODE_OPTIONS if it is present" node_options "NODE_OPTIONS: --require /__dash0__/instrumentation/node.js/node_modules/@dash0hq/opentelemetry --no-deprecation" "--no-deprecation" run_test_case "getenv: ask for NODE_OPTIONS (set) twice" node_options_twice "NODE_OPTIONS: --require /__dash0__/instrumentation/node.js/node_modules/@dash0hq/opentelemetry --no-deprecation; NODE_OPTIONS: --require /__dash0__/instrumentation/node.js/node_modules/@dash0hq/opentelemetry --no-deprecation" "--no-deprecation" -run_test_case "getenv: sets k8s.pod.uid and k8s.container.name via OTEL_RESOURCE_ATTRIBUTES" otel_resource_attributes "OTEL_RESOURCE_ATTRIBUTES: k8s.pod.uid=275ecb36-5aa8-4c2a-9c47-d8bb681b9aff,k8s.container.name=test-app" "" -run_test_case "getenv: sets k8s.pod.uid and k8s.container.name via OTEL_RESOURCE_ATTRIBUTES with pre-existing value" otel_resource_attributes "OTEL_RESOURCE_ATTRIBUTES: k8s.pod.uid=275ecb36-5aa8-4c2a-9c47-d8bb681b9aff,k8s.container.name=test-app,foo=bar" "" "foo=bar" +run_test_case "getenv: sets k8s.pod.uid and k8s.container.name via OTEL_RESOURCE_ATTRIBUTES" otel_resource_attributes "OTEL_RESOURCE_ATTRIBUTES: k8s.namespace.name=my-namespace,k8s.pod.name=my-pod,k8s.pod.uid=275ecb36-5aa8-4c2a-9c47-d8bb681b9aff,k8s.container.name=test-app" "" +run_test_case "getenv: sets k8s.pod.uid and k8s.container.name via OTEL_RESOURCE_ATTRIBUTES with pre-existing value" otel_resource_attributes "OTEL_RESOURCE_ATTRIBUTES: k8s.namespace.name=my-namespace,k8s.pod.name=my-pod,k8s.pod.uid=275ecb36-5aa8-4c2a-9c47-d8bb681b9aff,k8s.container.name=test-app,foo=bar" "" "foo=bar" exit $exit_code diff --git a/internal/webhooks/instrumentation_webhook_test.go b/internal/webhooks/instrumentation_webhook_test.go index 334368f8..346f70bb 100644 --- a/internal/webhooks/instrumentation_webhook_test.go +++ b/internal/webhooks/instrumentation_webhook_test.go @@ -196,25 +196,29 @@ var _ = Describe("The Dash0 instrumentation webhook", func() { { VolumeMounts: 2, Dash0VolumeMountIdx: 1, - EnvVars: 6, + EnvVars: 8, LdPreloadEnvVarIdx: 1, NodeIpIdx: 2, Dash0CollectorBaseUrlEnvVarIdx: 3, Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0PodUidEnvVarIdx: 4, - Dash0ContainerNameEnvVarIdx: 5, + Dash0NamespaceNameEnvVarIdx: 4, + Dash0PodNameEnvVarIdx: 5, + Dash0PodUidEnvVarIdx: 6, + Dash0ContainerNameEnvVarIdx: 7, Dash0ContainerNameEnvVarExpectedValue: "test-container-0", }, { VolumeMounts: 3, Dash0VolumeMountIdx: 2, - EnvVars: 7, + EnvVars: 9, LdPreloadEnvVarIdx: 2, NodeIpIdx: 3, Dash0CollectorBaseUrlEnvVarIdx: 4, Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0PodUidEnvVarIdx: 5, - Dash0ContainerNameEnvVarIdx: 6, + Dash0NamespaceNameEnvVarIdx: 5, + Dash0PodNameEnvVarIdx: 6, + Dash0PodUidEnvVarIdx: 7, + Dash0ContainerNameEnvVarIdx: 8, Dash0ContainerNameEnvVarExpectedValue: "test-container-1", }, }, @@ -242,27 +246,31 @@ var _ = Describe("The Dash0 instrumentation webhook", func() { { VolumeMounts: 2, Dash0VolumeMountIdx: 1, - EnvVars: 6, + EnvVars: 8, LdPreloadEnvVarIdx: 1, LdPreloadUsesValueFrom: true, NodeIpIdx: 2, Dash0CollectorBaseUrlEnvVarIdx: 3, Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0PodUidEnvVarIdx: 4, - Dash0ContainerNameEnvVarIdx: 5, + Dash0NamespaceNameEnvVarIdx: 4, + Dash0PodNameEnvVarIdx: 5, + Dash0PodUidEnvVarIdx: 6, + Dash0ContainerNameEnvVarIdx: 7, Dash0ContainerNameEnvVarExpectedValue: "test-container-0", }, { VolumeMounts: 3, Dash0VolumeMountIdx: 1, - EnvVars: 6, + EnvVars: 8, LdPreloadEnvVarIdx: 1, LdPreloadValue: "/__dash0__/dash0_injector.so third_party_preload.so another_third_party_preload.so", NodeIpIdx: 2, Dash0CollectorBaseUrlEnvVarIdx: 0, Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0PodUidEnvVarIdx: 4, - Dash0ContainerNameEnvVarIdx: 5, + Dash0NamespaceNameEnvVarIdx: 4, + Dash0PodNameEnvVarIdx: 5, + Dash0PodUidEnvVarIdx: 6, + Dash0ContainerNameEnvVarIdx: 7, Dash0ContainerNameEnvVarExpectedValue: "test-container-1", }, }, diff --git a/internal/workloads/workload_modifier.go b/internal/workloads/workload_modifier.go index 695e0c20..a6f8409d 100644 --- a/internal/workloads/workload_modifier.go +++ b/internal/workloads/workload_modifier.go @@ -32,7 +32,9 @@ const ( envVarLdPreloadValue = "/__dash0__/dash0_injector.so" envVarDash0CollectorBaseUrlName = "DASH0_OTEL_COLLECTOR_BASE_URL" envVarDash0NodeIp = "DASH0_NODE_IP" - envVarDash0PodUidName = "DASH0_POD_UID" + envVarDash0NamespaceName = "DASH0_NAMESPACE_NAME" + envVarDash0PodName = "DASH0_POD_NAME" + envVarDash0PodUid = "DASH0_POD_UID" envVarDash0ContainerName = "DASH0_CONTAINER_NAME" ) @@ -282,7 +284,31 @@ func (m *ResourceModifier) addEnvironmentVariables(container *corev1.Container, m.addOrReplaceEnvironmentVariable( container, corev1.EnvVar{ - Name: envVarDash0PodUidName, + Name: envVarDash0NamespaceName, + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.namespace", + }, + }, + }, + ) + + m.addOrReplaceEnvironmentVariable( + container, + corev1.EnvVar{ + Name: envVarDash0PodName, + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.name", + }, + }, + }, + ) + + m.addOrReplaceEnvironmentVariable( + container, + corev1.EnvVar{ + Name: envVarDash0PodUid, ValueFrom: &corev1.EnvVarSource{ FieldRef: &corev1.ObjectFieldSelector{ FieldPath: "metadata.uid", @@ -450,7 +476,9 @@ func (m *ResourceModifier) removeEnvironmentVariables(container *corev1.Containe m.removeLdPreload(container) m.removeEnvironmentVariable(container, envVarDash0NodeIp) m.removeEnvironmentVariable(container, envVarDash0CollectorBaseUrlName) - m.removeEnvironmentVariable(container, envVarDash0PodUidName) + m.removeEnvironmentVariable(container, envVarDash0NamespaceName) + m.removeEnvironmentVariable(container, envVarDash0PodName) + m.removeEnvironmentVariable(container, envVarDash0PodUid) m.removeEnvironmentVariable(container, envVarDash0ContainerName) } diff --git a/internal/workloads/workload_modifier_test.go b/internal/workloads/workload_modifier_test.go index 59b7f6ff..79ede4f9 100644 --- a/internal/workloads/workload_modifier_test.go +++ b/internal/workloads/workload_modifier_test.go @@ -74,25 +74,29 @@ var _ = Describe("Dash0 Workload Modification", func() { { VolumeMounts: 2, Dash0VolumeMountIdx: 1, - EnvVars: 6, + EnvVars: 8, LdPreloadEnvVarIdx: 1, NodeIpIdx: 2, Dash0CollectorBaseUrlEnvVarIdx: 3, Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0PodUidEnvVarIdx: 4, - Dash0ContainerNameEnvVarIdx: 5, + Dash0NamespaceNameEnvVarIdx: 4, + Dash0PodNameEnvVarIdx: 5, + Dash0PodUidEnvVarIdx: 6, + Dash0ContainerNameEnvVarIdx: 7, Dash0ContainerNameEnvVarExpectedValue: "test-container-0", }, { VolumeMounts: 3, Dash0VolumeMountIdx: 2, - EnvVars: 7, + EnvVars: 9, LdPreloadEnvVarIdx: 2, NodeIpIdx: 3, Dash0CollectorBaseUrlEnvVarIdx: 4, Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0PodUidEnvVarIdx: 5, - Dash0ContainerNameEnvVarIdx: 6, + Dash0NamespaceNameEnvVarIdx: 5, + Dash0PodNameEnvVarIdx: 6, + Dash0PodUidEnvVarIdx: 7, + Dash0ContainerNameEnvVarIdx: 8, Dash0ContainerNameEnvVarExpectedValue: "test-container-1", }, }, @@ -115,27 +119,31 @@ var _ = Describe("Dash0 Workload Modification", func() { { VolumeMounts: 2, Dash0VolumeMountIdx: 1, - EnvVars: 6, + EnvVars: 8, LdPreloadEnvVarIdx: 1, LdPreloadUsesValueFrom: true, NodeIpIdx: 2, Dash0CollectorBaseUrlEnvVarIdx: 3, Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0PodUidEnvVarIdx: 4, - Dash0ContainerNameEnvVarIdx: 5, + Dash0NamespaceNameEnvVarIdx: 4, + Dash0PodNameEnvVarIdx: 5, + Dash0PodUidEnvVarIdx: 6, + Dash0ContainerNameEnvVarIdx: 7, Dash0ContainerNameEnvVarExpectedValue: "test-container-0", }, { VolumeMounts: 3, Dash0VolumeMountIdx: 1, - EnvVars: 6, + EnvVars: 8, LdPreloadEnvVarIdx: 1, LdPreloadValue: "/__dash0__/dash0_injector.so third_party_preload.so another_third_party_preload.so", NodeIpIdx: 2, Dash0CollectorBaseUrlEnvVarIdx: 0, Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0PodUidEnvVarIdx: 4, - Dash0ContainerNameEnvVarIdx: 5, + Dash0NamespaceNameEnvVarIdx: 4, + Dash0PodNameEnvVarIdx: 5, + Dash0PodUidEnvVarIdx: 6, + Dash0ContainerNameEnvVarIdx: 7, Dash0ContainerNameEnvVarExpectedValue: "test-container-1", }, }, @@ -315,6 +323,8 @@ var _ = Describe("Dash0 Workload Modification", func() { LdPreloadEnvVarIdx: -1, NodeIpIdx: -1, Dash0CollectorBaseUrlEnvVarIdx: -1, + Dash0NamespaceNameEnvVarIdx: -1, + Dash0PodNameEnvVarIdx: -1, Dash0PodUidEnvVarIdx: -1, Dash0ContainerNameEnvVarIdx: -1, }, @@ -325,6 +335,8 @@ var _ = Describe("Dash0 Workload Modification", func() { LdPreloadEnvVarIdx: -1, NodeIpIdx: -1, Dash0CollectorBaseUrlEnvVarIdx: -1, + Dash0NamespaceNameEnvVarIdx: -1, + Dash0PodNameEnvVarIdx: -1, Dash0PodUidEnvVarIdx: -1, Dash0ContainerNameEnvVarIdx: -1, }, diff --git a/test/util/resources.go b/test/util/resources.go index ab254ea4..e1121bd0 100644 --- a/test/util/resources.go +++ b/test/util/resources.go @@ -916,6 +916,22 @@ func simulateInstrumentedPodSpec(podSpec *corev1.PodSpec, meta *metav1.ObjectMet Name: "DASH0_OTEL_COLLECTOR_BASE_URL", Value: OTelCollectorBaseUrlTest, }, + { + Name: "DASH0_NAMESPACE_NAME", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.namespace", + }, + }, + }, + { + Name: "DASH0_POD_NAME", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.name", + }, + }, + }, { Name: "DASH0_POD_UID", ValueFrom: &corev1.EnvVarSource{ diff --git a/test/util/verification.go b/test/util/verification.go index 0e1c0dd6..7c5d9e13 100644 --- a/test/util/verification.go +++ b/test/util/verification.go @@ -30,6 +30,8 @@ type ContainerExpectations struct { NodeIpIdx int Dash0CollectorBaseUrlEnvVarIdx int Dash0CollectorBaseUrlEnvVarExpectedValue string + Dash0NamespaceNameEnvVarIdx int + Dash0PodNameEnvVarIdx int Dash0PodUidEnvVarIdx int Dash0ContainerNameEnvVarIdx int Dash0ContainerNameEnvVarExpectedValue string @@ -75,13 +77,15 @@ func BasicInstrumentedPodSpecExpectations() PodSpecExpectations { Containers: []ContainerExpectations{{ VolumeMounts: 1, Dash0VolumeMountIdx: 0, - EnvVars: 5, + EnvVars: 7, LdPreloadEnvVarIdx: 0, NodeIpIdx: 1, Dash0CollectorBaseUrlEnvVarIdx: 2, Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0PodUidEnvVarIdx: 3, - Dash0ContainerNameEnvVarIdx: 4, + Dash0NamespaceNameEnvVarIdx: 3, + Dash0PodNameEnvVarIdx: 4, + Dash0PodUidEnvVarIdx: 5, + Dash0ContainerNameEnvVarIdx: 6, Dash0ContainerNameEnvVarExpectedValue: "test-container-0", }}, } @@ -310,6 +314,12 @@ func verifyPodSpec(podSpec corev1.PodSpec, expectations PodSpecExpectations) { Expect(envVar.Name).To(Equal("DASH0_OTEL_COLLECTOR_BASE_URL")) Expect(envVar.Value).To(Equal(containerExpectations.Dash0CollectorBaseUrlEnvVarExpectedValue)) Expect(envVar.ValueFrom).To(BeNil()) + } else if j == containerExpectations.Dash0NamespaceNameEnvVarIdx { + Expect(envVar.Name).To(Equal("DASH0_NAMESPACE_NAME")) + Expect(envVar.ValueFrom.FieldRef.FieldPath).To(Equal("metadata.namespace")) + } else if j == containerExpectations.Dash0PodNameEnvVarIdx { + Expect(envVar.Name).To(Equal("DASH0_POD_NAME")) + Expect(envVar.ValueFrom.FieldRef.FieldPath).To(Equal("metadata.name")) } else if j == containerExpectations.Dash0PodUidEnvVarIdx { Expect(envVar.Name).To(Equal("DASH0_POD_UID")) Expect(envVar.ValueFrom.FieldRef.FieldPath).To(Equal("metadata.uid"))