Skip to content

Commit 97e16ee

Browse files
authored
Re-add .NET deployer TA plus CI fixes (#5957)
* Revert "Revert "Adds the .NET deployer TA (#5949)" (#5956)" This reverts commit e99f1da. * Ensure that main CI is clean with new code * Allow manual runs of build-and-test * Fix include casing * Lint fixes
1 parent a4dd36d commit 97e16ee

File tree

20 files changed

+629
-0
lines changed

20 files changed

+629
-0
lines changed

.github/workflows/build-and-test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ on:
1919
- 'go.sum'
2020
- '!**.md'
2121
- '!packaging/**'
22+
workflow_dispatch: # Allows manual execution of the workflow
2223

2324
concurrency:
2425
group: build-and-test-${{ github.event.pull_request.number || github.ref }}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Ignore built or downloaded assets
2+
assets/windows_x86_64/bin/*.exe
3+
assets/windows_x86_64/bin/*.psm1
4+
assets/windows_x86_64/bin/*.zip
5+
6+
# Ignore the directory with the compressed package to be distributed
7+
out/
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
include ../../Makefile.Common
2+
3+
MOD_INPUT_NAME = splunk_otel_dotnet_deployer
4+
5+
.PHONY: all
6+
all: download-dotnet-assets build pack
7+
8+
.PHONY: download-dotnet-assets
9+
download-dotnet-assets:
10+
@echo "Downloading .NET assets..."
11+
@for asset in Splunk.OTel.DotNet.psm1 splunk-opentelemetry-dotnet-windows.zip; do \
12+
if [ ! -f ./assets/windows_x86_64/bin/$${asset} ]; then \
13+
echo " > Downloading $${asset}..."; \
14+
curl -s -L https://github.com/signalfx/splunk-otel-dotnet/releases/latest/download/$${asset} -o ./assets/windows_x86_64/bin/$${asset}; \
15+
else \
16+
echo " > $${asset} already exists, skipping download."; \
17+
fi \
18+
done
19+
20+
.PHONY: build
21+
build: ./assets/windows_x86_64/bin/$(MOD_INPUT_NAME).exe
22+
./assets/windows_x86_64/bin/$(MOD_INPUT_NAME).exe: $(shell find ./ -name '*.go')
23+
@echo "Building executable ..."
24+
@go build -o ./assets/windows_x86_64/bin/ ./cmd/$(MOD_INPUT_NAME)/...
25+
26+
.PHONY: pack
27+
pack:
28+
@echo "Packing add-on ..."
29+
@if [ ! -d ./out/distribution/ ]; then mkdir -p ./out/distribution/; fi
30+
@tar -C ./assets/ --transform='s,^,$(MOD_INPUT_NAME)/,' -hcz -f ./out/distribution/$(MOD_INPUT_NAME).tgz .
31+
32+
.PHONY: clean
33+
clean:
34+
@echo "Cleaning..."
35+
@if [ -f ./assets/windows_x86_64/bin/$(MOD_INPUT_NAME).exe ]; then rm -rf ./assets/windows_x86_64/bin/$(MOD_INPUT_NAME).exe; fi
36+
@if [ -f ../out/distribution/ ]; then rm -rf ./out/distribution/; fi
37+
38+
.PHONY: gotest
39+
gotest:
40+
@echo "Running golang tests..."
41+
@go test $${GOTEST_OPTS:- -v -race} ./...
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Splunk OpenTelemetry .NET Deployer
2+
3+
The Splunk OpenTelemetry .NET Deployer is a technical add-on to be used with
4+
Splunk Enterprise to facilitate the deployment of the
5+
[Splunk Distribution of OpenTelemetry .NET](https://docs.splunk.com/observability/en/gdi/get-data-in/application/otel-dotnet/get-started.html).
6+
It automates the setup process, ensuring that your .NET
7+
applications are properly configured to send telemetry data to Splunk
8+
Observability Cloud.
9+
10+
It assumes that the Splunk OpenTelemetry Collector is already deployed and
11+
configured to receive telemetry data from your .NET applications.
12+
13+
## Installation
14+
15+
It follows the standard installation process for Splunk apps and add-ons.
16+
Notice that the technical add-on is not a standalone application, it is meant
17+
to be run under `splunkd` control.
18+
19+
__Note:__ the technical add-on is only available for Windows x86_64 and requires
20+
`splunkd` to be running under a user with administrative privileges.
21+
22+
## Configuration
23+
24+
See the [inputs.conf.spec](./assets/README/inputs.conf.spec) file for the available
25+
configuration options.
26+
27+
## Development
28+
29+
This project was developed on Windows, using `MINGW64` tools and the `bash`
30+
provided by Git for Windows. Check the [Makefile](./Makefile) for the available
31+
targets - the default target generates the technical add-on under
32+
`./out/distribution`.
33+
34+
### Sources
35+
36+
#### `./assets/`
37+
38+
Mimics the structure of the technical add-on, notice the
39+
[`.gitignore`](./.gitignore) file to
40+
identify which assets are built and which are not.
41+
42+
It can be copied directly to a Splunk Enterprise instance to install the
43+
technical add-on. __Note:__ the name of the directory must be the same as the
44+
name of the technical add-on.
45+
46+
#### `./cmd/splunk_otel_dotnet_deployer/`
47+
48+
Contains the source code for the deployer. It is a simple Go application that
49+
reads the input XML from the `stdin` and calls a wrapper PowerShell script to
50+
control the installation process.
51+
52+
#### `./internal/`
53+
54+
Contains the internal packages used by the deployer that in principle could
55+
be used by other technical add-ons. Currently only contains a type to read the
56+
input XML.
57+
58+
### Manual run of the deployer
59+
60+
To manually run the deployer locally, use the following command:
61+
62+
```PowerShell
63+
> cd .\assets\windows_x86_64\bin
64+
65+
> Get-Content ..\..\..\internal\modularinput\testdata\install.inputs.xml | .\splunk_otel_dotnet_deployer.exe
66+
```
67+
68+
The application will generate output on the console. If you also want the log
69+
file you need to define the `SPLUNK_HOME` environment variable, pointing to an
70+
existing directory. The log file will be created under
71+
`$SPLUNK_HOME/var/log/splunk/splunk_otel_dotnet_deployer.log`. You need to
72+
create the directory structure, including 'var/log/splunk' if it does not exist.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[splunk_otel_dotnet_deployer://<name>]
2+
uninstall = <boolean>
3+
* By default it always attempt to install the Splunk Distribution of
4+
OpenTelemetry .NET, set to "true" to uninstall.
5+
* Default = false
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[install]
2+
state = enabled
3+
is_configured = false
4+
build = 1
5+
6+
[ui]
7+
is_visible = false
8+
label = Splunk OpenTelemetry .NET Deployer
9+
10+
[launcher]
11+
author = Splunk, Inc.
12+
description = A Splunk Technical Add-on that deploys the Splunk Distribution of OpenTelemetry .NET.
13+
version = 1.0.0
14+
15+
[package]
16+
id = splunk_otel_dotnet_deployer
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[splunk_otel_dotnet_deployer://splunk_otel_dotnet_deployer]
2+
uninstall = false
Loading
Loading
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<#
2+
.SYNOPSIS
3+
This script drives the installation of the Splunk Distribution of OpenTelemetry .NET.
4+
5+
.DESCRIPTION
6+
This script is intended to be called by the splunk_otel_dotnet_deployer.exe as
7+
the later is launched by splunkd with proper environment variables and configuration.
8+
9+
.PARAMETER uninstall
10+
If present, the script will uninstall the Splunk Distribution of OpenTelemetry .NET.
11+
12+
#>
13+
14+
param (
15+
[switch]$uninstall
16+
)
17+
18+
$ErrorActionPreference = "Stop"
19+
$ProgressPreference = "SilentlyContinue"
20+
21+
$scriptPath = $MyInvocation.MyCommand.Path
22+
$scriptDir = Split-Path $scriptPath
23+
24+
$modulePath = Join-Path $scriptDir "Splunk.OTel.DotNet.psm1"
25+
Import-Module $modulePath
26+
27+
$otelSDKInstallVersion = Get-OpenTelemetryInstallVersion
28+
29+
if ($uninstall) {
30+
if ($otelSDKInstallVersion) {
31+
# TODO: Is it necessary to uninstall for IIS specifically?
32+
Write-Host "Uninstalling Splunk Distribution of OpenTelemetry .NET ..."
33+
Uninstall-OpenTelemetryCore
34+
Write-Host "Splunk Distribution of OpenTelemetry .NET uninstalled successfully"
35+
} else {
36+
Write-Host "Nothing to do since Splunk Distribution of OpenTelemetry .NET is not installed"
37+
}
38+
# Install the SDK if it is not already installed
39+
} elseif ($otelSDKInstallVersion) {
40+
Write-Host "Nothing to do since Splunk Distribution of OpenTelemetry .NET is already installed. OpenTelelemetry .NET SDK version: $otelSDKInstallVersion"
41+
} else {
42+
Write-Host "Installing Splunk Distribution of OpenTelemetry .NET ..."
43+
$zipPath = Join-Path $scriptDir "splunk-opentelemetry-dotnet-windows.zip"
44+
Install-OpenTelemetryCore -LocalPath $zipPath
45+
46+
$w3svc = Get-Service -name "W3SVC" -ErrorAction SilentlyContinue
47+
$was = Get-Service -name "WAS" -ErrorAction SilentlyContinue
48+
if ($w3svc -And $was) {
49+
Write-Host "Registering OpenTelemetry for IIS ..."
50+
Register-OpenTelemetryForIIS
51+
}
52+
53+
Write-Host "Splunk Distribution of OpenTelemetry .NET installed successfully"
54+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright Splunk, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
//go:build !windows
16+
// +build !windows
17+
18+
package main
19+
20+
import (
21+
"os"
22+
23+
"github.com/splunk/splunk_otel_dotnet_deployer/internal/modularinput"
24+
)
25+
26+
func runDeployer(_ *modularinput.Input, _, _, _ *os.File) error {
27+
panic("OS not supported")
28+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright Splunk, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
//go:build windows
16+
// +build windows
17+
18+
package main
19+
20+
import (
21+
"fmt"
22+
"log"
23+
"os"
24+
"os/exec"
25+
"path/filepath"
26+
"strings"
27+
28+
"github.com/splunk/splunk_otel_dotnet_deployer/internal/modularinput"
29+
)
30+
31+
const (
32+
wrapperScript = "installer-wrapper.ps1"
33+
)
34+
35+
func runDeployer(input *modularinput.Input, stdin, stdout, stderr *os.File) error {
36+
// Launch the wrapper script using PowerShell capturing the output
37+
// and error streams and sending them to the stdout and stderr streams
38+
// of the deployer.
39+
40+
// The wrapper script is expected to be in the same directory as the deployer.
41+
// Get the path to the deployer executable.
42+
deployerPath, err := os.Executable()
43+
if err != nil {
44+
return fmt.Errorf("failed to get the path to the deployer executable: %w", err)
45+
}
46+
47+
scriptDir := filepath.Dir(deployerPath)
48+
scriptPath := filepath.Join(scriptDir, wrapperScript)
49+
if _, err := os.Stat(scriptPath); err != nil {
50+
if os.IsNotExist(err) {
51+
return fmt.Errorf("wrapper script not found at %s", scriptPath)
52+
}
53+
return fmt.Errorf("failed to check if wrapper script exists: %w", err)
54+
}
55+
56+
// Launch the wrapper script using PowerShell.
57+
args := []string{
58+
"-ExecutionPolicy", "ByPass",
59+
"-File", scriptPath,
60+
}
61+
args = append(args, scriptArgs(input)...)
62+
log.Printf("Running: powershell.exe args: %v\n", args)
63+
cmd := exec.Command("powershell.exe", args...)
64+
65+
var stdBuf, errBuf strings.Builder
66+
cmd.Stdin = stdin
67+
cmd.Stdout = &stdBuf
68+
cmd.Stderr = &errBuf
69+
70+
err = cmd.Run()
71+
72+
log.Printf("Wrapper stdout:\n%s\n", stdBuf.String())
73+
log.Printf("Wrapper stderr:\n%s\n", errBuf.String())
74+
75+
return err
76+
}
77+
78+
func scriptArgs(input *modularinput.Input) []string {
79+
var args []string
80+
var configStanza modularinput.Stanza
81+
for _, stanza := range input.Configuration.Stanza {
82+
if stanza.Name == modularinputName+"://"+modularinputName {
83+
configStanza = stanza
84+
break
85+
}
86+
}
87+
88+
for _, param := range configStanza.Param {
89+
switch param.Name {
90+
case "uninstall":
91+
if param.Value == "true" {
92+
args = append(args, "-uninstall")
93+
}
94+
}
95+
}
96+
return args
97+
}

0 commit comments

Comments
 (0)