From 088b15c85ffe085469354160a290bee477151788 Mon Sep 17 00:00:00 2001 From: Michele Mancioppi Date: Tue, 7 Jan 2025 09:15:45 +0100 Subject: [PATCH] feat: add auto-instrumentation support for Java 8+ (#228) Signed-off-by: Michele Mancioppi --- .github/dependabot.yml | 7 + .github/workflows/ci.yaml | 2 +- helm-chart/dash0-operator/README.md | 5 +- images/instrumentation/Dockerfile | 11 +- .../injector/src/dash0_injector.c | 184 ++++++++----- images/instrumentation/jvm/.gitignore | 14 + .../jvm/.mvn/wrapper/maven-wrapper.properties | 19 ++ images/instrumentation/jvm/README.md | 10 + images/instrumentation/jvm/build/.gitkeep | 0 images/instrumentation/jvm/mvnw | 259 ++++++++++++++++++ images/instrumentation/jvm/pom.xml | 34 +++ .../instrumentation/test/jvm/.m2/.gitignore | 1 + .../test/jvm/.m2/repository/.gitkeep | 0 .../instrumentation/test/jvm/.m2/settings.xml | 4 + images/instrumentation/test/jvm/Dockerfile | 20 ++ images/instrumentation/test/jvm/base-images | 7 + .../jvm/test-cases/existing-unmodified/.env | 8 + .../test-cases/existing-unmodified/.gitignore | 10 + .../.mvn/wrapper/maven-wrapper.properties | 19 ++ .../jvm/test-cases/existing-unmodified/mvnw | 259 ++++++++++++++++++ .../test-cases/existing-unmodified/pom.xml | 41 +++ .../existing_envvar_demo/TestApplication.java | 28 ++ .../src/main/resources/application.properties | 1 + .../TestApplicationTests.java | 15 + .../otel-resource-attributes-already-set/.env | 8 + .../.gitignore | 10 + .../.mvn/wrapper/maven-wrapper.properties | 19 ++ .../otel-resource-attributes-already-set/mvnw | 259 ++++++++++++++++++ .../pom.xml | 41 +++ .../TestApplication.java | 30 ++ .../src/main/resources/application.properties | 1 + .../TestApplicationTests.java | 15 + .../undefined-for-non-existing/.env | 7 + .../undefined-for-non-existing/.gitignore | 10 + .../.mvn/wrapper/maven-wrapper.properties | 19 ++ .../undefined-for-non-existing/mvnw | 259 ++++++++++++++++++ .../undefined-for-non-existing/pom.xml | 41 +++ .../existing_envvar_demo/TestApplication.java | 28 ++ .../TestApplicationTests.java | 13 + images/instrumentation/test/test-all.sh | 32 +-- .../webhooks/instrumentation_webhook_test.go | 108 ++++---- internal/workloads/workload_modifier.go | 35 ++- internal/workloads/workload_modifier_test.go | 150 +++++----- .../dash0operatorconfiguration.secret.yaml | 4 +- test/util/resources.go | 19 +- test/util/verification.go | 62 +++-- 46 files changed, 1878 insertions(+), 250 deletions(-) create mode 100644 images/instrumentation/jvm/.gitignore create mode 100644 images/instrumentation/jvm/.mvn/wrapper/maven-wrapper.properties create mode 100644 images/instrumentation/jvm/README.md create mode 100644 images/instrumentation/jvm/build/.gitkeep create mode 100755 images/instrumentation/jvm/mvnw create mode 100644 images/instrumentation/jvm/pom.xml create mode 100644 images/instrumentation/test/jvm/.m2/.gitignore create mode 100644 images/instrumentation/test/jvm/.m2/repository/.gitkeep create mode 100644 images/instrumentation/test/jvm/.m2/settings.xml create mode 100644 images/instrumentation/test/jvm/Dockerfile create mode 100644 images/instrumentation/test/jvm/base-images create mode 100644 images/instrumentation/test/jvm/test-cases/existing-unmodified/.env create mode 100644 images/instrumentation/test/jvm/test-cases/existing-unmodified/.gitignore create mode 100644 images/instrumentation/test/jvm/test-cases/existing-unmodified/.mvn/wrapper/maven-wrapper.properties create mode 100755 images/instrumentation/test/jvm/test-cases/existing-unmodified/mvnw create mode 100644 images/instrumentation/test/jvm/test-cases/existing-unmodified/pom.xml create mode 100644 images/instrumentation/test/jvm/test-cases/existing-unmodified/src/main/java/com/dash0/injector/existing_envvar_demo/TestApplication.java create mode 100644 images/instrumentation/test/jvm/test-cases/existing-unmodified/src/main/resources/application.properties create mode 100644 images/instrumentation/test/jvm/test-cases/existing-unmodified/src/test/java/com/dash0/injector/existing_envvar_demo/TestApplicationTests.java create mode 100644 images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/.env create mode 100644 images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/.gitignore create mode 100644 images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/.mvn/wrapper/maven-wrapper.properties create mode 100755 images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/mvnw create mode 100644 images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/pom.xml create mode 100644 images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/src/main/java/com/dash0/injector/otel-resource-attributes-already-set/TestApplication.java create mode 100644 images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/src/main/resources/application.properties create mode 100644 images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/src/test/java/com/dash0/injector/otel-resource-attributes-already-set/TestApplicationTests.java create mode 100644 images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/.env create mode 100644 images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/.gitignore create mode 100644 images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/.mvn/wrapper/maven-wrapper.properties create mode 100755 images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/mvnw create mode 100644 images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/pom.xml create mode 100644 images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/src/main/java/com/dash0/injector/existing_envvar_demo/TestApplication.java create mode 100644 images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/src/test/java/com/dash0/injector/existing_envvar_demo/TestApplicationTests.java diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a9f728d4..832e32a5 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -25,7 +25,14 @@ updates: development-dependencies: dependency-type: "development" + # Dash0 OpenTelemetry Distro for Node.js - package-ecosystem: "npm" directory: "images/instrumentation/node.js/" schedule: interval: "daily" + + # OpenTelemetry Java agent + - package-ecosystem: "maven" + directory: "images/instrumentation/jvm/" + schedule: + interval: "daily" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3fa98bd5..d8329f27 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -77,7 +77,7 @@ jobs: injector_binary_and_instrumentation_image_tests: name: Injector Binary & Instrumentation Image Tests runs-on: ubuntu-latest - timeout-minutes: 20 + timeout-minutes: 40 steps: - uses: actions/checkout@v4 diff --git a/helm-chart/dash0-operator/README.md b/helm-chart/dash0-operator/README.md index 6c8f85a5..75ce7d89 100644 --- a/helm-chart/dash0-operator/README.md +++ b/helm-chart/dash0-operator/README.md @@ -21,7 +21,8 @@ The Dash0 operator is currently available as a technical preview. Supported runtimes for automatic workload instrumentation: -* Node.js 18 and beyond +* Java 8+ +* Node.js 18+ Other features like metrics and log collection are independent of the runtime of workloads. @@ -878,7 +879,7 @@ Prometheus Rule Synchronization Results: ## Notes on Running The Operator on Apple Silicon When running the operator on an Apple Silicon host (M1, M3 etc.), for example via Docker Desktop, some attention needs -to be paid to the CPU architecture of images. The architcture of the Kubernetes node for this scenario will be `arm64`. +to be paid to the CPU architecture of images. The architecture of the Kubernetes node for this scenario will be `arm64`. When running a single-architecture `amd64` image (as opposed to a single-architecture `arm64` image or a [multi-platform build](https://docs.docker.com/build/building/multi-platform/) containing `amd64` as well as `arm64`) the operator will prevent the container from starting. diff --git a/images/instrumentation/Dockerfile b/images/instrumentation/Dockerfile index 70e1d255..d756719a 100644 --- a/images/instrumentation/Dockerfile +++ b/images/instrumentation/Dockerfile @@ -16,9 +16,17 @@ RUN gcc \ src/dash0_injector.c \ -o dash0_injector.so +# download OpenTelemetry Java agent +FROM openjdk:24-jdk-bookworm AS build-jvm +COPY jvm /dash0-init-container/instrumentation/jvm +WORKDIR /dash0-init-container/instrumentation/jvm +RUN ./mvnw dependency:copy-dependencies \ + && cp ./target/dependency/opentelemetry-javaagent-*.jar ./build/opentelemetry-javaagent.jar \ + && cp pom.xml ./build/pom.xml + # build Node.js artifacts FROM node:20.13.1-alpine3.19 AS build-node.js -RUN mkdir -p /instrumentation/node.js +RUN mkdir -p /dash0-init-container/instrumentation/node.js WORKDIR /dash0-init-container/instrumentation/node.js COPY node.js/package* ./ COPY node.js/dash0hq-opentelemetry-*.tgz . @@ -36,6 +44,7 @@ COPY copy-instrumentation.sh / # copy artifacts (distros, injector binary) from the build stages to the final image RUN mkdir -p /dash0-init-container/instrumentation COPY --from=build-injector /dash0-init-container/dash0_injector.so /dash0-init-container/dash0_injector.so +COPY --from=build-jvm /dash0-init-container/instrumentation/jvm/build /dash0-init-container/instrumentation/jvm COPY --from=build-node.js /dash0-init-container/instrumentation/node.js /dash0-init-container/instrumentation/node.js WORKDIR / diff --git a/images/instrumentation/injector/src/dash0_injector.c b/images/instrumentation/injector/src/dash0_injector.c index c91388ac..c1c27599 100644 --- a/images/instrumentation/injector/src/dash0_injector.c +++ b/images/instrumentation/injector/src/dash0_injector.c @@ -7,6 +7,10 @@ #define HIGHS (ONES * (UCHAR_MAX / 2 + 1)) #define HASZERO(x) ((x) - ONES & ~(x) & HIGHS) +#define JAVA_TOOL_OPTIONS_ENV_VAR_NAME "JAVA_TOOL_OPTIONS" +#define JAVA_TOOL_OPTIONS_DASH0_REQUIRE \ + "-javaagent:" \ + "/__dash0__/instrumentation/jvm/opentelemetry-javaagent.jar" #define NODE_OPTIONS_ENV_VAR_NAME "NODE_OPTIONS" #define NODE_OPTIONS_DASH0_REQUIRE \ "--require " \ @@ -92,103 +96,149 @@ char *__getenv(const char *name) { * the program manipulated values of env vars without dynamic allocations. */ char cachedModifiedOtelResourceAttributesValue[1012]; -char cachedModifiedNodeOptionsValue[1012]; +char cachedModifiedRuntimeOptionsValue[1012]; + +char *__appendResourceAttributes(const char *buffer, const char *origValue) { + 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 attributeCount = 0; + + /* + * We do not perform octect escaping in the resource attributes as + * specified in + * https://opentelemetry.io/docs/specs/otel/resource/sdk/#specifying-resource-information-via-an-environment-variable + * because the values that are passed down to the injector comes from + * fields that Kubernetes already enforces to either conform to RFC 1035 + * or RFC RFC 1123 + * (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names), + * and in either case, none of the characters allowed require escaping + * based on https://www.w3.org/TR/baggage/#header-content + */ + + if (namespaceName != NULL && __strlen(namespaceName) > 0) { + __strcat(buffer, "k8s.namespace.name="); + __strcat(buffer, namespaceName); + attributeCount += 1; + } + + if (podName != NULL && __strlen(podName) > 0) { + if (attributeCount > 0) { + __strcat(buffer, ","); + } + + __strcat(buffer, "k8s.pod.name="); + __strcat(buffer, podName); + attributeCount += 1; + } + + if (podUid != NULL && __strlen(podUid) > 0) { + if (attributeCount > 0) { + __strcat(buffer, ","); + } + + __strcat(buffer, "k8s.pod.uid="); + __strcat(buffer, podUid); + attributeCount += 1; + } + + if (containerName != NULL && __strlen(containerName) > 0) { + if (attributeCount > 0) { + __strcat(buffer, ","); + } + + __strcat(buffer, "k8s.container.name="); + __strcat(buffer, containerName); + attributeCount += 1; + } + + if (origValue != NULL && __strlen(origValue) > 0) { + if (attributeCount > 0) { + __strcat(buffer, ","); + } + + __strcat(buffer, origValue); + } +} char *getenv(const char *name) { char *origValue = __getenv(name); int l = __strlen(name); char *otelResourceAttributesVarName = OTEL_RESOURCE_ATTRIBUTES_ENV_VAR_NAME; + char *javaToolOptionsVarName = JAVA_TOOL_OPTIONS_ENV_VAR_NAME; char *nodeOptionsVarName = NODE_OPTIONS_ENV_VAR_NAME; if (__strcmp(name, otelResourceAttributesVarName) == 0) { if (__strlen(cachedModifiedOtelResourceAttributesValue) == 0) { // This environment variable (OTEL_RESOURCE_ATTRIBUTES) has not been // requested before, calculate the modified value and cache it. - 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 attributeCount = 0; - - /* - * We do not perform octect escaping in the resource attributes as - * specified in - * https://opentelemetry.io/docs/specs/otel/resource/sdk/#specifying-resource-information-via-an-environment-variable - * because the values that are passed down to the injector comes from - * fields that Kubernetes already enforces to either conform to RFC 1035 - * or RFC RFC 1123 - * (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names), - * and in either case, none of the characters allowed require escaping - * based on https://www.w3.org/TR/baggage/#header-content - */ - - if (namespaceName != NULL && __strlen(namespaceName) > 0) { - __strcat(cachedModifiedOtelResourceAttributesValue, - "k8s.namespace.name="); - __strcat(cachedModifiedOtelResourceAttributesValue, namespaceName); - attributeCount += 1; - } - - if (podName != NULL && __strlen(podName) > 0) { - if (attributeCount > 0) { - __strcat(cachedModifiedOtelResourceAttributesValue, ","); - } - - __strcat(cachedModifiedOtelResourceAttributesValue, "k8s.pod.name="); - __strcat(cachedModifiedOtelResourceAttributesValue, podName); - attributeCount += 1; - } - - if (podUid != NULL && __strlen(podUid) > 0) { - if (attributeCount > 0) { - __strcat(cachedModifiedOtelResourceAttributesValue, ","); - } - - __strcat(cachedModifiedOtelResourceAttributesValue, "k8s.pod.uid="); - __strcat(cachedModifiedOtelResourceAttributesValue, podUid); - attributeCount += 1; - } + __appendResourceAttributes(cachedModifiedOtelResourceAttributesValue, + origValue); + } - if (containerName != NULL && __strlen(containerName) > 0) { - if (attributeCount > 0) { - __strcat(cachedModifiedOtelResourceAttributesValue, ","); - } + return cachedModifiedOtelResourceAttributesValue; + } else if (__strcmp(name, javaToolOptionsVarName) == 0) { + if (__strlen(cachedModifiedRuntimeOptionsValue) == 0) { + // No runtime environment variable has been requested before, + // calculate the modified value and cache it. - __strcat(cachedModifiedOtelResourceAttributesValue, - "k8s.container.name="); - __strcat(cachedModifiedOtelResourceAttributesValue, containerName); - attributeCount += 1; - } + // Prepend our --require as the first item to the JAVA_TOOL_OPTIONS + // string. + char *javaToolOptionsDash0Require = JAVA_TOOL_OPTIONS_DASH0_REQUIRE; + __strcat(cachedModifiedRuntimeOptionsValue, javaToolOptionsDash0Require); + + // The Java runtime does not look up the OTEL_RESOURCE_ATTRIBUTES env var + // using getenv(), but rather by parsing the environment block + // (/proc/env/) directly, which we cannot affect with the getenv + // hook. So, instead, we append the resource attributes as the + // -Dotel.resource.attributes Java system property. + // If the -Dotel.resource.attributes system property is already set, + // the user-defined property will take precedence: + // + // % JAVA_TOOL_OPTIONS="-Dprop=B" jshell -R -Dprop=A + // Picked up JAVA_TOOL_OPTIONS: -Dprop=B + // | Welcome to JShell -- Version 17.0.12 + // | For an introduction type: /help intro + // + // jshell> System.getProperty("prop") + // $1 ==> "A" + + char *otelResourceAttributesViaEnv = + __getenv(OTEL_RESOURCE_ATTRIBUTES_ENV_VAR_NAME); + __strcat(cachedModifiedRuntimeOptionsValue, + " -Dotel.resource.attributes="); + __appendResourceAttributes(cachedModifiedRuntimeOptionsValue, + otelResourceAttributesViaEnv); if (origValue != NULL && __strlen(origValue) > 0) { - if (attributeCount > 0) { - __strcat(cachedModifiedOtelResourceAttributesValue, ","); - } - - __strcat(cachedModifiedOtelResourceAttributesValue, origValue); + // If JAVA_TOOL_OPTIONS were present, append the existing + // JAVA_TOOL_OPTIONS after our --javaagent. + __strcat(cachedModifiedRuntimeOptionsValue, " "); + __strcat(cachedModifiedRuntimeOptionsValue, origValue); } } - return cachedModifiedOtelResourceAttributesValue; + return cachedModifiedRuntimeOptionsValue; } else if (__strcmp(name, nodeOptionsVarName) == 0) { - if (__strlen(cachedModifiedNodeOptionsValue) == 0) { - // This environment variable (NODE_OPTIONS) has not been requested before, + if (__strlen(cachedModifiedRuntimeOptionsValue) == 0) { + // No runtime environment variable has been requested before, // calculate the modified value and cache it. // Prepend our --require as the first item to the NODE_OPTIONS string. char *nodeOptionsDash0Require = NODE_OPTIONS_DASH0_REQUIRE; - __strcat(cachedModifiedNodeOptionsValue, nodeOptionsDash0Require); + __strcat(cachedModifiedRuntimeOptionsValue, nodeOptionsDash0Require); if (origValue != NULL && __strlen(origValue) > 0) { // If NODE_OPTIONS were present, append the existing NODE_OPTIONS after // our --require. - __strcat(cachedModifiedNodeOptionsValue, " "); - __strcat(cachedModifiedNodeOptionsValue, origValue); + __strcat(cachedModifiedRuntimeOptionsValue, " "); + __strcat(cachedModifiedRuntimeOptionsValue, origValue); } } - return cachedModifiedNodeOptionsValue; + return cachedModifiedRuntimeOptionsValue; } return origValue; diff --git a/images/instrumentation/jvm/.gitignore b/images/instrumentation/jvm/.gitignore new file mode 100644 index 00000000..e967900a --- /dev/null +++ b/images/instrumentation/jvm/.gitignore @@ -0,0 +1,14 @@ +# Download +build/* + +# Maven +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar \ No newline at end of file diff --git a/images/instrumentation/jvm/.mvn/wrapper/maven-wrapper.properties b/images/instrumentation/jvm/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..d58dfb70 --- /dev/null +++ b/images/instrumentation/jvm/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +wrapperVersion=3.3.2 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/images/instrumentation/jvm/README.md b/images/instrumentation/jvm/README.md new file mode 100644 index 00000000..593ec660 --- /dev/null +++ b/images/instrumentation/jvm/README.md @@ -0,0 +1,10 @@ +# JVM instrumentation + +We currently do not have a Dash0 distro for Java. +Rather, we use the upstream [OpenTelemetry Java agent](https://github.com/open-telemetry/opentelemetry-java-instrumentation). +The version of the OTel Java agent to be used is specified in the [local `pom.xml`](./pom.xml) file. +Maven can download the correct version of the OTel Java agent by running: + +```shell +./mvnw dependency:copy-dependencies +``` \ No newline at end of file diff --git a/images/instrumentation/jvm/build/.gitkeep b/images/instrumentation/jvm/build/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/images/instrumentation/jvm/mvnw b/images/instrumentation/jvm/mvnw new file mode 100755 index 00000000..19529ddf --- /dev/null +++ b/images/instrumentation/jvm/mvnw @@ -0,0 +1,259 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.3.2 +# +# Optional ENV vars +# ----------------- +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output +# ---------------------------------------------------------------------------- + +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x + +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac + +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/images/instrumentation/jvm/pom.xml b/images/instrumentation/jvm/pom.xml new file mode 100644 index 00000000..690fbc64 --- /dev/null +++ b/images/instrumentation/jvm/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + com.dash0.instrumentation + otel-javaagent-downloader + 0.0.1-SNAPSHOT + pom + + + io.opentelemetry.javaagent + opentelemetry-javaagent + 2.11.0 + + + + + + maven-dependency-plugin + + + install + + copy-dependencies + + + ${project.build.directory} + + + + + + + \ No newline at end of file diff --git a/images/instrumentation/test/jvm/.m2/.gitignore b/images/instrumentation/test/jvm/.m2/.gitignore new file mode 100644 index 00000000..a8fa6605 --- /dev/null +++ b/images/instrumentation/test/jvm/.m2/.gitignore @@ -0,0 +1 @@ +repository/* \ No newline at end of file diff --git a/images/instrumentation/test/jvm/.m2/repository/.gitkeep b/images/instrumentation/test/jvm/.m2/repository/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/images/instrumentation/test/jvm/.m2/settings.xml b/images/instrumentation/test/jvm/.m2/settings.xml new file mode 100644 index 00000000..69994132 --- /dev/null +++ b/images/instrumentation/test/jvm/.m2/settings.xml @@ -0,0 +1,4 @@ + + /.m2/repository + \ No newline at end of file diff --git a/images/instrumentation/test/jvm/Dockerfile b/images/instrumentation/test/jvm/Dockerfile new file mode 100644 index 00000000..f1cc5627 --- /dev/null +++ b/images/instrumentation/test/jvm/Dockerfile @@ -0,0 +1,20 @@ +# SPDX-FileCopyrightText: Copyright 2024 Dash0 Inc. +# SPDX-License-Identifier: Apache-2.0 + +ARG instrumentation_image=dash0-instrumentation:latest +ARG test_image=openjdk:24-jdk-bookworm + +FROM ${instrumentation_image} AS init + +FROM ${test_image} + +COPY test-cases /test-cases +COPY .m2 /.m2 + +RUN for test in /test-cases/*; do (cd "/${test}" && JAVA_HOME=$(which java | xargs dirname | xargs dirname) "./mvnw" "-gs" "/.m2/settings.xml" package); done + +# The following lines emulate the behavior of running the instrumentation image as a Kubernetes init container and +# setting the LD_PRELOAD environment variable via the operator. +COPY --from=init /dash0-init-container/*.so /__dash0__/ +COPY --from=init /dash0-init-container/instrumentation /__dash0__/instrumentation +ENV LD_PRELOAD=/__dash0__/dash0_injector.so \ No newline at end of file diff --git a/images/instrumentation/test/jvm/base-images b/images/instrumentation/test/jvm/base-images new file mode 100644 index 00000000..5aa00505 --- /dev/null +++ b/images/instrumentation/test/jvm/base-images @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: Copyright 2024 Dash0 Inc. +# SPDX-License-Identifier: Apache-2.0 + +# one base image per line +openjdk:24-jdk-bookworm +openjdk:21-jdk-bookworm +openjdk:17-jdk-bookworm diff --git a/images/instrumentation/test/jvm/test-cases/existing-unmodified/.env b/images/instrumentation/test/jvm/test-cases/existing-unmodified/.env new file mode 100644 index 00000000..3358d222 --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/existing-unmodified/.env @@ -0,0 +1,8 @@ +AN_ENVIRONMENT_VARIABLE=value +DASH0_NAMESPACE_NAME=namespace +DASH0_POD_UID=pod_uid +DASH0_POD_NAME=pod_name +DASH0_CONTAINER_NAME=container_name +OTEL_LOGS_EXPORTER=none +OTEL_METRICS_EXPORTER=none +OTEL_TRACES_EXPORTER=none \ No newline at end of file diff --git a/images/instrumentation/test/jvm/test-cases/existing-unmodified/.gitignore b/images/instrumentation/test/jvm/test-cases/existing-unmodified/.gitignore new file mode 100644 index 00000000..9c01d043 --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/existing-unmodified/.gitignore @@ -0,0 +1,10 @@ +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar \ No newline at end of file diff --git a/images/instrumentation/test/jvm/test-cases/existing-unmodified/.mvn/wrapper/maven-wrapper.properties b/images/instrumentation/test/jvm/test-cases/existing-unmodified/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..d58dfb70 --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/existing-unmodified/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +wrapperVersion=3.3.2 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/images/instrumentation/test/jvm/test-cases/existing-unmodified/mvnw b/images/instrumentation/test/jvm/test-cases/existing-unmodified/mvnw new file mode 100755 index 00000000..19529ddf --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/existing-unmodified/mvnw @@ -0,0 +1,259 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.3.2 +# +# Optional ENV vars +# ----------------- +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output +# ---------------------------------------------------------------------------- + +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x + +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac + +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/images/instrumentation/test/jvm/test-cases/existing-unmodified/pom.xml b/images/instrumentation/test/jvm/test-cases/existing-unmodified/pom.xml new file mode 100644 index 00000000..b0621897 --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/existing-unmodified/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.1 + + + com.dash0.injector + existing-unmodified-envvar-demo + 0.0.1-SNAPSHOT + existing-unmodified-envvar-demo + Test App for Dash0 injector + + 17 + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + + app + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/images/instrumentation/test/jvm/test-cases/existing-unmodified/src/main/java/com/dash0/injector/existing_envvar_demo/TestApplication.java b/images/instrumentation/test/jvm/test-cases/existing-unmodified/src/main/java/com/dash0/injector/existing_envvar_demo/TestApplication.java new file mode 100644 index 00000000..9efe5fed --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/existing-unmodified/src/main/java/com/dash0/injector/existing_envvar_demo/TestApplication.java @@ -0,0 +1,28 @@ +package com.dash0.injector.existing_envvar_demo; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; +import org.springframework.core.env.Environment; + +@SpringBootApplication +public class TestApplication { + + @Autowired + private Environment environment; + + @EventListener(ApplicationReadyEvent.class) + public void checkEnvVar() { + final String value = environment.getProperty("AN_ENVIRONMENT_VARIABLE"); + if (!"value".equals(value)) { + throw new RuntimeException(String.format("Unexpected value for the 'AN_ENVIRONMENT_VARIABLE' env var: %s", value)); + } + } + + public static void main(String[] args) { + SpringApplication.run(TestApplication.class, args); + } + +} diff --git a/images/instrumentation/test/jvm/test-cases/existing-unmodified/src/main/resources/application.properties b/images/instrumentation/test/jvm/test-cases/existing-unmodified/src/main/resources/application.properties new file mode 100644 index 00000000..3898fd08 --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/existing-unmodified/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.application.name=existing-envvar-demo diff --git a/images/instrumentation/test/jvm/test-cases/existing-unmodified/src/test/java/com/dash0/injector/existing_envvar_demo/TestApplicationTests.java b/images/instrumentation/test/jvm/test-cases/existing-unmodified/src/test/java/com/dash0/injector/existing_envvar_demo/TestApplicationTests.java new file mode 100644 index 00000000..bd889c10 --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/existing-unmodified/src/test/java/com/dash0/injector/existing_envvar_demo/TestApplicationTests.java @@ -0,0 +1,15 @@ +package com.dash0.injector.existing_envvar_demo; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; + +@SpringBootTest +@TestPropertySource(properties={"AN_ENVIRONMENT_VARIABLE=value"}) +class TestApplicationTests { + + @Test + void contextLoadSucceeds() { + } + +} diff --git a/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/.env b/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/.env new file mode 100644 index 00000000..0a9b1564 --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/.env @@ -0,0 +1,8 @@ +DASH0_NAMESPACE_NAME=namespace +DASH0_POD_UID=pod_uid +DASH0_POD_NAME=pod_name +DASH0_CONTAINER_NAME=container_name +OTEL_LOGS_EXPORTER=none +OTEL_METRICS_EXPORTER=none +OTEL_TRACES_EXPORTER=none +OTEL_RESOURCE_ATTRIBUTES=key1=value1,key2=value2 \ No newline at end of file diff --git a/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/.gitignore b/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/.gitignore new file mode 100644 index 00000000..9c01d043 --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/.gitignore @@ -0,0 +1,10 @@ +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar \ No newline at end of file diff --git a/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/.mvn/wrapper/maven-wrapper.properties b/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..d58dfb70 --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +wrapperVersion=3.3.2 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/mvnw b/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/mvnw new file mode 100755 index 00000000..19529ddf --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/mvnw @@ -0,0 +1,259 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.3.2 +# +# Optional ENV vars +# ----------------- +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output +# ---------------------------------------------------------------------------- + +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x + +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac + +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/pom.xml b/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/pom.xml new file mode 100644 index 00000000..93f66684 --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.1 + + + com.dash0.injector + otel-resource-attributes-already-set-demo + 0.0.1-SNAPSHOT + otel-resource-attributes-already-set-demo + Test App for Dash0 injector + + 17 + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + + app + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/src/main/java/com/dash0/injector/otel-resource-attributes-already-set/TestApplication.java b/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/src/main/java/com/dash0/injector/otel-resource-attributes-already-set/TestApplication.java new file mode 100644 index 00000000..91b771e7 --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/src/main/java/com/dash0/injector/otel-resource-attributes-already-set/TestApplication.java @@ -0,0 +1,30 @@ +package com.dash0.injector.existing_envvar_demo; + +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; +import org.springframework.core.env.Environment; + +@SpringBootApplication +public class TestApplication { + + @Autowired + private Environment environment; + + @EventListener(ApplicationReadyEvent.class) + public void checkEnvVar() { + final String value = environment.getProperty("OTEL_RESOURCE_ATTRIBUTES"); + if (!Optional.of(value).orElse("").contains("key1=value1,key2=value2")) { + throw new RuntimeException(String.format("Unexpected value for the 'OTEL_RESOURCE_ATTRIBUTES' env var: %s", value)); + } + } + + public static void main(String[] args) { + SpringApplication.run(TestApplication.class, args); + } + +} diff --git a/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/src/main/resources/application.properties b/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/src/main/resources/application.properties new file mode 100644 index 00000000..86357c48 --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.application.name=otel-resource-attributes-already-set-demo diff --git a/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/src/test/java/com/dash0/injector/otel-resource-attributes-already-set/TestApplicationTests.java b/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/src/test/java/com/dash0/injector/otel-resource-attributes-already-set/TestApplicationTests.java new file mode 100644 index 00000000..25b6426c --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/otel-resource-attributes-already-set/src/test/java/com/dash0/injector/otel-resource-attributes-already-set/TestApplicationTests.java @@ -0,0 +1,15 @@ +package com.dash0.injector.existing_envvar_demo; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; + +@SpringBootTest +@TestPropertySource(properties={"OTEL_RESOURCE_ATTRIBUTES=k8s.namespace.name=namespace,k8s.pod.name=pod_name,k8s.pod.uid=pod_uid,k8s.container.name=container_name,key1=value1,key2=value2"}) +class TestApplicationTests { + + @Test + void contextLoadSucceeds() { + } + +} diff --git a/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/.env b/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/.env new file mode 100644 index 00000000..acb01468 --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/.env @@ -0,0 +1,7 @@ +DASH0_NAMESPACE_NAME=namespace +DASH0_POD_UID=pod_uid +DASH0_POD_NAME=pod_name +DASH0_CONTAINER_NAME=container_name +OTEL_LOGS_EXPORTER=none +OTEL_METRICS_EXPORTER=none +OTEL_TRACES_EXPORTER=none \ No newline at end of file diff --git a/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/.gitignore b/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/.gitignore new file mode 100644 index 00000000..9c01d043 --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/.gitignore @@ -0,0 +1,10 @@ +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar \ No newline at end of file diff --git a/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/.mvn/wrapper/maven-wrapper.properties b/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..d58dfb70 --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +wrapperVersion=3.3.2 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/mvnw b/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/mvnw new file mode 100755 index 00000000..19529ddf --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/mvnw @@ -0,0 +1,259 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.3.2 +# +# Optional ENV vars +# ----------------- +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output +# ---------------------------------------------------------------------------- + +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x + +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac + +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/pom.xml b/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/pom.xml new file mode 100644 index 00000000..80942ef1 --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.1 + + + com.dash0.injector + undefined-envvar-demo + 0.0.1-SNAPSHOT + undefined-envvar-demo + Test App for Dash0 injector + + 17 + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + + app + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/src/main/java/com/dash0/injector/existing_envvar_demo/TestApplication.java b/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/src/main/java/com/dash0/injector/existing_envvar_demo/TestApplication.java new file mode 100644 index 00000000..f2c271c1 --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/src/main/java/com/dash0/injector/existing_envvar_demo/TestApplication.java @@ -0,0 +1,28 @@ +package com.dash0.injector.existing_envvar_demo; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; +import org.springframework.core.env.Environment; + +@SpringBootApplication +public class TestApplication { + + @Autowired + private Environment environment; + + @EventListener(ApplicationReadyEvent.class) + public void checkEnvVar() { + final String value = environment.getProperty("UNDEFINED_ENVIRONMENT_VARIABLE"); + if (value != null) { + throw new RuntimeException(String.format("Unexpected value for the 'UNDEFINED_ENVIRONMENT_VARIABLE' env var: %s", value)); + } + } + + public static void main(String[] args) { + SpringApplication.run(TestApplication.class, args); + } + +} diff --git a/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/src/test/java/com/dash0/injector/existing_envvar_demo/TestApplicationTests.java b/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/src/test/java/com/dash0/injector/existing_envvar_demo/TestApplicationTests.java new file mode 100644 index 00000000..a79bc26f --- /dev/null +++ b/images/instrumentation/test/jvm/test-cases/undefined-for-non-existing/src/test/java/com/dash0/injector/existing_envvar_demo/TestApplicationTests.java @@ -0,0 +1,13 @@ +package com.dash0.injector.existing_envvar_demo; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class TestApplicationTests { + + @Test + void contextLoadSucceeds() { + } + +} diff --git a/images/instrumentation/test/test-all.sh b/images/instrumentation/test/test-all.sh index f10e4ed7..cfd5d7c6 100755 --- a/images/instrumentation/test/test-all.sh +++ b/images/instrumentation/test/test-all.sh @@ -71,17 +71,22 @@ run_tests_for_runtime() { for t in "${script_dir}"/"${runtime}"/test-cases/*/ ; do test=$(basename "$(realpath "${t}")") - if docker_run_output=$(docker run \ + + if [ "${runtime}" = "jvm" ] && docker run \ + --env-file="${script_dir}/${runtime}/test-cases/${test}/.env" \ + "${image_name_test}" \ + java -jar "/test-cases/${test}/target/app.jar" \ + 2>&1; then + printf "${GREEN}test case \"${test}\": OK${NC}\n" + elif [ "${runtime}" = "node" ] && docker run \ --env-file="${script_dir}/${runtime}/test-cases/${test}/.env" \ "${image_name_test}" \ node "/test-cases/${test}" \ - 2>&1 - ); then + 2>&1; then printf "${GREEN}test case \"${test}\": OK${NC}\n" else printf "${RED}test case \"${test}\": FAIL\n" printf "test output:${NC}\n" - echo "$docker_run_output" exit_code=1 summary="$summary\n${runtime}/${base_image}\t- ${test}:\tfailed" fi @@ -115,18 +120,13 @@ run_tests_for_architecture() { echo "- base image: '${base_image}'" image_name_test="test-${runtime}-${arch}:latest" echo "building test image for ${arch}/${runtime}/${base_image} with instrumentation image ${instrumentation_image}" - if ! build_output=$( - docker build \ - --platform "$docker_platform" \ - --build-arg "instrumentation_image=${instrumentation_image}" \ - --build-arg "base_image=${base_image}" \ - "${script_dir}/${runtime}" \ - -t "$image_name_test" \ - 2>&1 - ); then - echo "${build_output}" - exit 1 - fi + docker build \ + --platform "$docker_platform" \ + --build-arg "instrumentation_image=${instrumentation_image}" \ + --build-arg "base_image=${base_image}" \ + "${script_dir}/${runtime}" \ + -t "$image_name_test" \ + 2>&1; run_tests_for_runtime "${runtime}" "$image_name_test" "$base_image" echo done diff --git a/internal/webhooks/instrumentation_webhook_test.go b/internal/webhooks/instrumentation_webhook_test.go index 346f70bb..125697cb 100644 --- a/internal/webhooks/instrumentation_webhook_test.go +++ b/internal/webhooks/instrumentation_webhook_test.go @@ -194,32 +194,36 @@ var _ = Describe("The Dash0 instrumentation webhook", func() { Dash0InitContainerIdx: 2, Containers: []ContainerExpectations{ { - VolumeMounts: 2, - Dash0VolumeMountIdx: 1, - EnvVars: 8, - LdPreloadEnvVarIdx: 1, - NodeIpIdx: 2, - Dash0CollectorBaseUrlEnvVarIdx: 3, - Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0NamespaceNameEnvVarIdx: 4, - Dash0PodNameEnvVarIdx: 5, - Dash0PodUidEnvVarIdx: 6, - Dash0ContainerNameEnvVarIdx: 7, - Dash0ContainerNameEnvVarExpectedValue: "test-container-0", + VolumeMounts: 2, + Dash0VolumeMountIdx: 1, + EnvVars: 9, + LdPreloadEnvVarIdx: 1, + Dash0NodeIpIdx: 2, + Dash0CollectorBaseUrlEnvVarIdx: 3, + Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, + OtelExporterOtlpEndpointEnvVarIdx: 4, + OtelExporterOtlpEndpointEnvVarExpectedValue: OTelCollectorBaseUrlTest, + Dash0NamespaceNameEnvVarIdx: 5, + Dash0PodNameEnvVarIdx: 6, + Dash0PodUidEnvVarIdx: 7, + Dash0ContainerNameEnvVarIdx: 8, + Dash0ContainerNameEnvVarExpectedValue: "test-container-0", }, { - VolumeMounts: 3, - Dash0VolumeMountIdx: 2, - EnvVars: 9, - LdPreloadEnvVarIdx: 2, - NodeIpIdx: 3, - Dash0CollectorBaseUrlEnvVarIdx: 4, - Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0NamespaceNameEnvVarIdx: 5, - Dash0PodNameEnvVarIdx: 6, - Dash0PodUidEnvVarIdx: 7, - Dash0ContainerNameEnvVarIdx: 8, - Dash0ContainerNameEnvVarExpectedValue: "test-container-1", + VolumeMounts: 3, + Dash0VolumeMountIdx: 2, + EnvVars: 10, + LdPreloadEnvVarIdx: 2, + Dash0NodeIpIdx: 3, + Dash0CollectorBaseUrlEnvVarIdx: 4, + Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, + OtelExporterOtlpEndpointEnvVarIdx: 5, + OtelExporterOtlpEndpointEnvVarExpectedValue: OTelCollectorBaseUrlTest, + Dash0NamespaceNameEnvVarIdx: 6, + Dash0PodNameEnvVarIdx: 7, + Dash0PodUidEnvVarIdx: 8, + Dash0ContainerNameEnvVarIdx: 9, + Dash0ContainerNameEnvVarExpectedValue: "test-container-1", }, }, }, @@ -244,34 +248,38 @@ var _ = Describe("The Dash0 instrumentation webhook", func() { Dash0InitContainerIdx: 1, Containers: []ContainerExpectations{ { - VolumeMounts: 2, - Dash0VolumeMountIdx: 1, - EnvVars: 8, - LdPreloadEnvVarIdx: 1, - LdPreloadUsesValueFrom: true, - NodeIpIdx: 2, - Dash0CollectorBaseUrlEnvVarIdx: 3, - Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0NamespaceNameEnvVarIdx: 4, - Dash0PodNameEnvVarIdx: 5, - Dash0PodUidEnvVarIdx: 6, - Dash0ContainerNameEnvVarIdx: 7, - Dash0ContainerNameEnvVarExpectedValue: "test-container-0", + VolumeMounts: 2, + Dash0VolumeMountIdx: 1, + EnvVars: 9, + LdPreloadEnvVarIdx: 1, + LdPreloadUsesValueFrom: true, + Dash0NodeIpIdx: 2, + Dash0CollectorBaseUrlEnvVarIdx: 3, + Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, + OtelExporterOtlpEndpointEnvVarIdx: 4, + OtelExporterOtlpEndpointEnvVarExpectedValue: OTelCollectorBaseUrlTest, + Dash0NamespaceNameEnvVarIdx: 5, + Dash0PodNameEnvVarIdx: 6, + Dash0PodUidEnvVarIdx: 7, + Dash0ContainerNameEnvVarIdx: 8, + Dash0ContainerNameEnvVarExpectedValue: "test-container-0", }, { - VolumeMounts: 3, - Dash0VolumeMountIdx: 1, - EnvVars: 8, - LdPreloadEnvVarIdx: 1, - LdPreloadValue: "/__dash0__/dash0_injector.so third_party_preload.so another_third_party_preload.so", - NodeIpIdx: 2, - Dash0CollectorBaseUrlEnvVarIdx: 0, - Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0NamespaceNameEnvVarIdx: 4, - Dash0PodNameEnvVarIdx: 5, - Dash0PodUidEnvVarIdx: 6, - Dash0ContainerNameEnvVarIdx: 7, - Dash0ContainerNameEnvVarExpectedValue: "test-container-1", + VolumeMounts: 3, + Dash0VolumeMountIdx: 1, + EnvVars: 9, + LdPreloadEnvVarIdx: 1, + LdPreloadValue: "/__dash0__/dash0_injector.so third_party_preload.so another_third_party_preload.so", + Dash0NodeIpIdx: 2, + Dash0CollectorBaseUrlEnvVarIdx: 4, + Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, + OtelExporterOtlpEndpointEnvVarIdx: 0, + OtelExporterOtlpEndpointEnvVarExpectedValue: OTelCollectorBaseUrlTest, + Dash0NamespaceNameEnvVarIdx: 5, + Dash0PodNameEnvVarIdx: 6, + Dash0PodUidEnvVarIdx: 7, + Dash0ContainerNameEnvVarIdx: 8, + Dash0ContainerNameEnvVarExpectedValue: "test-container-1", }, }, }, diff --git a/internal/workloads/workload_modifier.go b/internal/workloads/workload_modifier.go index a6f8409d..7eb0256f 100644 --- a/internal/workloads/workload_modifier.go +++ b/internal/workloads/workload_modifier.go @@ -24,18 +24,19 @@ import ( const ( initContainerName = "dash0-instrumentation" - dash0VolumeName = "dash0-instrumentation" - dash0DirectoryEnvVarName = "DASH0_INSTRUMENTATION_FOLDER_DESTINATION" - dash0InstrumentationBaseDirectory = "/__dash0__" - dash0InstrumentationDirectory = "/__dash0__/instrumentation" - envVarLdPreloadName = "LD_PRELOAD" - envVarLdPreloadValue = "/__dash0__/dash0_injector.so" - envVarDash0CollectorBaseUrlName = "DASH0_OTEL_COLLECTOR_BASE_URL" - envVarDash0NodeIp = "DASH0_NODE_IP" - envVarDash0NamespaceName = "DASH0_NAMESPACE_NAME" - envVarDash0PodName = "DASH0_POD_NAME" - envVarDash0PodUid = "DASH0_POD_UID" - envVarDash0ContainerName = "DASH0_CONTAINER_NAME" + dash0VolumeName = "dash0-instrumentation" + dash0DirectoryEnvVarName = "DASH0_INSTRUMENTATION_FOLDER_DESTINATION" + dash0InstrumentationBaseDirectory = "/__dash0__" + dash0InstrumentationDirectory = "/__dash0__/instrumentation" + envVarLdPreloadName = "LD_PRELOAD" + envVarLdPreloadValue = "/__dash0__/dash0_injector.so" + envVarOtelExporterOtlpEndpointName = "OTEL_EXPORTER_OTLP_ENDPOINT" + envVarDash0CollectorBaseUrlName = "DASH0_OTEL_COLLECTOR_BASE_URL" + envVarDash0NodeIp = "DASH0_NODE_IP" + envVarDash0NamespaceName = "DASH0_NAMESPACE_NAME" + envVarDash0PodName = "DASH0_POD_NAME" + envVarDash0PodUid = "DASH0_POD_UID" + envVarDash0ContainerName = "DASH0_CONTAINER_NAME" ) var ( @@ -281,6 +282,15 @@ func (m *ResourceModifier) addEnvironmentVariables(container *corev1.Container, }, ) + // Keep backwards compatibility with the Dash0 Node.js distro + m.addOrReplaceEnvironmentVariable( + container, + corev1.EnvVar{ + Name: envVarOtelExporterOtlpEndpointName, + Value: collectorBaseUrl, + }, + ) + m.addOrReplaceEnvironmentVariable( container, corev1.EnvVar{ @@ -476,6 +486,7 @@ func (m *ResourceModifier) removeEnvironmentVariables(container *corev1.Containe m.removeLdPreload(container) m.removeEnvironmentVariable(container, envVarDash0NodeIp) m.removeEnvironmentVariable(container, envVarDash0CollectorBaseUrlName) + m.removeEnvironmentVariable(container, envVarOtelExporterOtlpEndpointName) m.removeEnvironmentVariable(container, envVarDash0NamespaceName) m.removeEnvironmentVariable(container, envVarDash0PodName) m.removeEnvironmentVariable(container, envVarDash0PodUid) diff --git a/internal/workloads/workload_modifier_test.go b/internal/workloads/workload_modifier_test.go index 79ede4f9..104ab712 100644 --- a/internal/workloads/workload_modifier_test.go +++ b/internal/workloads/workload_modifier_test.go @@ -72,32 +72,36 @@ var _ = Describe("Dash0 Workload Modification", func() { Dash0InitContainerIdx: 2, Containers: []ContainerExpectations{ { - VolumeMounts: 2, - Dash0VolumeMountIdx: 1, - EnvVars: 8, - LdPreloadEnvVarIdx: 1, - NodeIpIdx: 2, - Dash0CollectorBaseUrlEnvVarIdx: 3, - Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0NamespaceNameEnvVarIdx: 4, - Dash0PodNameEnvVarIdx: 5, - Dash0PodUidEnvVarIdx: 6, - Dash0ContainerNameEnvVarIdx: 7, - Dash0ContainerNameEnvVarExpectedValue: "test-container-0", + VolumeMounts: 2, + Dash0VolumeMountIdx: 1, + EnvVars: 9, + LdPreloadEnvVarIdx: 1, + Dash0NodeIpIdx: 2, + Dash0CollectorBaseUrlEnvVarIdx: 3, + Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, + OtelExporterOtlpEndpointEnvVarIdx: 4, + OtelExporterOtlpEndpointEnvVarExpectedValue: OTelCollectorBaseUrlTest, + Dash0NamespaceNameEnvVarIdx: 5, + Dash0PodNameEnvVarIdx: 6, + Dash0PodUidEnvVarIdx: 7, + Dash0ContainerNameEnvVarIdx: 8, + Dash0ContainerNameEnvVarExpectedValue: "test-container-0", }, { - VolumeMounts: 3, - Dash0VolumeMountIdx: 2, - EnvVars: 9, - LdPreloadEnvVarIdx: 2, - NodeIpIdx: 3, - Dash0CollectorBaseUrlEnvVarIdx: 4, - Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0NamespaceNameEnvVarIdx: 5, - Dash0PodNameEnvVarIdx: 6, - Dash0PodUidEnvVarIdx: 7, - Dash0ContainerNameEnvVarIdx: 8, - Dash0ContainerNameEnvVarExpectedValue: "test-container-1", + VolumeMounts: 3, + Dash0VolumeMountIdx: 2, + EnvVars: 10, + LdPreloadEnvVarIdx: 2, + Dash0NodeIpIdx: 3, + Dash0CollectorBaseUrlEnvVarIdx: 4, + Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, + OtelExporterOtlpEndpointEnvVarIdx: 5, + OtelExporterOtlpEndpointEnvVarExpectedValue: OTelCollectorBaseUrlTest, + Dash0NamespaceNameEnvVarIdx: 6, + Dash0PodNameEnvVarIdx: 7, + Dash0PodUidEnvVarIdx: 8, + Dash0ContainerNameEnvVarIdx: 9, + Dash0ContainerNameEnvVarExpectedValue: "test-container-1", }, }, }, @@ -117,34 +121,38 @@ var _ = Describe("Dash0 Workload Modification", func() { Dash0InitContainerIdx: 1, Containers: []ContainerExpectations{ { - VolumeMounts: 2, - Dash0VolumeMountIdx: 1, - EnvVars: 8, - LdPreloadEnvVarIdx: 1, - LdPreloadUsesValueFrom: true, - NodeIpIdx: 2, - Dash0CollectorBaseUrlEnvVarIdx: 3, - Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0NamespaceNameEnvVarIdx: 4, - Dash0PodNameEnvVarIdx: 5, - Dash0PodUidEnvVarIdx: 6, - Dash0ContainerNameEnvVarIdx: 7, - Dash0ContainerNameEnvVarExpectedValue: "test-container-0", + VolumeMounts: 2, + Dash0VolumeMountIdx: 1, + EnvVars: 9, + LdPreloadEnvVarIdx: 1, + LdPreloadUsesValueFrom: true, + Dash0NodeIpIdx: 2, + Dash0CollectorBaseUrlEnvVarIdx: 3, + Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, + OtelExporterOtlpEndpointEnvVarIdx: 4, + OtelExporterOtlpEndpointEnvVarExpectedValue: OTelCollectorBaseUrlTest, + Dash0NamespaceNameEnvVarIdx: 5, + Dash0PodNameEnvVarIdx: 6, + Dash0PodUidEnvVarIdx: 7, + Dash0ContainerNameEnvVarIdx: 8, + Dash0ContainerNameEnvVarExpectedValue: "test-container-0", }, { - VolumeMounts: 3, - Dash0VolumeMountIdx: 1, - EnvVars: 8, - LdPreloadEnvVarIdx: 1, - LdPreloadValue: "/__dash0__/dash0_injector.so third_party_preload.so another_third_party_preload.so", - NodeIpIdx: 2, - Dash0CollectorBaseUrlEnvVarIdx: 0, - Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0NamespaceNameEnvVarIdx: 4, - Dash0PodNameEnvVarIdx: 5, - Dash0PodUidEnvVarIdx: 6, - Dash0ContainerNameEnvVarIdx: 7, - Dash0ContainerNameEnvVarExpectedValue: "test-container-1", + VolumeMounts: 3, + Dash0VolumeMountIdx: 1, + EnvVars: 9, + LdPreloadEnvVarIdx: 1, + LdPreloadValue: "/__dash0__/dash0_injector.so third_party_preload.so another_third_party_preload.so", + Dash0NodeIpIdx: 2, + Dash0CollectorBaseUrlEnvVarIdx: 4, + Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, + OtelExporterOtlpEndpointEnvVarIdx: 0, + OtelExporterOtlpEndpointEnvVarExpectedValue: OTelCollectorBaseUrlTest, + Dash0NamespaceNameEnvVarIdx: 5, + Dash0PodNameEnvVarIdx: 6, + Dash0PodUidEnvVarIdx: 7, + Dash0ContainerNameEnvVarIdx: 8, + Dash0ContainerNameEnvVarExpectedValue: "test-container-1", }, }, }, @@ -317,28 +325,30 @@ var _ = Describe("Dash0 Workload Modification", func() { Dash0InitContainerIdx: -1, Containers: []ContainerExpectations{ { - VolumeMounts: 1, - Dash0VolumeMountIdx: -1, - EnvVars: 1, - LdPreloadEnvVarIdx: -1, - NodeIpIdx: -1, - Dash0CollectorBaseUrlEnvVarIdx: -1, - Dash0NamespaceNameEnvVarIdx: -1, - Dash0PodNameEnvVarIdx: -1, - Dash0PodUidEnvVarIdx: -1, - Dash0ContainerNameEnvVarIdx: -1, + VolumeMounts: 1, + Dash0VolumeMountIdx: -1, + EnvVars: 1, + LdPreloadEnvVarIdx: -1, + Dash0NodeIpIdx: -1, + Dash0CollectorBaseUrlEnvVarIdx: -1, + OtelExporterOtlpEndpointEnvVarIdx: -1, + Dash0NamespaceNameEnvVarIdx: -1, + Dash0PodNameEnvVarIdx: -1, + Dash0PodUidEnvVarIdx: -1, + Dash0ContainerNameEnvVarIdx: -1, }, { - VolumeMounts: 2, - Dash0VolumeMountIdx: -1, - EnvVars: 2, - LdPreloadEnvVarIdx: -1, - NodeIpIdx: -1, - Dash0CollectorBaseUrlEnvVarIdx: -1, - Dash0NamespaceNameEnvVarIdx: -1, - Dash0PodNameEnvVarIdx: -1, - Dash0PodUidEnvVarIdx: -1, - Dash0ContainerNameEnvVarIdx: -1, + VolumeMounts: 2, + Dash0VolumeMountIdx: -1, + EnvVars: 2, + LdPreloadEnvVarIdx: -1, + Dash0NodeIpIdx: -1, + Dash0CollectorBaseUrlEnvVarIdx: -1, + OtelExporterOtlpEndpointEnvVarIdx: -1, + Dash0NamespaceNameEnvVarIdx: -1, + Dash0PodNameEnvVarIdx: -1, + Dash0PodUidEnvVarIdx: -1, + Dash0ContainerNameEnvVarIdx: -1, }, }, }) diff --git a/test-resources/customresources/dash0operatorconfiguration/dash0operatorconfiguration.secret.yaml b/test-resources/customresources/dash0operatorconfiguration/dash0operatorconfiguration.secret.yaml index a94c8c64..169f5da0 100644 --- a/test-resources/customresources/dash0operatorconfiguration/dash0operatorconfiguration.secret.yaml +++ b/test-resources/customresources/dash0operatorconfiguration/dash0operatorconfiguration.secret.yaml @@ -7,5 +7,7 @@ spec: dash0: endpoint: ingress.eu-west-1.aws.dash0-dev.com:4317 authorization: - secretRef: {} + secretRef: + name: dash0-authorization-secret + key: token apiEndpoint: https://api.eu-west-1.aws.dash0-dev.com diff --git a/test/util/resources.go b/test/util/resources.go index e1121bd0..d5d587ff 100644 --- a/test/util/resources.go +++ b/test/util/resources.go @@ -716,6 +716,11 @@ func DeploymentWithExistingDash0Artifacts(namespace string, name string) *appsv1 Name: "DASH0_OTEL_COLLECTOR_BASE_URL", ValueFrom: &corev1.EnvVarSource{FieldRef: &corev1.ObjectFieldSelector{FieldPath: "metadata.namespace"}}, }, + { + // this ValueFrom will be removed and replaced by a simple Value + Name: "OTEL_EXPORTER_OTLP_ENDPOINT", + ValueFrom: &corev1.EnvVarSource{FieldRef: &corev1.ObjectFieldSelector{FieldPath: "metadata.namespace"}}, + }, }, }, { @@ -737,7 +742,7 @@ func DeploymentWithExistingDash0Artifacts(namespace string, name string) *appsv1 }, Env: []corev1.EnvVar{ { - Name: "DASH0_OTEL_COLLECTOR_BASE_URL", + Name: "OTEL_EXPORTER_OTLP_ENDPOINT", Value: "base url will be replaced", }, { @@ -833,7 +838,7 @@ func InstrumentedDeploymentWithMoreBellsAndWhistles(namespace string, name strin ValueFrom: &corev1.EnvVarSource{FieldRef: &corev1.ObjectFieldSelector{FieldPath: "status.hostIP"}}, }, { - Name: "DASH0_OTEL_COLLECTOR_BASE_URL", + Name: "OTEL_EXPORTER_OTLP_ENDPOINT", Value: OTelCollectorBaseUrlTest, }, }, @@ -872,6 +877,10 @@ func InstrumentedDeploymentWithMoreBellsAndWhistles(namespace string, name strin Name: "DASH0_OTEL_COLLECTOR_BASE_URL", Value: OTelCollectorBaseUrlTest, }, + { + Name: "OTEL_EXPORTER_OTLP_ENDPOINT", + Value: OTelCollectorBaseUrlTest, + }, }, }, } @@ -916,6 +925,10 @@ func simulateInstrumentedPodSpec(podSpec *corev1.PodSpec, meta *metav1.ObjectMet Name: "DASH0_OTEL_COLLECTOR_BASE_URL", Value: OTelCollectorBaseUrlTest, }, + { + Name: "OTEL_EXPORTER_OTLP_ENDPOINT", + Value: OTelCollectorBaseUrlTest, + }, { Name: "DASH0_NAMESPACE_NAME", ValueFrom: &corev1.EnvVarSource{ @@ -1102,7 +1115,7 @@ func AddManagedFields(meta *metav1.ObjectMeta) { FieldsType: "FieldsV1", FieldsV1: &metav1.FieldsV1{ //nolint:lll - Raw: []byte(`{\"f:metadata\":{\"f:labels\":{\".\":{},\"f:dash0.com/init-container-image\":{},\"f:dash0.com/instrumented\":{},\"f:dash0.com/instrumented-by\":{},\"f:dash0.com/operator-image\":{}}},\"f:spec\":{\"f:template\":{\"f:metadata\":{\"f:labels\":{\"f:dash0.com/init-container-image\":{},\"f:dash0.com/instrumented\":{},\"f:dash0.com/instrumented-by\":{},\"f:dash0.com/operator-image\":{}}},\"f:spec\":{\"f:containers\":{\"k:{\\\"name\\\":\\\"test-container-0\\\"}\":{\"f:env\":{\".\":{},\"k:{\\\"name\\\":\\\"DASH0_NODE_IP\\\"}\":{\".\":{},\"f:name\":{},\"f:valueFrom\":{\".\":{},\"f:fieldRef\":{}}},\"k:{\\\"name\\\":\\\"DASH0_OTEL_COLLECTOR_BASE_URL\\\"}\":{\".\":{},\"f:name\":{},\"f:value\":{}},\"k:{\\\"name\\\":\\\"LD_PRELOAD\\\"}\":{\".\":{},\"f:name\":{},\"f:value\":{}}},\"f:volumeMounts\":{\".\":{},\"k:{\\\"mountPath\\\":\\\"/__dash0__\\\"}\":{\".\":{},\"f:mountPath\":{},\"f:name\":{}}}}},\"f:initContainers\":{\".\":{},\"k:{\\\"name\\\":\\\"dash0-instrumentation\\\"}\":{\".\":{},\"f:env\":{\".\":{},\"k:{\\\"name\\\":\\\"DASH0_INSTRUMENTATION_FOLDER_DESTINATION\\\"}\":{\".\":{},\"f:name\":{},\"f:value\":{}}},\"f:image\":{},\"f:imagePullPolicy\":{},\"f:name\":{},\"f:resources\":{},\"f:securityContext\":{\".\":{},\"f:allowPrivilegeEscalation\":{},\"f:privileged\":{},\"f:readOnlyRootFilesystem\":{},\"f:runAsGroup\":{},\"f:runAsUser\":{}},\"f:terminationMessagePath\":{},\"f:terminationMessagePolicy\":{},\"f:volumeMounts\":{\".\":{},\"k:{\\\"mountPath\\\":\\\"/__dash0__\\\"}\":{\".\":{},\"f:mountPath\":{},\"f:name\":{}}}}},\"f:volumes\":{\".\":{},\"k:{\\\"name\\\":\\\"dash0-instrumentation\\\"}\":{\".\":{},\"f:emptyDir\":{\".\":{},\"f:sizeLimit\":{}},\"f:name\":{}}}}}}}`), + Raw: []byte(`{\"f:metadata\":{\"f:labels\":{\".\":{},\"f:dash0.com/init-container-image\":{},\"f:dash0.com/instrumented\":{},\"f:dash0.com/instrumented-by\":{},\"f:dash0.com/operator-image\":{}}},\"f:spec\":{\"f:template\":{\"f:metadata\":{\"f:labels\":{\"f:dash0.com/init-container-image\":{},\"f:dash0.com/instrumented\":{},\"f:dash0.com/instrumented-by\":{},\"f:dash0.com/operator-image\":{}}},\"f:spec\":{\"f:containers\":{\"k:{\\\"name\\\":\\\"test-container-0\\\"}\":{\"f:env\":{\".\":{},\"k:{\\\"name\\\":\\\"DASH0_NODE_IP\\\"}\":{\".\":{},\"f:name\":{},\"f:valueFrom\":{\".\":{},\"f:fieldRef\":{}}},\"k:{\\\"name\\\":\\\"OTEL_EXPORTER_OTLP_ENDPOINT\\\"}\":{\".\":{},\"f:name\":{},\"f:value\":{}},\"k:{\\\"name\\\":\\\"LD_PRELOAD\\\"}\":{\".\":{},\"f:name\":{},\"f:value\":{}}},\"f:volumeMounts\":{\".\":{},\"k:{\\\"mountPath\\\":\\\"/__dash0__\\\"}\":{\".\":{},\"f:mountPath\":{},\"f:name\":{}}}}},\"f:initContainers\":{\".\":{},\"k:{\\\"name\\\":\\\"dash0-instrumentation\\\"}\":{\".\":{},\"f:env\":{\".\":{},\"k:{\\\"name\\\":\\\"DASH0_INSTRUMENTATION_FOLDER_DESTINATION\\\"}\":{\".\":{},\"f:name\":{},\"f:value\":{}}},\"f:image\":{},\"f:imagePullPolicy\":{},\"f:name\":{},\"f:resources\":{},\"f:securityContext\":{\".\":{},\"f:allowPrivilegeEscalation\":{},\"f:privileged\":{},\"f:readOnlyRootFilesystem\":{},\"f:runAsGroup\":{},\"f:runAsUser\":{}},\"f:terminationMessagePath\":{},\"f:terminationMessagePolicy\":{},\"f:volumeMounts\":{\".\":{},\"k:{\\\"mountPath\\\":\\\"/__dash0__\\\"}\":{\".\":{},\"f:mountPath\":{},\"f:name\":{}}}}},\"f:volumes\":{\".\":{},\"k:{\\\"name\\\":\\\"dash0-instrumentation\\\"}\":{\".\":{},\"f:emptyDir\":{\".\":{},\"f:sizeLimit\":{}},\"f:name\":{}}}}}}}`), }, }) } diff --git a/test/util/verification.go b/test/util/verification.go index 7c5d9e13..ec7aa6d7 100644 --- a/test/util/verification.go +++ b/test/util/verification.go @@ -21,20 +21,22 @@ import ( ) type ContainerExpectations struct { - VolumeMounts int - Dash0VolumeMountIdx int - EnvVars int - LdPreloadEnvVarIdx int - LdPreloadValue string - LdPreloadUsesValueFrom bool - NodeIpIdx int - Dash0CollectorBaseUrlEnvVarIdx int - Dash0CollectorBaseUrlEnvVarExpectedValue string - Dash0NamespaceNameEnvVarIdx int - Dash0PodNameEnvVarIdx int - Dash0PodUidEnvVarIdx int - Dash0ContainerNameEnvVarIdx int - Dash0ContainerNameEnvVarExpectedValue string + VolumeMounts int + Dash0VolumeMountIdx int + EnvVars int + LdPreloadEnvVarIdx int + LdPreloadValue string + LdPreloadUsesValueFrom bool + Dash0NodeIpIdx int + OtelExporterOtlpEndpointEnvVarIdx int + OtelExporterOtlpEndpointEnvVarExpectedValue string + Dash0CollectorBaseUrlEnvVarIdx int + Dash0CollectorBaseUrlEnvVarExpectedValue string + Dash0NamespaceNameEnvVarIdx int + Dash0PodNameEnvVarIdx int + Dash0PodUidEnvVarIdx int + Dash0ContainerNameEnvVarIdx int + Dash0ContainerNameEnvVarExpectedValue string } type PodSpecExpectations struct { @@ -75,18 +77,20 @@ func BasicInstrumentedPodSpecExpectations() PodSpecExpectations { InitContainers: 1, Dash0InitContainerIdx: 0, Containers: []ContainerExpectations{{ - VolumeMounts: 1, - Dash0VolumeMountIdx: 0, - EnvVars: 7, - LdPreloadEnvVarIdx: 0, - NodeIpIdx: 1, - Dash0CollectorBaseUrlEnvVarIdx: 2, - Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, - Dash0NamespaceNameEnvVarIdx: 3, - Dash0PodNameEnvVarIdx: 4, - Dash0PodUidEnvVarIdx: 5, - Dash0ContainerNameEnvVarIdx: 6, - Dash0ContainerNameEnvVarExpectedValue: "test-container-0", + VolumeMounts: 1, + Dash0VolumeMountIdx: 0, + EnvVars: 8, + LdPreloadEnvVarIdx: 0, + Dash0NodeIpIdx: 1, + Dash0CollectorBaseUrlEnvVarIdx: 2, + Dash0CollectorBaseUrlEnvVarExpectedValue: OTelCollectorBaseUrlTest, + OtelExporterOtlpEndpointEnvVarIdx: 3, + OtelExporterOtlpEndpointEnvVarExpectedValue: OTelCollectorBaseUrlTest, + Dash0NamespaceNameEnvVarIdx: 4, + Dash0PodNameEnvVarIdx: 5, + Dash0PodUidEnvVarIdx: 6, + Dash0ContainerNameEnvVarIdx: 7, + Dash0ContainerNameEnvVarExpectedValue: "test-container-0", }}, } } @@ -303,7 +307,7 @@ func verifyPodSpec(podSpec corev1.PodSpec, expectations PodSpecExpectations) { "/__dash0__/dash0_injector.so", )) } - } else if j == containerExpectations.NodeIpIdx { + } else if j == containerExpectations.Dash0NodeIpIdx { Expect(envVar.Name).To(Equal("DASH0_NODE_IP")) valueFrom := envVar.ValueFrom Expect(valueFrom).ToNot(BeNil()) @@ -314,6 +318,10 @@ 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.OtelExporterOtlpEndpointEnvVarIdx { + Expect(envVar.Name).To(Equal("OTEL_EXPORTER_OTLP_ENDPOINT")) + Expect(envVar.Value).To(Equal(containerExpectations.OtelExporterOtlpEndpointEnvVarExpectedValue)) + 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"))