Skip to content

Commit

Permalink
Merge branch 'main' into update-dotnet-version-for-zeroconfig-windows…
Browse files Browse the repository at this point in the history
…-test
  • Loading branch information
pjanotti authored Mar 6, 2025
2 parents 6983ba5 + 4df992d commit 9072958
Show file tree
Hide file tree
Showing 19 changed files with 604 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/splunk-ta-otel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ jobs:
set -o pipefail
PLATFORM="all" make -e distribute-ta
- name: Upload Collector TA
uses: actions/upload-artifact@v4
with:
name: Splunk_TA_otel
path: ./build/out/distribution/Splunk_TA_otel.tgz

test-discovery:
name: test-discovery
runs-on: ubuntu-24.04
Expand Down
7 changes: 7 additions & 0 deletions packaging/dotnet-instr-deployer-add-on/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Ignore built or downloaded assets
assets/windows_x86_64/bin/*.exe
assets/windows_x86_64/bin/*.psm1
assets/windows_x86_64/bin/*.zip

# Ignore the directory with the compressed package to be distributed
out/
39 changes: 39 additions & 0 deletions packaging/dotnet-instr-deployer-add-on/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
MOD_INPUT_NAME = splunk_otel_dotnet_deployer

.PHONY: all
all: download-dotnet-assets build pack

.PHONY: download-dotnet-assets
download-dotnet-assets:
@echo "Downloading .NET assets..."
@for asset in Splunk.OTel.DotNet.psm1 splunk-opentelemetry-dotnet-windows.zip; do \
if [ ! -f ./assets/windows_x86_64/bin/$${asset} ]; then \
echo " > Downloading $${asset}..."; \
curl -s -L https://github.com/signalfx/splunk-otel-dotnet/releases/latest/download/$${asset} -o ./assets/windows_x86_64/bin/$${asset}; \
else \
echo " > $${asset} already exists, skipping download."; \
fi \
done

.PHONY: build
build: ./assets/windows_x86_64/bin/$(MOD_INPUT_NAME).exe
./assets/windows_x86_64/bin/$(MOD_INPUT_NAME).exe: $(shell find ./ -name '*.go')
@echo "Building executable ..."
@go build -o ./assets/windows_x86_64/bin/ ./cmd/$(MOD_INPUT_NAME)/...

.PHONY: pack
pack:
@echo "Packing add-on ..."
@if [ ! -d ./out/distribution/ ]; then mkdir -p ./out/distribution/; fi
@tar -C ./assets/ --transform='s,^,$(MOD_INPUT_NAME)/,' -hcz -f ./out/distribution/$(MOD_INPUT_NAME).tgz .

.PHONY: clean
clean:
@echo "Cleaning..."
@if [ -f ./assets/windows_x86_64/bin/$(MOD_INPUT_NAME).exe ]; then rm -rf ./assets/windows_x86_64/bin/$(MOD_INPUT_NAME).exe; fi
@if [ -f ../out/distribution/ ]; then rm -rf ./out/distribution/; fi

.PHONY: gotest
gotest:
@echo "Running golang tests..."
@go test $${GOTEST_OPTS:- -v -race} ./...
72 changes: 72 additions & 0 deletions packaging/dotnet-instr-deployer-add-on/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Splunk OpenTelemetry .NET Deployer

The Splunk OpenTelemetry .NET Deployer is a technical add-on to be used with
Splunk Enterprise to facilitate the deployment of the
[Splunk Distribution of OpenTelemetry .NET](https://docs.splunk.com/observability/en/gdi/get-data-in/application/otel-dotnet/get-started.html).
It automates the setup process, ensuring that your .NET
applications are properly configured to send telemetry data to Splunk
Observability Cloud.

It assumes that the Splunk OpenTelemetry Collector is already deployed and
configured to receive telemetry data from your .NET applications.

## Installation

It follows the standard installation process for Splunk apps and add-ons.
Notice that the technical add-on is not a standalone application, it is meant
to be run under `splunkd` control.

__Note:__ the technical add-on is only available for Windows x86_64 and requires
`splunkd` to be running under a user with administrative privileges.

## Configuration

See the [inputs.conf.spec](./assets/README/inputs.conf.spec) file for the available
configuration options.

## Development

This project was developed on Windows, using `MINGW64` tools and the `bash`
provided by Git for Windows. Check the [Makefile](./Makefile) for the available
targets - the default target generates the technical add-on under
`./out/distribution`.

### Sources

#### `./assets/`

Mimics the structure of the technical add-on, notice the
[`.gitignore`](./.gitignore) file to
identify which assets are built and which are not.

It can be copied directly to a Splunk Enterprise instance to install the
technical add-on. __Note:__ the name of the directory must be the same as the
name of the technical add-on.

#### `./cmd/splunk_otel_dotnet_deployer/`

Contains the source code for the deployer. It is a simple Go application that
reads the input XML from the `stdin` and calls a wrapper PowerShell script to
control the installation process.

#### `./internal/`

Contains the internal packages used by the deployer that in principle could
be used by other technical add-ons. Currently only contains a type to read the
input XML.

### Manual run of the deployer

To manually run the deployer locally, use the following command:

```PowerShell
> cd .\assets\windows_x86_64\bin
> Get-Content ..\..\..\internal\modularinput\testdata\install.inputs.xml | .\splunk_otel_dotnet_deployer.exe
```

The application will generate output on the console. If you also want the log
file you need to define the `SPLUNK_HOME` environment variable, pointing to an
existing directory. The log file will be created under
`$SPLUNK_HOME/var/log/splunk/splunk_otel_dotnet_deployer.log`. You need to
create the directory structure, including 'var/log/splunk' if it does not exist.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[splunk_otel_dotnet_deployer://<name>]
uninstall = <boolean>
* By default it always attempt to install the Splunk Distribution of
OpenTelemetry .NET, set to "true" to uninstall.
* Default = false
16 changes: 16 additions & 0 deletions packaging/dotnet-instr-deployer-add-on/assets/default/app.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[install]
state = enabled
is_configured = false
build = 1

[ui]
is_visible = false
label = Splunk OpenTelemetry .NET Deployer

[launcher]
author = Splunk, Inc.
description = A Splunk Technical Add-on that deploys the Splunk Distribution of OpenTelemetry .NET.
version = 1.0.0

[package]
id = splunk_otel_dotnet_deployer
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[splunk_otel_dotnet_deployer://splunk_otel_dotnet_deployer]
uninstall = false
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<#
.SYNOPSIS
This script drives the installation of the Splunk Distribution of OpenTelemetry .NET.
.DESCRIPTION
This script is intended to be called by the splunk_otel_dotnet_deployer.exe as
the later is launched by splunkd with proper environment variables and configuration.
.PARAMETER uninstall
If present, the script will uninstall the Splunk Distribution of OpenTelemetry .NET.
#>

param (
[switch]$uninstall
)

$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"

$scriptPath = $MyInvocation.MyCommand.Path
$scriptDir = Split-Path $scriptPath

$modulePath = Join-Path $scriptDir "Splunk.OTel.DotNet.psm1"
Import-Module $modulePath

$otelSDKInstallVersion = Get-OpenTelemetryInstallVersion

if ($uninstall) {
if ($otelSDKInstallVersion) {
# TODO: Is it necessary to uninstall for IIS specifically?
Write-Host "Uninstalling Splunk Distribution of OpenTelemetry .NET ..."
Uninstall-OpenTelemetryCore
Write-Host "Splunk Distribution of OpenTelemetry .NET uninstalled successfully"
} else {
Write-Host "Nothing to do since Splunk Distribution of OpenTelemetry .NET is not installed"
}
# Install the SDK if it is not already installed
} elseif ($otelSDKInstallVersion) {
Write-Host "Nothing to do since Splunk Distribution of OpenTelemetry .NET is already installed. OpenTelelemetry .NET SDK version: $otelSDKInstallVersion"
} else {
Write-Host "Installing Splunk Distribution of OpenTelemetry .NET ..."
$zipPath = Join-Path $scriptDir "splunk-opentelemetry-dotnet-windows.zip"
Install-OpenTelemetryCore -LocalPath $zipPath

$w3svc = Get-Service -name "W3SVC" -ErrorAction SilentlyContinue
$was = Get-Service -name "WAS" -ErrorAction SilentlyContinue
if ($w3svc -And $was) {
Write-Host "Registering OpenTelemetry for IIS ..."
Register-OpenTelemetryForIIS
}

Write-Host "Splunk Distribution of OpenTelemetry .NET installed successfully"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// 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.

//go:build windows
// +build windows

package main

import (
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strings"

"github.com/splunk/splunk_otel_dotnet_deployer/internal/modularinput"
)

const (
wrapperScript = "installer-wrapper.ps1"
)

func runDeployer(input *modularinput.Input, stdin, stdout, stderr *os.File) error {
// Launch the wrapper script using PowerShell capturing the output
// and error streams and sending them to the stdout and stderr streams
// of the deployer.

// The wrapper script is expected to be in the same directory as the deployer.
// Get the path to the deployer executable.
deployerPath, err := os.Executable()
if err != nil {
return fmt.Errorf("failed to get the path to the deployer executable: %w", err)
}

scriptDir := filepath.Dir(deployerPath)
scriptPath := filepath.Join(scriptDir, wrapperScript)
if _, err := os.Stat(scriptPath); err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("wrapper script not found at %s", scriptPath)
}
return fmt.Errorf("failed to check if wrapper script exists: %w", err)
}

// Launch the wrapper script using PowerShell.
args := []string{
"-ExecutionPolicy", "ByPass",
"-File", scriptPath,
}
args = append(args, scriptArgs(input)...)
log.Printf("Running: powershell.exe args: %v\n", args)
cmd := exec.Command("powershell.exe", args...)

var stdBuf, errBuf strings.Builder
cmd.Stdin = stdin
cmd.Stdout = &stdBuf
cmd.Stderr = &errBuf

err = cmd.Run()

log.Printf("Wrapper stdout:\n%s\n", stdBuf.String())
log.Printf("Wrapper stderr:\n%s\n", errBuf.String())

return err
}

func scriptArgs(input *modularinput.Input) []string {
var args []string
var configStanza modularinput.Stanza
for _, stanza := range input.Configuration.Stanza {
if stanza.Name == modularinputName+"://"+modularinputName {
configStanza = stanza
break
}
}

for _, param := range configStanza.Param {
switch param.Name {
case "uninstall":
if param.Value == "true" {
args = append(args, "-uninstall")
}
}
}
return args
}
Loading

0 comments on commit 9072958

Please sign in to comment.