From dcccac616cc463f24d215a24de7602640c154e76 Mon Sep 17 00:00:00 2001 From: jeffreyc-splunk Date: Mon, 14 Aug 2023 09:44:48 -0400 Subject: [PATCH] Add systemd sample file to splunk-otel-auto-instrumention --- .github/workflows/auto-instrumentation.yml | 178 +++++++----- instrumentation/README.md | 231 ++++----------- instrumentation/libsplunk.md | 181 ++++++++++++ instrumentation/packaging/fpm/common.sh | 17 +- instrumentation/packaging/fpm/deb/build.sh | 1 - .../systemd/00-splunk-otel-javaagent.conf | 37 +++ instrumentation/packaging/fpm/postinstall.sh | 37 --- instrumentation/packaging/fpm/rpm/build.sh | 1 - instrumentation/systemd.md | 95 ++++++ .../packaging/tests/helpers/util.py | 21 +- .../tests/instrumentation/__init__.py | 0 .../tests/instrumentation/config.yaml | 25 ++ .../images/deb/Dockerfile.debian-bullseye | 31 ++ .../images/deb/Dockerfile.debian-buster | 31 ++ .../images/deb/Dockerfile.debian-stretch | 34 +++ .../images/deb/Dockerfile.ubuntu-bionic | 31 ++ .../images/deb/Dockerfile.ubuntu-focal | 31 ++ .../images/deb/Dockerfile.ubuntu-jammy | 31 ++ .../images/deb/Dockerfile.ubuntu-xenial | 31 ++ .../images/rpm/Dockerfile.amazonlinux-2 | 27 ++ .../images/rpm/Dockerfile.amazonlinux-2023 | 27 ++ .../images/rpm/Dockerfile.centos-7 | 28 ++ .../images/rpm/Dockerfile.centos-8 | 28 ++ .../images/rpm/Dockerfile.centos-9 | 29 ++ .../images/rpm/Dockerfile.opensuse-12 | 29 ++ .../images/rpm/Dockerfile.opensuse-15 | 27 ++ .../images/rpm/Dockerfile.oraclelinux-7 | 27 ++ .../images/rpm/Dockerfile.oraclelinux-8 | 27 ++ .../images/rpm/Dockerfile.oraclelinux-9 | 27 ++ .../instrumentation/instrumentation_test.py | 275 ++++++++++++++++++ .../tests/instrumentation/libsplunk-test.conf | 7 + .../tests/instrumentation/setup-tomcat.sh | 38 +++ .../tests/instrumentation/systemd-test.conf | 6 + .../packaging/tests/requirements.txt | 1 + 34 files changed, 1339 insertions(+), 308 deletions(-) create mode 100644 instrumentation/libsplunk.md create mode 100644 instrumentation/packaging/fpm/examples/systemd/00-splunk-otel-javaagent.conf delete mode 100644 instrumentation/packaging/fpm/postinstall.sh create mode 100644 instrumentation/systemd.md create mode 100644 internal/buildscripts/packaging/tests/instrumentation/__init__.py create mode 100755 internal/buildscripts/packaging/tests/instrumentation/config.yaml create mode 100644 internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-bullseye create mode 100644 internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-buster create mode 100644 internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-stretch create mode 100644 internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-bionic create mode 100644 internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-focal create mode 100644 internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-jammy create mode 100644 internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-xenial create mode 100644 internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.amazonlinux-2 create mode 100644 internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.amazonlinux-2023 create mode 100644 internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-7 create mode 100644 internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-8 create mode 100644 internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-9 create mode 100644 internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.opensuse-12 create mode 100644 internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.opensuse-15 create mode 100644 internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-7 create mode 100644 internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-8 create mode 100644 internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-9 create mode 100644 internal/buildscripts/packaging/tests/instrumentation/instrumentation_test.py create mode 100644 internal/buildscripts/packaging/tests/instrumentation/libsplunk-test.conf create mode 100644 internal/buildscripts/packaging/tests/instrumentation/setup-tomcat.sh create mode 100644 internal/buildscripts/packaging/tests/instrumentation/systemd-test.conf diff --git a/.github/workflows/auto-instrumentation.yml b/.github/workflows/auto-instrumentation.yml index c8c891f813..d7c7a847d0 100644 --- a/.github/workflows/auto-instrumentation.yml +++ b/.github/workflows/auto-instrumentation.yml @@ -8,43 +8,51 @@ on: paths: - '.github/workflows/auto-instrumentation.yml' - 'instrumentation/**' + - 'internal/buildscripts/packaging/tests/helpers/**' + - 'internal/buildscripts/packaging/tests/instrumentation/**' + - 'internal/buildscripts/packaging/tests/requirements.txt' + - '!**.md' concurrency: group: auto-instrumentation-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true +env: + PYTHON_VERSION: '3.10' + PIP_VERSION: '22.0.4' + REQUIREMENTS_PATH: "internal/buildscripts/packaging/tests/requirements.txt" + GO_VERSION: 1.20.6 + jobs: - libsplunk: + cross-compile: # Use 20.04.5 until https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/16450 is resolved runs-on: ubuntu-20.04 strategy: matrix: - ARCH: [ "amd64", "arm64" ] + SYS_BINARIES: [ "binaries-linux_amd64", "binaries-linux_arm64" ] steps: - name: Check out the codebase. uses: actions/checkout@v3 - - name: Set up QEMU - if: ${{ matrix.ARCH == 'arm64' }} - uses: docker/setup-qemu-action@v2 + - name: Set up Go + uses: actions/setup-go@v4 with: - platforms: arm64 - image: tonistiigi/binfmt:qemu-v7.0.0 + go-version: ${{ env.GO_VERSION }} + cache-dependency-path: '**/go.sum' - - name: Build libsplunk.so - run: make -C instrumentation dist ARCH=${{ matrix.ARCH }} + - name: Build Collector + run: | + make ${{ matrix.SYS_BINARIES }} - - name: Upload artifact + - name: Uploading binaries uses: actions/upload-artifact@v3 with: - name: libsplunk-${{ matrix.ARCH }} - path: ./instrumentation/dist/libsplunk_${{ matrix.ARCH }}.so + name: ${{ matrix.SYS_BINARIES }} + path: | + ./bin/* - build-package: - name: build-package - # Use 20.04.5 until https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/16450 is resolved + instrumentation-package: runs-on: ubuntu-20.04 - needs: [libsplunk] strategy: matrix: SYS_PACKAGE: [ "deb", "rpm" ] @@ -55,86 +63,106 @@ jobs: with: fetch-depth: 0 - - name: Downloading libsplunk-${{ matrix.ARCH }} - uses: actions/download-artifact@v3 + - uses: docker/setup-qemu-action@v2 + if: ${{ matrix.ARCH != 'amd64' }} with: - name: libsplunk-${{ matrix.ARCH }} - path: ./instrumentation/dist + platforms: ${{ matrix.ARCH }} + image: tonistiigi/binfmt:qemu-v7.0.0 - - name: Build ${{ matrix.SYS_PACKAGE }} ${{ matrix.ARCH }} package - run: | - gitRef=(${GITHUB_REF//// }) - if [[ "${gitRef[1]}" = "tags" ]] ; - then - echo "TAG_NAME=${gitRef[2]}" >> $GITHUB_ENV - else - echo "TAG_NAME=" >> $GITHUB_ENV - fi - make -C instrumentation ${{ matrix.SYS_PACKAGE }}-package SKIP_COMPILE=true VERSION="${TAG_NAME:-}" ARCH="${{ matrix.ARCH }}" + - name: Build ${{ matrix.ARCH }} ${{ matrix.SYS_PACKAGE }} package + run: make -C instrumentation/ ${{ matrix.SYS_PACKAGE }}-package ARCH="${{ matrix.ARCH }}" - name: Upload artifact uses: actions/upload-artifact@v3 with: name: splunk-otel-auto-instrumentation-${{ matrix.ARCH }}-${{ matrix.SYS_PACKAGE }} - path: ./instrumentation/dist/splunk-otel-auto-instrumentation*.${{ matrix.SYS_PACKAGE }} + path: ./instrumentation/dist/*.${{ matrix.SYS_PACKAGE }} - test-deb-package: - name: test-deb-package - # Use 20.04.5 until https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/16450 is resolved + test-instrumentation-matrix: runs-on: ubuntu-20.04 - needs: [build-package] - strategy: - matrix: - DISTRO: [ "debian:8", "debian:9", "debian:10", "ubuntu:16.04", "ubuntu:18.04", "ubuntu:20.04" ] - ARCH: [ "amd64", "arm64" ] - exclude: - - DISTRO: debian:8 - ARCH: arm64 steps: - - name: Check out the codebase. + - name: Check out code uses: actions/checkout@v3 - - name: Downloading splunk-otel-auto-instrumentation-${{ matrix.ARCH }}-deb - uses: actions/download-artifact@v3 - with: - name: splunk-otel-auto-instrumentation-${{ matrix.ARCH }}-deb - path: ./instrumentation/dist - - - name: Set up QEMU - if: ${{ matrix.ARCH == 'arm64' }} - uses: docker/setup-qemu-action@v2 - with: - platforms: arm64 - image: tonistiigi/binfmt:qemu-v7.0.0 - - - name: Test - run: docker run --platform linux/${{ matrix.ARCH }} --rm -v $(pwd):/repo -w /repo ${{ matrix.DISTRO }} /repo/instrumentation/packaging/fpm/test.sh deb ${{ matrix.ARCH }} - - test-rpm-package: - name: test-rpm-package + - name: Get matrix + id: get-matrix + run: | + # create test matrix for distro and arch + dockerfiles=$(find internal/buildscripts/packaging/tests/instrumentation/images/ -name "Dockerfile.*" | cut -d '.' -f2- | sort -u) + if [ -z "$dockerfiles" ]; then + echo "Failed to get dockerfiles from internal/buildscripts/packaging/tests/instrumentation/images!" >&2 + exit 1 + fi + distro=$(for d in $dockerfiles; do echo -n "\"$d\","; done) + arch="\"amd64\", \"arm64\"" + matrix="{\"DISTRO\": [${distro%,}], \"ARCH\": [${arch}]}" + echo "$matrix" | jq + echo "matrix=${matrix}" >> $GITHUB_OUTPUT + outputs: + matrix: ${{ steps.get-matrix.outputs.matrix }} + + test-instrumentation-package: # Use 20.04.5 until https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/16450 is resolved - runs-on: ubuntu-20.04 - needs: [build-package] + runs-on: ${{ fromJSON('["ubuntu-20.04", "ubuntu-22.04"]')[matrix.DISTRO == 'amazonlinux-2023'] }} + timeout-minutes: 60 + needs: [cross-compile, instrumentation-package, test-instrumentation-matrix] strategy: - matrix: - DISTRO: [ "centos:7", "centos:8", "amazonlinux:2", "opensuse/leap:42", "opensuse/leap:15", "oraclelinux:7", "oraclelinux:8" ] - ARCH: [ "amd64", "arm64" ] + matrix: ${{ fromJSON(needs.test-instrumentation-matrix.outputs.matrix) }} + fail-fast: false steps: - name: Check out the codebase. uses: actions/checkout@v3 - - name: Downloading splunk-otel-auto-instrumentation-${{ matrix.ARCH }}-rpm - uses: actions/download-artifact@v3 + - name: Get package type for ${{ matrix.DISTRO }} + run: | + for pkg in "deb" "rpm"; do + if [[ -f "internal/buildscripts/packaging/tests/instrumentation/images/${pkg}/Dockerfile.${{ matrix.DISTRO }}" ]]; then + echo "SYS_PACKAGE=${pkg}" >> $GITHUB_ENV + exit 0 + fi + done + echo "Unknown distro '${{ matrix.DISTRO }}'!" + exit 1 + + - uses: actions/download-artifact@v3 + with: + name: binaries-linux_${{ matrix.ARCH }} + path: ./bin + + - uses: actions/download-artifact@v3 with: - name: splunk-otel-auto-instrumentation-${{ matrix.ARCH }}-rpm + name: splunk-otel-auto-instrumentation-${{ matrix.ARCH }}-${{ env.SYS_PACKAGE }} path: ./instrumentation/dist - - name: Set up QEMU - if: ${{ matrix.ARCH == 'arm64'}} - uses: docker/setup-qemu-action@v2 + - uses: docker/setup-qemu-action@v2 + if: ${{ matrix.ARCH != 'amd64' }} with: - platforms: arm64 + platforms: ${{ matrix.ARCH }} image: tonistiigi/binfmt:qemu-v7.0.0 - - name: Test - run: docker run --platform linux/${{ matrix.ARCH }} --rm -v $(pwd):/repo -w /repo ${{ matrix.DISTRO }} /repo/instrumentation/packaging/fpm/test.sh rpm ${{ matrix.ARCH }} + - name: Setup python + uses: actions/setup-python@v4 + with: + python-version: ${{ env.PYTHON_VERSION }} + cache: 'pip' + cache-dependency-path: ${{ env.REQUIREMENTS_PATH }} + + - name: Install pytest + run: | + if which pip; then + pip install --upgrade 'pip==${{ env.PIP_VERSION }}' + else + curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py + python get-pip.py 'pip==${{ env.PIP_VERSION }}' + fi + pip install -r "${{ env.REQUIREMENTS_PATH }}" + + - name: Test ${{ env.SYS_PACKAGE }} on ${{ matrix.DISTRO }} ${{ matrix.ARCH }} + run: | + distro="${{ matrix.DISTRO }}" + if [[ "$distro" = "amazonlinux-2" ]]; then + # workaround for pytest substring matching + distro="amazonlinux-2 and not amazonlinux-2023" + fi + python3 -u -m pytest -sx --verbose -k "$distro and ${{ matrix.ARCH }}" \ + internal/buildscripts/packaging/tests/instrumentation/instrumentation_test.py diff --git a/instrumentation/README.md b/instrumentation/README.md index fc6604f7c2..8d5cd857e9 100644 --- a/instrumentation/README.md +++ b/instrumentation/README.md @@ -1,181 +1,50 @@ -# Linux Java Auto Instrumentation - -This directory contains functionality to automatically instrument your local Java applications so that they capture and -report distributed traces to Splunk APM. - -## Operation - -This directory contains functionality for building a Linux .so (shared object) file, which, in conjunction with a -reference to that file in -`/etc/ld.so.preload` (provided by an installer defined elsewhere) causes processes on the host to run this .so before -the main executable runs. If the executable that's starting is not named `java`, the .so quits silently and the -executable starts normally. Otherwise, it attempts to set environment variables that will cause the -[Splunk OTel Java JAR](https://github.com/signalfx/splunk-otel-java) (also provided by the installer) to instrument the -soon-to-be running Java application. In this way, all Java applications on the host will be automatically instrumented -by the Splunk OTel Java agent. - -Once instrumented, Java executables send traces to a locally running -[Splunk Open Telemetry Collector](https://github.com/signalfx/splunk-otel-collector) -(installed separately) and then on to Splunk APM. - -## Configuration File - -At startup, the shared object reads the config file, `/usr/lib/splunk-instrumentation/instrumentation.conf` which by -default, looks like this: - -``` -java_agent_jar=/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar -``` - -The `java_agent_jar` parameter is set to the default location of the agent jar. - -### Supported parameters - -#### `java_agent_jar` (required) - -The full path to the auto instrumentation JAR (provided by the installer). - -#### `service_name` (optional) - -This is an optional override for the service name that would otherwise be generated by the shared object before Java -startup. By default, this line is commented out, but can be uncommented to override the generated name. If this -parameter is set, all instrumented Java applications on this host will have the specified service name (via the -OTEL_SERVICE_NAME environment variable). If this override is set and `generate_service_name` is also explicitly set to -`false`, that parameter will win, and the service name will not be set. - -#### `resource_attributes` (optional -- typically set by the installer script) - -This value, if present, should contain a list of name-value pairs (separated by `=`s and pairs separated by `,`s) to -which the .so will set the OTEL_RESOURCE_ATTRIBUTES environment variable. The OTEL_RESOURCE_ATTRIBUTES environment -variable will then be picked up by the Java instrumentation jar. Typically, it will be set to something like: - -`resource_attributes=deployment.environment=test` - -to set the deployment environment for the Splunk backend. - -#### `disable_telemetry` (optional) - -Set this value to `true` to disable the preloader from sending the `splunk.linux-autoinstr.executions` metric to the -local collector. Default: `false`. - -#### `generate_service_name` (optional) - -Set this value to `false` to prevent the preloader from setting the `OTEL_SERVICE_NAME` environment variable. If this -value is `false`, the preloader will not set `OTEL_SERVICE_NAME`, and the soon-to-be running Java instrumentation -library will attempt to set it instead (in the future, this will be the default behavior). Default: `true`. - -#### `enable_profiler` (optional) - -Set this value to `true` to pass `-Dsplunk.profiler.enabled=true` to the starting Java executable, which will enable -[AlwaysOn CPU Profiling](https://docs.splunk.com/Observability/apm/profiling/get-data-in-profiling.html). -Default: `false`. - -#### `enable_profiler_memory` (optional) - -Set this value to `true` to pass `-Dsplunk.profiler.memory.enabled=true` to the starting Java executable, which will -enable -[AlwaysOn Memory Profiling](https://docs.splunk.com/Observability/apm/profiling/get-data-in-profiling.html). -Default: `false`. - -#### `enable_metrics` (optional) - -Set this value to `true` to pass `-Dsplunk.metrics.enabled=true` to the starting Java executable, which will enable -[exporting metrics](https://github.com/signalfx/splunk-otel-java/blob/main/docs/metrics.md). Default: `false`. - -### Syntax - -To add a comment or comment out a line, start it with a `#`. - -Not supported (and unnecessary) are: - -* Quoting of any kind -* Whitespace on either side of the equals sign -* Leading whitespace - -### Environment Variables - -The way the .so causes a Java executable to be instrumented is by setting the environment variables, JAVA_TOOL_OPTIONS -and OTEL_SERVICE_NAME, and optionally, OTEL_RESOURCE_ATTRIBUTES. - -#### JAVA_TOOL_OPTIONS - -This environment variable contains a `-javaagent` flag set to the full path of the Splunk OTel Java JAR. - -e.g. `JAVA_TOOL_OPTIONS='-javaagent:/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar'` - -This variable is populated by the .so by concatenating the `java_agent_jar` attribute in the config to a `-javaagent:` -prefix, and then appending any additional system properties specified in the configuration file. - -#### OTEL_SERVICE_NAME - -This environment variable sets the service name for the soon-to-be running Java application, usually derived from the -arguments of the Java executable (can be overridden via the config). - -This variable is set directly from the `service_name` attribute in the config. - -_Meta: link to docs about how service name is used and why it's required._ - -#### OTEL_RESOURCE_ATTRIBUTES - -This environment variable contains a list of name-value pairs (separated by `=`s) passed on to the Java instrumentation -jar. - -This variable is set directly from the optional `resource_attributes` attribute in the config. - -##### Service Name Generation - -The OTEL_SERVICE_NAME environment variable is set to a value that the .so generates from the arguments passed to the -Java executable. The .so does this by reading the arguments to the Java application from left to right, ignoring -arguments that look like flags (that start with a `-`), and reading arguments containing `.jar`, splitting those on `:`, -then on `/`, removing known path parts such as `usr`, `local`, etc., truncating the `.jar` extension, replacing dots -with dashes, removing segments, and concatenating the result with dashes. If while scanning the arguments, it finds a -main class name, it just returns the main class name with dots replaced with dashes and caps to lowercase, otherwise, -it returns the munged jar names. - -For example, the following command: - -``` -/usr/bin/java -jar app/petclinic/spring-petclinic-2.4.5.jar -``` - -produces a service name of: - -``` -app-petclinic-spring-2.4.5 -``` - -The following, more complex command: - -``` -java -Djava.util.logging.config.file=\ -/usr/local/apache-tomcat/8.5.4/conf/logging.properties \ --Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager \ --Djdk.tls.ephemeralDHKeySize=2048 \ --classpath \ -/usr/local/apache-tomcat/8.5.4/bin/bootstrap.jar:\ -/usr/local/apache-tomcat/8.5.4/bin/tomcat-juli.jar \ --Dcatalina.base=/usr/local/apache-tomcat/8.5.4 \ --Dcatalina.home=/usr/local/apache-tomcat/8.5.4 \ --Djava.io.tmpdir=/usr/local/apache-tomcat/8.5.4/temp \ -org.apache.catalina.startup.Bootstrap start -``` - -produces a service name of: - -``` -org-apache-catalina-startup-bootstrap -``` - -## Disabling - -Short of uninstalling the package, there are a few safe ways of disabling auto instrumentation - -* Set `DISABLE_SPLUNK_AUTOINSTRUMENTATION` to any non-empty value other than false, FALSE, or 0 -* Set `JAVA_TOOL_OPTIONS` to some value that you want the JVM to pick up -* Delete or move the config `instrumentation.conf` file - -## Files - -* /usr/lib/splunk-instrumentation/libsplunk.so -* /usr/lib/splunk-instrumentation/instrumentation.conf -* /usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar +# Splunk OpenTelemetry Zero Configuration Auto Instrumentation for Linux + +**Splunk OpenTelemetry Zero Configuration Auto Instrumentation for Linux** (`splunk-otel-auto-instrumentation`) +Debian/RPM package installs Splunk OpenTelemetry Auto Instrumentation agent(s), the `libsplunk.so` shared object +library, and sample configuration files to automatically instrument applications and services to capture and report +distributed traces and metrics to the [Splunk OpenTelemetry Collector]( +https://docs.splunk.com/Observability/gdi/opentelemetry/opentelemetry.html), and then on to [Splunk APM]( +https://docs.splunk.com/Observability/apm/intro-to-apm.html). + +Currently, `splunk-otel-auto-instrumentation` installs and supports configuration of the following Auto Instrumentation +agent(s): + +- [Java](https://docs.splunk.com/Observability/gdi/get-data-in/application/java/get-started.html) + +## Prerequisites/Requirements + +- Check agent compatibility and requirements: + - [Java](https://docs.splunk.com/Observability/gdi/get-data-in/application/java/java-otel-requirements.html) +- [Install and configure](https://docs.splunk.com/Observability/gdi/opentelemetry/install-linux.html) the Splunk + OpenTelemetry Collector. +- Debian or RPM based Linux distribution (amd64/x86_64 or arm64/aarch64). + +## Zero Configuration Options + +The following options are supported to enable the installed Auto Instrumentation agent(s): + +- **[`libsplunk.so`](./libsplunk.md)**: The provided `/usr/lib/splunk-instrumentation/libsplunk.so` shared object + library can be added to the `/etc/ld.so.preload` file to enable and configure Auto Instrumentation for ***all*** + supported processes on the system, or it can be assigned to the `LD_PRELOAD` environment variable for specific + applications/services. Configuration of the installed agent(s) is supported by the + [`/usr/lib/splunk-instrumentation/instrumentation.conf`](./libsplunk.md#configuration-file) file. + +- **[`systemd`](./systemd.md)**: The provided `systemd` drop-in file(s) in the + `/usr/lib/splunk-instrumentation/examples/systemd/` directory can be copied to the host's `systemd` configuration + directory, e.g. `/usr/lib/systemd/system.conf.d/`, to enable and configure Auto Instrumentation for ***all*** + supported applications running as `systemd` services. Configuration of the installed agent(s) is supported by + modifying these files or adding custom drop-in files with the desired environment variables. + +Alternatively, [manually install and configure]( +https://docs.splunk.com/Observability/gdi/get-data-in/application/application.html) +Auto Instrumentation if neither option is appropriate for the target host or application. + +> ### Notes +> +> 1. To prevent conflicts and duplicate traces/metrics, only one option should be enabled on the target system. +> 2. The configuration files and the options defined within are only applicable for the respective option that is +> configured. For example, `/usr/lib/splunk-instrumentation/instrumentation.conf` is only applicable with +> `libsplunk.so`, and the systemd drop-in file is not applicable for `libsplunk.so`. +> 3. The [`splunk.linux-autoinstr.executions`](./libsplunk.md#disable_telemetry-optional) telemetry +> metric is currently only provided with `libsplunk.so`. diff --git a/instrumentation/libsplunk.md b/instrumentation/libsplunk.md new file mode 100644 index 0000000000..fc6604f7c2 --- /dev/null +++ b/instrumentation/libsplunk.md @@ -0,0 +1,181 @@ +# Linux Java Auto Instrumentation + +This directory contains functionality to automatically instrument your local Java applications so that they capture and +report distributed traces to Splunk APM. + +## Operation + +This directory contains functionality for building a Linux .so (shared object) file, which, in conjunction with a +reference to that file in +`/etc/ld.so.preload` (provided by an installer defined elsewhere) causes processes on the host to run this .so before +the main executable runs. If the executable that's starting is not named `java`, the .so quits silently and the +executable starts normally. Otherwise, it attempts to set environment variables that will cause the +[Splunk OTel Java JAR](https://github.com/signalfx/splunk-otel-java) (also provided by the installer) to instrument the +soon-to-be running Java application. In this way, all Java applications on the host will be automatically instrumented +by the Splunk OTel Java agent. + +Once instrumented, Java executables send traces to a locally running +[Splunk Open Telemetry Collector](https://github.com/signalfx/splunk-otel-collector) +(installed separately) and then on to Splunk APM. + +## Configuration File + +At startup, the shared object reads the config file, `/usr/lib/splunk-instrumentation/instrumentation.conf` which by +default, looks like this: + +``` +java_agent_jar=/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar +``` + +The `java_agent_jar` parameter is set to the default location of the agent jar. + +### Supported parameters + +#### `java_agent_jar` (required) + +The full path to the auto instrumentation JAR (provided by the installer). + +#### `service_name` (optional) + +This is an optional override for the service name that would otherwise be generated by the shared object before Java +startup. By default, this line is commented out, but can be uncommented to override the generated name. If this +parameter is set, all instrumented Java applications on this host will have the specified service name (via the +OTEL_SERVICE_NAME environment variable). If this override is set and `generate_service_name` is also explicitly set to +`false`, that parameter will win, and the service name will not be set. + +#### `resource_attributes` (optional -- typically set by the installer script) + +This value, if present, should contain a list of name-value pairs (separated by `=`s and pairs separated by `,`s) to +which the .so will set the OTEL_RESOURCE_ATTRIBUTES environment variable. The OTEL_RESOURCE_ATTRIBUTES environment +variable will then be picked up by the Java instrumentation jar. Typically, it will be set to something like: + +`resource_attributes=deployment.environment=test` + +to set the deployment environment for the Splunk backend. + +#### `disable_telemetry` (optional) + +Set this value to `true` to disable the preloader from sending the `splunk.linux-autoinstr.executions` metric to the +local collector. Default: `false`. + +#### `generate_service_name` (optional) + +Set this value to `false` to prevent the preloader from setting the `OTEL_SERVICE_NAME` environment variable. If this +value is `false`, the preloader will not set `OTEL_SERVICE_NAME`, and the soon-to-be running Java instrumentation +library will attempt to set it instead (in the future, this will be the default behavior). Default: `true`. + +#### `enable_profiler` (optional) + +Set this value to `true` to pass `-Dsplunk.profiler.enabled=true` to the starting Java executable, which will enable +[AlwaysOn CPU Profiling](https://docs.splunk.com/Observability/apm/profiling/get-data-in-profiling.html). +Default: `false`. + +#### `enable_profiler_memory` (optional) + +Set this value to `true` to pass `-Dsplunk.profiler.memory.enabled=true` to the starting Java executable, which will +enable +[AlwaysOn Memory Profiling](https://docs.splunk.com/Observability/apm/profiling/get-data-in-profiling.html). +Default: `false`. + +#### `enable_metrics` (optional) + +Set this value to `true` to pass `-Dsplunk.metrics.enabled=true` to the starting Java executable, which will enable +[exporting metrics](https://github.com/signalfx/splunk-otel-java/blob/main/docs/metrics.md). Default: `false`. + +### Syntax + +To add a comment or comment out a line, start it with a `#`. + +Not supported (and unnecessary) are: + +* Quoting of any kind +* Whitespace on either side of the equals sign +* Leading whitespace + +### Environment Variables + +The way the .so causes a Java executable to be instrumented is by setting the environment variables, JAVA_TOOL_OPTIONS +and OTEL_SERVICE_NAME, and optionally, OTEL_RESOURCE_ATTRIBUTES. + +#### JAVA_TOOL_OPTIONS + +This environment variable contains a `-javaagent` flag set to the full path of the Splunk OTel Java JAR. + +e.g. `JAVA_TOOL_OPTIONS='-javaagent:/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar'` + +This variable is populated by the .so by concatenating the `java_agent_jar` attribute in the config to a `-javaagent:` +prefix, and then appending any additional system properties specified in the configuration file. + +#### OTEL_SERVICE_NAME + +This environment variable sets the service name for the soon-to-be running Java application, usually derived from the +arguments of the Java executable (can be overridden via the config). + +This variable is set directly from the `service_name` attribute in the config. + +_Meta: link to docs about how service name is used and why it's required._ + +#### OTEL_RESOURCE_ATTRIBUTES + +This environment variable contains a list of name-value pairs (separated by `=`s) passed on to the Java instrumentation +jar. + +This variable is set directly from the optional `resource_attributes` attribute in the config. + +##### Service Name Generation + +The OTEL_SERVICE_NAME environment variable is set to a value that the .so generates from the arguments passed to the +Java executable. The .so does this by reading the arguments to the Java application from left to right, ignoring +arguments that look like flags (that start with a `-`), and reading arguments containing `.jar`, splitting those on `:`, +then on `/`, removing known path parts such as `usr`, `local`, etc., truncating the `.jar` extension, replacing dots +with dashes, removing segments, and concatenating the result with dashes. If while scanning the arguments, it finds a +main class name, it just returns the main class name with dots replaced with dashes and caps to lowercase, otherwise, +it returns the munged jar names. + +For example, the following command: + +``` +/usr/bin/java -jar app/petclinic/spring-petclinic-2.4.5.jar +``` + +produces a service name of: + +``` +app-petclinic-spring-2.4.5 +``` + +The following, more complex command: + +``` +java -Djava.util.logging.config.file=\ +/usr/local/apache-tomcat/8.5.4/conf/logging.properties \ +-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager \ +-Djdk.tls.ephemeralDHKeySize=2048 \ +-classpath \ +/usr/local/apache-tomcat/8.5.4/bin/bootstrap.jar:\ +/usr/local/apache-tomcat/8.5.4/bin/tomcat-juli.jar \ +-Dcatalina.base=/usr/local/apache-tomcat/8.5.4 \ +-Dcatalina.home=/usr/local/apache-tomcat/8.5.4 \ +-Djava.io.tmpdir=/usr/local/apache-tomcat/8.5.4/temp \ +org.apache.catalina.startup.Bootstrap start +``` + +produces a service name of: + +``` +org-apache-catalina-startup-bootstrap +``` + +## Disabling + +Short of uninstalling the package, there are a few safe ways of disabling auto instrumentation + +* Set `DISABLE_SPLUNK_AUTOINSTRUMENTATION` to any non-empty value other than false, FALSE, or 0 +* Set `JAVA_TOOL_OPTIONS` to some value that you want the JVM to pick up +* Delete or move the config `instrumentation.conf` file + +## Files + +* /usr/lib/splunk-instrumentation/libsplunk.so +* /usr/lib/splunk-instrumentation/instrumentation.conf +* /usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar diff --git a/instrumentation/packaging/fpm/common.sh b/instrumentation/packaging/fpm/common.sh index 4080931ec2..3d3d4d2696 100644 --- a/instrumentation/packaging/fpm/common.sh +++ b/instrumentation/packaging/fpm/common.sh @@ -24,16 +24,18 @@ PKG_DESCRIPTION="Splunk OpenTelemetry Auto Instrumentation" PKG_LICENSE="Apache 2.0" PKG_URL="https://github.com/signalfx/splunk-otel-collector" -LIBSPLUNK_INSTALL_PATH="/usr/lib/splunk-instrumentation/libsplunk.so" -JAVA_AGENT_INSTALL_PATH="/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar" -CONFIG_INSTALL_PATH="/usr/lib/splunk-instrumentation/instrumentation.conf" +INSTALL_DIR="/usr/lib/splunk-instrumentation" +LIBSPLUNK_INSTALL_PATH="${INSTALL_DIR}/libsplunk.so" +JAVA_AGENT_INSTALL_PATH="${INSTALL_DIR}/splunk-otel-javaagent.jar" +CONFIG_INSTALL_PATH="${INSTALL_DIR}/instrumentation.conf" +CONFIG_PATH="$REPO_DIR/instrumentation/install/instrumentation.conf" +EXAMPLES_INSTALL_DIR="${INSTALL_DIR}/examples" +EXAMPLES_DIR="${FPM_DIR}/examples" JAVA_AGENT_RELEASE_PATH="${FPM_DIR}/../java-agent-release.txt" JAVA_AGENT_RELEASE_URL="https://github.com/signalfx/splunk-otel-java/releases/" -POSTINSTALL_PATH="$FPM_DIR/postinstall.sh" PREUNINSTALL_PATH="$FPM_DIR/preuninstall.sh" -CONFIG_PATH="$REPO_DIR/instrumentation/install/instrumentation.conf" get_version() { commit_tag="$( git -C "$REPO_DIR" describe --abbrev=0 --tags --exact-match --match 'v[0-9]*' 2>/dev/null || true )" @@ -83,4 +85,9 @@ setup_files_and_permissions() { cp -f "$CONFIG_PATH" "$buildroot/$CONFIG_INSTALL_PATH" sudo chown root:root "$buildroot/$CONFIG_INSTALL_PATH" sudo chmod 644 "$buildroot/$CONFIG_INSTALL_PATH" + + mkdir -p "$buildroot/$INSTALL_DIR" + cp -rf "$EXAMPLES_DIR" "$buildroot/$INSTALL_DIR/" + sudo chown -R root:root "$buildroot/$EXAMPLES_INSTALL_DIR" + sudo chmod -R 644 "$buildroot/$EXAMPLES_INSTALL_DIR" } diff --git a/instrumentation/packaging/fpm/deb/build.sh b/instrumentation/packaging/fpm/deb/build.sh index 457c2ac9aa..587f602f5c 100755 --- a/instrumentation/packaging/fpm/deb/build.sh +++ b/instrumentation/packaging/fpm/deb/build.sh @@ -48,7 +48,6 @@ sudo fpm -s dir -t deb -n "$PKG_NAME" -v "$VERSION" -f -p "$OUTPUT_DIR" \ --architecture "$ARCH" \ --deb-dist "stable" \ --deb-use-file-permissions \ - --after-install "$POSTINSTALL_PATH" \ --before-remove "$PREUNINSTALL_PATH" \ --deb-no-default-config-files \ --depends sed \ diff --git a/instrumentation/packaging/fpm/examples/systemd/00-splunk-otel-javaagent.conf b/instrumentation/packaging/fpm/examples/systemd/00-splunk-otel-javaagent.conf new file mode 100644 index 0000000000..9a16c133e0 --- /dev/null +++ b/instrumentation/packaging/fpm/examples/systemd/00-splunk-otel-javaagent.conf @@ -0,0 +1,37 @@ +# Copyright Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Sample systemd drop-in file to define the default environment variables for Splunk OpenTelemetry Auto Instrumentation for Java + +# To use this file to enable/configure auto instrumentation for all Java applications running as systemd services (requires root privileges): +# 1. See https://docs.splunk.com/Observability/gdi/get-data-in/application/java/configuration/advanced-java-otel-configuration.html +# for supported environment variables and defaults for the Java agent +# 2. Add/Update the DefaultEnvironment entries below for the desired environment variables and values +# 3. Copy this file to the systemd configuration directory, e.g. /usr/lib/systemd/system.conf.d +# 4. Reboot the system or run the following commands to restart the applicable service(s) for any changes to take effect: +# $ sudo systemctl daemon-reload +# $ sudo systemctl restart # replace "" and run for each applicable service + +# See https://www.freedesktop.org/software/systemd/man/systemd-system.conf.html for general information +# about systemd configuration and supported options. + +[Manager] +# Required to enable the Splunk OpenTelemetry Auto Instrumentation for Java agent +DefaultEnvironment="JAVA_TOOL_OPTIONS=-javaagent:/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar" + +# Examples of common configuration options: +#DefaultEnvironment="OTEL_EXPORTER_OTLP_ENDPOINT=http://1.2.3.4:5678" +#DefaultEnvironment="OTEL_RESOURCE_ATTRIBUTES=deployment.environment=my_deployment_environment" +#DefaultEnvironment="OTEL_SERVICE_NAME=my_service_name" +#DefaultEnvironment="SPLUNK_PROFILER_ENABLED=true" diff --git a/instrumentation/packaging/fpm/postinstall.sh b/instrumentation/packaging/fpm/postinstall.sh deleted file mode 100644 index d935680009..0000000000 --- a/instrumentation/packaging/fpm/postinstall.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -# Copyright Splunk Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -PRELOAD_PATH="/etc/ld.so.preload" -LIBSPLUNK_PATH="/usr/lib/splunk-instrumentation/libsplunk.so" - -if [ -f "$PRELOAD_PATH" ]; then - if ! grep -q "$LIBSPLUNK_PATH" "$PRELOAD_PATH"; then - # backup existing file with timestamp - if command -v rpm >/dev/null 2>&1; then - # need to escape '%' for rpm macros - ts="$(date '+%%Y%%m%%d-%%H%%M%%S')" - else - ts="$(date '+%Y%m%d-%H%M%S')" - fi - echo "Saving $PRELOAD_PATH as ${PRELOAD_PATH}.bak.${ts}" - cp "$PRELOAD_PATH" "${PRELOAD_PATH}.bak.${ts}" - echo "Adding $LIBSPLUNK_PATH to $PRELOAD_PATH" - echo "$LIBSPLUNK_PATH" >> "$PRELOAD_PATH" - fi -else - echo "Adding $LIBSPLUNK_PATH to $PRELOAD_PATH" - echo "$LIBSPLUNK_PATH" >> "$PRELOAD_PATH" -fi diff --git a/instrumentation/packaging/fpm/rpm/build.sh b/instrumentation/packaging/fpm/rpm/build.sh index 6bfc96e621..1066dc2c9d 100755 --- a/instrumentation/packaging/fpm/rpm/build.sh +++ b/instrumentation/packaging/fpm/rpm/build.sh @@ -58,7 +58,6 @@ sudo fpm -s dir -t rpm -n "$PKG_NAME" -v "$VERSION" -f -p "$OUTPUT_DIR" \ --rpm-rpmbuild-define "_build_id_links none" \ --rpm-summary "$PKG_DESCRIPTION" \ --rpm-use-file-permissions \ - --rpm-posttrans "$POSTINSTALL_PATH" \ --before-remove "$PREUNINSTALL_PATH" \ --depends sed \ --depends grep \ diff --git a/instrumentation/systemd.md b/instrumentation/systemd.md new file mode 100644 index 0000000000..15633b6e47 --- /dev/null +++ b/instrumentation/systemd.md @@ -0,0 +1,95 @@ +# Splunk OpenTelemetry Zero Configuration Auto Instrumentation for Systemd + +The `splunk-otel-auto-instrumentation` Debian/RPM package provides examples of drop-in file(s) that can be copied to the +host's `systemd` configuration directory to activate/configure Auto Instrumentation agent(s) for supported applications +running as `systemd` services by defining default environment variables. + +## Manual Systemd Configuration + +> `systemd` supports many options, methods, and paths for configuring environment variables at the system level or for +> individual services, and are not limited to the examples below. Before making any changes, it is recommended to +> consult the documentation specific to your Linux distribution or service, and check the existing configuration of the +> system or individual services for potential conflicts. For general details about `systemd`, see the +> [`systemd` man page](https://www.freedesktop.org/software/systemd/man/index.html). + +### Java Auto Instrumentation ### + +See the [Advanced Configuration Guide]( +https://docs.splunk.com/Observability/gdi/get-data-in/application/java/configuration/advanced-java-otel-configuration.html) +for details about supported options and defaults for the Java agent. These options can be configured via environment +variables or their corresponding system properties. + +#### Configuration Priority #### + +The Java agent can consume configuration options from one or more of the following sources (ordered from highest to +lowest priority): +1. Java system properties (`-D` flags) passed directly to the agent. For example, + ```shell + JAVA_TOOL_OPTIONS="-javaagent:/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar -Dotel.service.name=my-service" + ``` +2. Environment variables +3. Property files + +See [Configuring the agent]( +https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/#configuring-the-agent) for more +information. + +#### Quick Start #### + +The [`/usr/lib/splunk-instrumentation/examples/systemd/00-splunk-otel-javaagent.conf`]( +packaging/fpm/examples/systemd/00-splunk-otel-javaagent.conf) example drop-in file defines the following environment variable: + +- `JAVA_TOOL_OPTIONS=-javaagent:/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar` + +To activate the Java agent and its default configuration for ***all*** Java applications running as `systemd` services, +copy this file to the host's `systemd` configuration directory, e.g. `/usr/lib/systemd/system.conf.d/`, and +reboot the system or run the following commands to restart the applicable services for the changes to take effect +(requires `root` privileges): + ```shell + $ systemctl daemon-reload + $ systemctl restart # replace "" and run for each applicable service + ``` + +#### Configuration #### + +To configure the Java agent, add/modify/override [supported environment variables]( +https://docs.splunk.com/Observability/gdi/get-data-in/application/java/configuration/advanced-java-otel-configuration.html) +within `/usr/lib/systemd/system.conf.d/00-splunk-otel-javaagent.conf` (requires `root` privileges): + +1. **Option A**: Add/Update `DefaultEnvironment` within `/usr/lib/systemd/system.conf.d/00-splunk-otel-javaagent.conf` + for the desired environment variables. For example: + ```shell + $ cat < /usr/lib/systemd/system.conf.d/00-splunk-otel-javaagent.conf + [Manager] + DefaultEnvironment="JAVA_TOOL_OPTIONS=-javaagent:/my/custom/splunk-otel-javaagent.jar -Dotel.service.name=my-service" + DefaultEnvironment="OTEL_RESOURCE_ATTRIBUTES=myattrubute1=value1,myattribute2=value2" + DefaultEnvironment="SPLUNK_PROFILER_ENABLED=true" + EOH + ``` + **Option B**: Create/Modify a higher-priority drop-in file for ***all*** services to add or override the environment + variables defined in `/usr/lib/systemd/system.conf.d/00-splunk-otel-javaagent.conf`. For example: + ```shell + $ cat <> /usr/lib/systemd/system.conf.d/99-my-custom-env-vars.conf + [Manager] + DefaultEnvironment="JAVA_TOOL_OPTIONS=-javaagent:/my/custom/splunk-otel-javaagent.jar -Dotel.service.name=my-service" + DefaultEnvironment="OTEL_RESOURCE_ATTRIBUTES=myattrubute1=value1,myattribute2=value2" + DefaultEnvironment="SPLUNK_PROFILER_ENABLED=true" + EOH + ``` + **Option C**: Create/Modify a higher-priority drop-in file for a ***specific*** service to add or override the + environment variables defined in `/usr/lib/systemd/system.conf.d/00-splunk-otel-javaagent.conf`. For + example: + ```shell + $ cat <> /usr/lib/systemd/system/my-service.d/99-my-custom-env-vars.conf + [Service] + Environment="JAVA_TOOL_OPTIONS=-javaagent:/my/custom/splunk-otel-javaagent.jar -Dotel.service.name=my-service" + Environment="OTEL_RESOURCE_ATTRIBUTES=myattrubute1=value1,myattribute2=value2" + Environment="SPLUNK_PROFILER_ENABLED=true" + EOH + ``` +2. After any configuration changes, reboot the system or run the following commands to restart the applicable services + for the changes to take effect: + ```shell + $ systemctl daemon-reload + $ systemctl restart # replace "" and run for each applicable service + ``` diff --git a/internal/buildscripts/packaging/tests/helpers/util.py b/internal/buildscripts/packaging/tests/helpers/util.py index cfad62f47d..7ba9809e06 100644 --- a/internal/buildscripts/packaging/tests/helpers/util.py +++ b/internal/buildscripts/packaging/tests/helpers/util.py @@ -42,6 +42,18 @@ def retry(function, exception, max_attempts=5, interval=5): time.sleep(interval) +def wait_for_container_cmd(container, cmd, timeout=DEFAULT_TIMEOUT): + start_time = time.time() + while True: + code, output = container.exec_run(cmd) + elapsed = time.time() - start_time + if code == 0: + print(f"'{cmd}' completed in {elapsed}s:\n{output.decode('utf-8')}") + return code, output + assert elapsed < timeout, f"timed out waiting for '{cmd}':\n{output.decode('utf-8')}" + time.sleep(1) + + @contextmanager def run_distro_container(distro, arch="amd64", dockerfile=None, path=TESTS_DIR, buildargs=None, timeout=DEFAULT_TIMEOUT): client = docker.from_env() @@ -98,14 +110,7 @@ def run_distro_container(distro, arch="amd64", dockerfile=None, path=TESTS_DIR, time.sleep(1) # qemu is slow, so wait for systemd to be ready - start_time = time.time() - while True: - code, output = container.exec_run("systemctl list-units --no-pager") - if code == 0: - break - output = output.decode("utf-8").strip() - assert (time.time() - start_time) < timeout, f"timed out waiting for systemd to start: {output}" - time.sleep(1) + wait_for_container_cmd(container, "systemctl show-environment", timeout=timeout) yield container finally: diff --git a/internal/buildscripts/packaging/tests/instrumentation/__init__.py b/internal/buildscripts/packaging/tests/instrumentation/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/internal/buildscripts/packaging/tests/instrumentation/config.yaml b/internal/buildscripts/packaging/tests/instrumentation/config.yaml new file mode 100755 index 0000000000..30fac53b0f --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/config.yaml @@ -0,0 +1,25 @@ +receivers: + signalfx: + endpoint: 0.0.0.0:9943 + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + http: + endpoint: 0.0.0.0:4318 + +exporters: + logging: + verbosity: detailed + +service: + pipelines: + metrics: + receivers: [signalfx, otlp] + exporters: [logging] + logs: + receivers: [otlp] + exporters: [logging] + traces: + receivers: [otlp] + exporters: [logging] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-bullseye b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-bullseye new file mode 100644 index 0000000000..8530d48181 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-bullseye @@ -0,0 +1,31 @@ +# A debian image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM debian:bullseye + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update &&\ + apt-get install -yq ca-certificates curl procps systemd wget + +ENV container docker +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +RUN systemctl set-default multi-user.target +ENV init /lib/systemd/systemd + +VOLUME [ "/sys/fs/cgroup" ] + +ENTRYPOINT ["/lib/systemd/systemd"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-buster b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-buster new file mode 100644 index 0000000000..05c8048a59 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-buster @@ -0,0 +1,31 @@ +# A debian image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM debian:buster + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update &&\ + apt-get install -yq ca-certificates curl procps systemd wget + +ENV container docker +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +RUN systemctl set-default multi-user.target +ENV init /lib/systemd/systemd + +VOLUME [ "/sys/fs/cgroup" ] + +ENTRYPOINT ["/lib/systemd/systemd"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-stretch b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-stretch new file mode 100644 index 0000000000..f59f75bc35 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.debian-stretch @@ -0,0 +1,34 @@ +# A debian image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM debian:stretch + +ENV DEBIAN_FRONTEND noninteractive + +RUN sed -i 's|http://.*.debian.org|http://archive.debian.org|' /etc/apt/sources.list +RUN sed -i '/stretch-updates/d' /etc/apt/sources.list + +RUN apt-get update &&\ + apt-get install -yq ca-certificates curl procps systemd wget + +ENV container docker +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +RUN systemctl set-default multi-user.target +ENV init /lib/systemd/systemd + +VOLUME [ "/sys/fs/cgroup" ] + +ENTRYPOINT ["/lib/systemd/systemd"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-bionic b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-bionic new file mode 100644 index 0000000000..460acf9d7a --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-bionic @@ -0,0 +1,31 @@ +# A ubuntu image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM ubuntu:bionic + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update &&\ + apt-get install -yq ca-certificates curl procps systemd wget + +ENV container docker +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +RUN systemctl set-default multi-user.target +ENV init /lib/systemd/systemd + +VOLUME [ "/sys/fs/cgroup" ] + +ENTRYPOINT ["/lib/systemd/systemd"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-focal b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-focal new file mode 100644 index 0000000000..f817229087 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-focal @@ -0,0 +1,31 @@ +# A ubuntu image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM ubuntu:focal + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update &&\ + apt-get install -yq ca-certificates curl procps systemd wget + +ENV container docker +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +RUN systemctl set-default multi-user.target +ENV init /lib/systemd/systemd + +VOLUME [ "/sys/fs/cgroup" ] + +ENTRYPOINT ["/lib/systemd/systemd"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-jammy b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-jammy new file mode 100644 index 0000000000..a4fd8f72bc --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-jammy @@ -0,0 +1,31 @@ +# A ubuntu image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM ubuntu:jammy + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update &&\ + apt-get install -yq ca-certificates curl procps systemd wget + +ENV container docker +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +RUN systemctl set-default multi-user.target +ENV init /lib/systemd/systemd + +VOLUME [ "/sys/fs/cgroup" ] + +ENTRYPOINT ["/lib/systemd/systemd"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-xenial b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-xenial new file mode 100644 index 0000000000..8629c6f1a1 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/deb/Dockerfile.ubuntu-xenial @@ -0,0 +1,31 @@ +# A ubuntu image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM ubuntu:xenial + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update &&\ + apt-get install -yq ca-certificates curl procps systemd wget + +ENV container docker +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +RUN systemctl set-default multi-user.target +ENV init /lib/systemd/systemd + +VOLUME [ "/sys/fs/cgroup" ] + +ENTRYPOINT ["/lib/systemd/systemd"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.amazonlinux-2 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.amazonlinux-2 new file mode 100644 index 0000000000..4d73204d67 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.amazonlinux-2 @@ -0,0 +1,27 @@ +# A amazonlinux2 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM amazonlinux:2 + +ENV container docker + +RUN yum install -y curl procps initscripts systemd wget tar + +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/basic.target.wants/*;\ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/usr/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.amazonlinux-2023 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.amazonlinux-2023 new file mode 100644 index 0000000000..b21df31625 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.amazonlinux-2023 @@ -0,0 +1,27 @@ +# A amazonlinux2023 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM amazonlinux:2023 + +ENV container docker + +RUN yum install -y procps initscripts systemd systemd-udev wget tar + +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/basic.target.wants/*;\ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/usr/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-7 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-7 new file mode 100644 index 0000000000..ee582c7aef --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-7 @@ -0,0 +1,28 @@ +# A centos7 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM centos:7 + +ENV container docker + +RUN echo 'fastestmirror=1' >> /etc/yum.conf +RUN yum install -y curl procps initscripts systemd wget + +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/basic.target.wants/*;\ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/usr/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-8 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-8 new file mode 100644 index 0000000000..8984412744 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-8 @@ -0,0 +1,28 @@ +# A centos8 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM quay.io/centos/centos:stream8 + +ENV container docker + +RUN echo 'fastestmirror=1' >> /etc/yum.conf +RUN dnf install -y procps initscripts systemd wget + +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/basic.target.wants/*;\ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/usr/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-9 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-9 new file mode 100644 index 0000000000..b30564af9e --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.centos-9 @@ -0,0 +1,29 @@ +# A centos9 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM quay.io/centos/centos:stream9 + +ENV container docker + +RUN rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +RUN echo 'fastestmirror=1' >> /etc/yum.conf +RUN dnf install -y procps initscripts systemd wget + +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/basic.target.wants/*;\ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/usr/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.opensuse-12 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.opensuse-12 new file mode 100644 index 0000000000..e3e2bf0818 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.opensuse-12 @@ -0,0 +1,29 @@ +# A opensuse12 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM opensuse/leap:42 + +ENV container docker + +RUN sed -i 's|download.opensuse.org|ftp5.gwdg.de/pub/opensuse/discontinued|' /etc/zypp/repos.d/*.repo +RUN zypper -n clean && zypper -n refresh +RUN zypper -n install -l curl dbus-1 gzip procps systemd-sysvinit tar wget + +RUN (cd /usr/lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /usr/lib/systemd/system/multi-user.target.wants/*;\ + rm -f /usr/lib/systemd/system/local-fs.target.wants/*; \ + rm -f /usr/lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /usr/lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /usr/lib/systemd/system/basic.target.wants/*;\ + rm -f /usr/lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.opensuse-15 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.opensuse-15 new file mode 100644 index 0000000000..ffd5264656 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.opensuse-15 @@ -0,0 +1,27 @@ +# A opensuse15 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM opensuse/leap:15 + +ENV container docker + +RUN sed -i 's|download.opensuse.org|provo-mirror.opensuse.org|' /etc/zypp/repos.d/*.repo +RUN zypper -n install -l curl dbus-1 gzip systemd-sysvinit tar wget + +RUN (cd /usr/lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /usr/lib/systemd/system/multi-user.target.wants/*;\ + rm -f /usr/lib/systemd/system/local-fs.target.wants/*; \ + rm -f /usr/lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /usr/lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /usr/lib/systemd/system/basic.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-7 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-7 new file mode 100644 index 0000000000..b303c1df36 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-7 @@ -0,0 +1,27 @@ +# A oraclelinux7 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM oraclelinux:7 + +ENV container docker + +RUN yum install -y curl procps initscripts systemd wget + +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/basic.target.wants/*;\ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/usr/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-8 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-8 new file mode 100644 index 0000000000..358209afa1 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-8 @@ -0,0 +1,27 @@ +# A oraclelinux8 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM oraclelinux:8 + +ENV container docker + +RUN dnf install -y curl procps initscripts systemd wget + +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/basic.target.wants/*;\ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/usr/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-9 b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-9 new file mode 100644 index 0000000000..c2ab85152d --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/images/rpm/Dockerfile.oraclelinux-9 @@ -0,0 +1,27 @@ +# A oraclelinux9 image with systemd enabled. Must be run with: +# `-d --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro` flags +FROM tomcat:9-jre8 as tomcat + +FROM oraclelinux:9 + +ENV container docker + +RUN dnf install -y curl procps initscripts systemd wget + +RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i = \ + "systemd-tmpfiles-setup.service" ] || rm -f $i; done); \ + rm -f /lib/systemd/system/multi-user.target.wants/*;\ + rm -f /lib/systemd/system/local-fs.target.wants/*; \ + rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ + rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ + rm -f /lib/systemd/system/basic.target.wants/*;\ + rm -f /lib/systemd/system/anaconda.target.wants/*; + +COPY --from=tomcat /usr/local/tomcat /usr/local/tomcat +COPY --from=tomcat /opt/java /opt/java +COPY instrumentation/setup-tomcat.sh /opt/ +RUN bash /opt/setup-tomcat.sh + +VOLUME [ "/sys/fs/cgroup" ] + +CMD ["/usr/sbin/init"] diff --git a/internal/buildscripts/packaging/tests/instrumentation/instrumentation_test.py b/internal/buildscripts/packaging/tests/instrumentation/instrumentation_test.py new file mode 100644 index 0000000000..d447bbaacf --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/instrumentation_test.py @@ -0,0 +1,275 @@ +# Copyright Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import glob +import os +import re +import time + +from pathlib import Path + +import pytest +from iterators import TimeoutIterator + +from tests.helpers.util import ( + copy_file_into_container, + retry, + run_container_cmd, + run_distro_container, + wait_for, + wait_for_container_cmd, + REPO_DIR, + TESTS_DIR, +) + + +IMAGES_DIR = Path(__file__).parent.resolve() / "images" +DEB_DISTROS = [df.split(".")[-1] for df in glob.glob(str(IMAGES_DIR / "deb" / "Dockerfile.*"))] +RPM_DISTROS = [df.split(".")[-1] for df in glob.glob(str(IMAGES_DIR / "rpm" / "Dockerfile.*"))] + +OTELCOL_BIN_DIR = REPO_DIR / "bin" +INSTALLER_PATH = REPO_DIR / "internal" / "buildscripts" / "packaging" / "installer" / "install.sh" +COLLECTOR_CONFIG_PATH = TESTS_DIR / "instrumentation" / "config.yaml" +JAVA_AGENT_PATH = "/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar" + +PKG_NAME = "splunk-otel-auto-instrumentation" +LIBSPLUNK_PATH = "/usr/lib/splunk-instrumentation/libsplunk.so" +DEFAULT_INSTRUMENTATION_CONF = "/usr/lib/splunk-instrumentation/instrumentation.conf" +CUSTOM_INSTRUMENTATION_CONF = TESTS_DIR / "instrumentation" / "libsplunk-test.conf" +DEFAULT_SYSTEMD_CONF_PATH = "/usr/lib/splunk-instrumentation/examples/systemd/00-splunk-otel-javaagent.conf" +CUSTOM_SYSTEMD_CONF_PATH = TESTS_DIR / "instrumentation" / "systemd-test.conf" +SYSTEMD_CONF_DIR = "/usr/lib/systemd/system.conf.d" +PRELOAD_PATH = "/etc/ld.so.preload" + + +def get_dockerfile(distro): + if distro in DEB_DISTROS: + return IMAGES_DIR / "deb" / f"Dockerfile.{distro}" + else: + return IMAGES_DIR / "rpm" / f"Dockerfile.{distro}" + + +def get_package(distro, name, arch): + pkg_dir = REPO_DIR / "instrumentation" / "dist" + pkg_paths = [] + if distro in DEB_DISTROS: + pkg_paths = glob.glob(str(pkg_dir / f"{name}*{arch}.deb")) + elif distro in RPM_DISTROS: + if arch == "amd64": + arch = "x86_64" + elif arch == "arm64": + arch = "aarch64" + pkg_paths = glob.glob(str(pkg_dir / f"{name}*{arch}.rpm")) + + if pkg_paths: + return sorted(pkg_paths)[-1] + else: + return None + + +def container_file_exists(container, path): + return container.exec_run(f"test -f {path}").exit_code == 0 + + +def install_package(container, distro, path): + if distro in DEB_DISTROS: + run_container_cmd(container, f"dpkg -i {path}") + else: + run_container_cmd(container, f"rpm -ivh {path}") + + +def verify_preload(container, line, exists=True): + code, output = container.exec_run(f"cat {PRELOAD_PATH}") + assert code == 0, f"failed to get contents from {PRELOAD_PATH}" + config = output.decode("utf-8") + + match = re.search(f"^{line}$", config, re.MULTILINE) + + if exists: + assert match, f"'{line}' not found in {PRELOAD_PATH}" + else: + assert not match, f"'{line}' found in {PRELOAD_PATH}" + + +def verify_tomcat_instrumentation(container, otelcol_path, test_case, source, attributes=[]): + if source == "systemd": + if otelcol_path is None: + container.restart() + wait_for_container_cmd(container, "systemctl show-environment", timeout=30) + wait_for_container_cmd(container, "systemctl status splunk-otel-collector", timeout=30) + # get the output stream for the collector from journald + stream = container.exec_run("journalctl -u splunk-otel-collector -f", stream=True).output + else: + run_container_cmd(container, f"mkdir -p {SYSTEMD_CONF_DIR}") + run_container_cmd(container, f"cp {DEFAULT_SYSTEMD_CONF_PATH} {SYSTEMD_CONF_DIR}/") + if test_case == "custom": + copy_file_into_container(container, CUSTOM_SYSTEMD_CONF_PATH, + f"{SYSTEMD_CONF_DIR}/99-systemd-test.conf") + container.restart() + wait_for_container_cmd(container, "systemctl show-environment", timeout=30) + # start the collector and get the output stream + stream = container.exec_run(f"{otelcol_path} --config=/test/config.yaml", stream=True).output + print("Starting the tomcat systemd service ...") + run_container_cmd(container, "systemctl start tomcat") + else: + if otelcol_path is None: + wait_for_container_cmd(container, "systemctl status splunk-otel-collector", timeout=30) + # get the output stream for the collector from journald + stream = container.exec_run("journalctl -u splunk-otel-collector -f", stream=True).output + else: + run_container_cmd(container, + "sh -c 'echo /usr/lib/splunk-instrumentation/libsplunk.so > /etc/ld.so.preload'") + if test_case == "custom": + # overwrite the default instrumentation.conf with the custom one for testing + copy_file_into_container(container, CUSTOM_INSTRUMENTATION_CONF, DEFAULT_INSTRUMENTATION_CONF) + # start the collector and get the output stream + stream = container.exec_run(f"{otelcol_path} --config=/test/config.yaml", stream=True).output + print("Starting tomcat from a shell ...") + tomcat_env = { + "JAVA_HOME": "/opt/java/openjdk", + "CATALINA_PID": "/usr/local/tomcat/temp/tomcat.pid", + "CATALINA_HOME": "/usr/local/tomcat", + "CATALINA_BASE": "/usr/local/tomcat", + "CATALINA_OPTS": "-Xms512M -Xmx1024M -server -XX:+UseParallelGC", + "JAVA_OPTS": "-Djava.awt.headless=true", + } + run_container_cmd(container, "bash -c /usr/local/tomcat/bin/startup.sh", env=tomcat_env) + + print("Waiting for http://127.0.0.1:8080/sample ...") + wait_for_container_cmd(container, "curl -sSL http://127.0.0.1:8080/sample", timeout=300) + + # check the collector output stream for attributes + start_time = time.time() + for output in TimeoutIterator(stream, timeout=10, sentinel=None): + if output: + output = output.decode("utf-8").rstrip() + print(output) + for attr in attributes: + if attr["found"]: + continue + if re.search(f"{attr['key']}: {attr['value']}", output, re.MULTILINE): + attr["found"] = True + if False not in [ attr["found"] for attr in attributes ] or ((time.time() - start_time) > 300): + break + + for attr in attributes: + assert attr["found"], f"timed out waiting for '{attr['key']}: {attr['value']}'" + + +@pytest.mark.parametrize( + "distro", + [pytest.param(distro, marks=pytest.mark.deb) for distro in DEB_DISTROS] + + [pytest.param(distro, marks=pytest.mark.rpm) for distro in RPM_DISTROS], + ) +@pytest.mark.parametrize("arch", ["amd64", "arm64"]) +@pytest.mark.parametrize("test_case", ["default", "custom"]) +@pytest.mark.parametrize("source", ["systemd", "libsplunk"]) +def test_tomcat_instrumentation(distro, arch, test_case, source): + if distro == "opensuse-12" and arch == "arm64": + pytest.skip("opensuse-12 arm64 no longer supported") + + otelcol_bin = f"otelcol_linux_{arch}" + otelcol_bin_path = OTELCOL_BIN_DIR / otelcol_bin + assert os.path.isfile(otelcol_bin_path), f"{otelcol_bin_path} not found!" + + pkg_path = get_package(distro, PKG_NAME, arch) + assert pkg_path, f"{PKG_NAME} package not found" + pkg_base = os.path.basename(pkg_path) + + with run_distro_container(distro, dockerfile=get_dockerfile(distro), arch=arch) as container: + copy_file_into_container(container, COLLECTOR_CONFIG_PATH, "/test/config.yaml") + copy_file_into_container(container, pkg_path, f"/test/{pkg_base}") + copy_file_into_container(container, otelcol_bin_path, f"/test/{otelcol_bin}") + run_container_cmd(container, f"chmod a+x /test/{otelcol_bin}") + + install_package(container, distro, f"/test/{pkg_base}") + for path in [JAVA_AGENT_PATH, LIBSPLUNK_PATH, DEFAULT_INSTRUMENTATION_CONF, DEFAULT_SYSTEMD_CONF_PATH]: + assert container_file_exists(container, path), f"{path} not found" + + if test_case == "default": + if source == "libsplunk": + # service name auto-generated by libsplunk.so + service_name = r"Str\(org-apache-catalina-startup-bootstrap\)" + else: + # service name auto-generated by java agent + service_name = r"Str\(Hello, World Application\)" + environment = None + profiling = None + else: + service_name = rf"Str\(service_name_from_{source}\)" + environment = rf"Str\(deployment_environment_from_{source}\)" + profiling = r"Str\(otel\.profiling\)" + + attributes = [ + {"key": r"telemetry\.sdk\.language", "value": r"Str\(java\)", "found": False}, + {"key": r"service\.name", "value": service_name, "found": False}, + {"key": r"deployment\.environment", "value": environment, "found": False if environment else True}, + {"key": r"com\.splunk\.sourcetype", "value": profiling, "found": False if profiling else True}, + ] + + verify_tomcat_instrumentation(container, f"/test/{otelcol_bin}", test_case, source, attributes) + + +@pytest.mark.parametrize( + "distro", + [pytest.param(distro, marks=pytest.mark.deb) for distro in DEB_DISTROS] + + [pytest.param(distro, marks=pytest.mark.rpm) for distro in RPM_DISTROS], + ) +@pytest.mark.parametrize("arch", ["amd64", "arm64"]) +def test_package_uninstall(distro, arch): + if distro == "opensuse-12" and arch == "arm64": + pytest.skip("opensuse-12 arm64 no longer supported") + + pkg_path = get_package(distro, PKG_NAME, arch) + assert pkg_path, f"{PKG_NAME} package not found" + pkg_base = os.path.basename(pkg_path) + + with run_distro_container(distro, dockerfile=get_dockerfile(distro), arch=arch) as container: + copy_file_into_container(container, pkg_path, f"/test/{pkg_base}") + run_container_cmd(container, f"sh -c 'echo \"# This line should be preserved\" >> {PRELOAD_PATH}'") + + # install the package + install_package(container, distro, f"/test/{pkg_base}") + + verify_preload(container, "# This line should be preserved") + + for path in [JAVA_AGENT_PATH, LIBSPLUNK_PATH, DEFAULT_INSTRUMENTATION_CONF, DEFAULT_SYSTEMD_CONF_PATH]: + assert container_file_exists(container, path), f"{path} not found" + + # verify libsplunk.so was not automatically added to /etc/ld.so.preload + verify_preload(container, LIBSPLUNK_PATH, exists=False) + + # explicitly add libsplunk.so to /etc/ld.so.preload + run_container_cmd(container, f"sh -c 'echo {LIBSPLUNK_PATH} >> {PRELOAD_PATH}'") + + # uninstall the package + if distro in DEB_DISTROS: + run_container_cmd(container, f"dpkg -P {PKG_NAME}") + else: + run_container_cmd(container, f"rpm -e {PKG_NAME}") + + # verify the package was uninstalled + if distro in DEB_DISTROS: + assert container.exec_run(f"dpkg -s {PKG_NAME}").exit_code != 0 + else: + assert container.exec_run(f"rpm -q {PKG_NAME}").exit_code != 0 + + # verify files were uninstalled + for path in [JAVA_AGENT_PATH, LIBSPLUNK_PATH, DEFAULT_INSTRUMENTATION_CONF, DEFAULT_SYSTEMD_CONF_PATH]: + assert not container_file_exists(container, path) + + # verify libsplunk.so was removed from /etc/ld.so.preload + verify_preload(container, LIBSPLUNK_PATH, exists=False) + + verify_preload(container, "# This line should be preserved") diff --git a/internal/buildscripts/packaging/tests/instrumentation/libsplunk-test.conf b/internal/buildscripts/packaging/tests/instrumentation/libsplunk-test.conf new file mode 100644 index 0000000000..c9c01233e5 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/libsplunk-test.conf @@ -0,0 +1,7 @@ +java_agent_jar=/usr/lib/splunk-instrumentation/splunk-otel-javaagent.jar +resource_attributes=deployment.environment=deployment_environment_from_libsplunk +service_name=service_name_from_libsplunk +disable_telemetry=false +enable_profiler=true +enable_profiler_memory=true +enable_metrics=true diff --git a/internal/buildscripts/packaging/tests/instrumentation/setup-tomcat.sh b/internal/buildscripts/packaging/tests/instrumentation/setup-tomcat.sh new file mode 100644 index 0000000000..c338d319e0 --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/setup-tomcat.sh @@ -0,0 +1,38 @@ +#!/bin/bash +set -euo pipefail + +TOMCAT_HOME="/usr/local/tomcat" +JAVA_HOME="/opt/java/openjdk" + +wget --no-check-certificate -nv -O ${TOMCAT_HOME}/webapps/sample.war https://tomcat.apache.org/tomcat-9.0-doc/appdev/sample/sample.war + +cat < /etc/systemd/system/tomcat.service +[Unit] +Description=Apache Tomcat Web Application Container +After=network.target + +[Service] +Type=forking + +Environment="JAVA_HOME=${JAVA_HOME}" +Environment="CATALINA_PID=${TOMCAT_HOME}/temp/tomcat.pid" +Environment="CATALINA_HOME=${TOMCAT_HOME}" +Environment="CATALINA_BASE=${TOMCAT_HOME}" +Environment="CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC" +Environment="JAVA_OPTS=-Djava.awt.headless=true" + +ExecStart=${TOMCAT_HOME}/bin/startup.sh +ExecStop=${TOMCAT_HOME}/bin/shutdown.sh + +User=tomcat +Group=tomcat +UMask=0007 +RestartSec=10 +Restart=always + +[Install] +WantedBy=multi-user.target +EOH + +useradd -r -m -U -d $TOMCAT_HOME -s /bin/false tomcat +chown -R tomcat:tomcat $TOMCAT_HOME diff --git a/internal/buildscripts/packaging/tests/instrumentation/systemd-test.conf b/internal/buildscripts/packaging/tests/instrumentation/systemd-test.conf new file mode 100644 index 0000000000..8738416f1f --- /dev/null +++ b/internal/buildscripts/packaging/tests/instrumentation/systemd-test.conf @@ -0,0 +1,6 @@ +[Manager] +DefaultEnvironment="OTEL_SERVICE_NAME=service_name_from_systemd" +DefaultEnvironment="OTEL_RESOURCE_ATTRIBUTES=deployment.environment=deployment_environment_from_systemd" +DefaultEnvironment="SPLUNK_METRICS_ENABLED=true" +DefaultEnvironment="SPLUNK_PROFILER_ENABLED=true" +DefaultEnvironment="SPLUNK_PROFILER_MEMORY_ENABLED=true" diff --git a/internal/buildscripts/packaging/tests/requirements.txt b/internal/buildscripts/packaging/tests/requirements.txt index 3865b295fc..2bb78d3ffe 100644 --- a/internal/buildscripts/packaging/tests/requirements.txt +++ b/internal/buildscripts/packaging/tests/requirements.txt @@ -1,4 +1,5 @@ docker==6.1.3 +iterators==0.2.0 psutil==5.9.5 pytest==7.4.0 pytest-html==3.1.1