From 742078e33dca8b13fb9fc6a45d40a32b41a7edf8 Mon Sep 17 00:00:00 2001 From: Paulo Janotti Date: Wed, 5 Mar 2025 23:47:16 -0800 Subject: [PATCH 1/2] Adds the .NET deployer TA (#5949) * Adds the .NET deployer TA * Fix some brand names * Match golang practices of the repo * Make test file more readable * Make explicit that err is ignored on logFile.Close() --- .../dotnet-instr-deployer-add-on/.gitignore | 7 ++ .../dotnet-instr-deployer-add-on/Makefile | 39 +++++++ .../dotnet-instr-deployer-add-on/README.md | 72 ++++++++++++ .../assets/README/inputs.conf.spec | 5 + .../assets/default/app.conf | 16 +++ .../assets/default/inputs.conf | 2 + .../assets/static/appIcon.png | Bin 0 -> 1216 bytes .../assets/static/appIcon_2x.png | Bin 0 -> 1207 bytes .../windows_x86_64/bin/installer-wrapper.ps1 | 54 +++++++++ .../deployer_windows.go | 97 ++++++++++++++++ .../cmd/splunk_otel_dotnet_deployer/main.go | 105 ++++++++++++++++++ packaging/dotnet-instr-deployer-add-on/go.mod | 13 +++ packaging/dotnet-instr-deployer-add-on/go.sum | 10 ++ .../internal/modularinput/inputs_xml.go | 76 +++++++++++++ .../internal/modularinput/inputs_xml_test.go | 49 ++++++++ .../testdata/Splunk_TA_otel.inputs.xml | 27 +++++ .../modularinput/testdata/install.inputs.xml | 13 +++ .../testdata/uninstall.inputs.xml | 13 +++ 18 files changed, 598 insertions(+) create mode 100644 packaging/dotnet-instr-deployer-add-on/.gitignore create mode 100644 packaging/dotnet-instr-deployer-add-on/Makefile create mode 100644 packaging/dotnet-instr-deployer-add-on/README.md create mode 100644 packaging/dotnet-instr-deployer-add-on/assets/README/inputs.conf.spec create mode 100644 packaging/dotnet-instr-deployer-add-on/assets/default/app.conf create mode 100644 packaging/dotnet-instr-deployer-add-on/assets/default/inputs.conf create mode 100644 packaging/dotnet-instr-deployer-add-on/assets/static/appIcon.png create mode 100644 packaging/dotnet-instr-deployer-add-on/assets/static/appIcon_2x.png create mode 100644 packaging/dotnet-instr-deployer-add-on/assets/windows_x86_64/bin/installer-wrapper.ps1 create mode 100644 packaging/dotnet-instr-deployer-add-on/cmd/splunk_otel_dotnet_deployer/deployer_windows.go create mode 100644 packaging/dotnet-instr-deployer-add-on/cmd/splunk_otel_dotnet_deployer/main.go create mode 100644 packaging/dotnet-instr-deployer-add-on/go.mod create mode 100644 packaging/dotnet-instr-deployer-add-on/go.sum create mode 100644 packaging/dotnet-instr-deployer-add-on/internal/modularinput/inputs_xml.go create mode 100644 packaging/dotnet-instr-deployer-add-on/internal/modularinput/inputs_xml_test.go create mode 100644 packaging/dotnet-instr-deployer-add-on/internal/modularinput/testdata/Splunk_TA_otel.inputs.xml create mode 100644 packaging/dotnet-instr-deployer-add-on/internal/modularinput/testdata/install.inputs.xml create mode 100644 packaging/dotnet-instr-deployer-add-on/internal/modularinput/testdata/uninstall.inputs.xml diff --git a/packaging/dotnet-instr-deployer-add-on/.gitignore b/packaging/dotnet-instr-deployer-add-on/.gitignore new file mode 100644 index 0000000000..ea9089ae35 --- /dev/null +++ b/packaging/dotnet-instr-deployer-add-on/.gitignore @@ -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/ diff --git a/packaging/dotnet-instr-deployer-add-on/Makefile b/packaging/dotnet-instr-deployer-add-on/Makefile new file mode 100644 index 0000000000..fd072da594 --- /dev/null +++ b/packaging/dotnet-instr-deployer-add-on/Makefile @@ -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} ./... diff --git a/packaging/dotnet-instr-deployer-add-on/README.md b/packaging/dotnet-instr-deployer-add-on/README.md new file mode 100644 index 0000000000..d56879785f --- /dev/null +++ b/packaging/dotnet-instr-deployer-add-on/README.md @@ -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. diff --git a/packaging/dotnet-instr-deployer-add-on/assets/README/inputs.conf.spec b/packaging/dotnet-instr-deployer-add-on/assets/README/inputs.conf.spec new file mode 100644 index 0000000000..b5393e1e09 --- /dev/null +++ b/packaging/dotnet-instr-deployer-add-on/assets/README/inputs.conf.spec @@ -0,0 +1,5 @@ +[splunk_otel_dotnet_deployer://] +uninstall = +* By default it always attempt to install the Splunk Distribution of + OpenTelemetry .NET, set to "true" to uninstall. +* Default = false diff --git a/packaging/dotnet-instr-deployer-add-on/assets/default/app.conf b/packaging/dotnet-instr-deployer-add-on/assets/default/app.conf new file mode 100644 index 0000000000..79722ef77f --- /dev/null +++ b/packaging/dotnet-instr-deployer-add-on/assets/default/app.conf @@ -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 diff --git a/packaging/dotnet-instr-deployer-add-on/assets/default/inputs.conf b/packaging/dotnet-instr-deployer-add-on/assets/default/inputs.conf new file mode 100644 index 0000000000..bc9b448536 --- /dev/null +++ b/packaging/dotnet-instr-deployer-add-on/assets/default/inputs.conf @@ -0,0 +1,2 @@ +[splunk_otel_dotnet_deployer://splunk_otel_dotnet_deployer] +uninstall = false diff --git a/packaging/dotnet-instr-deployer-add-on/assets/static/appIcon.png b/packaging/dotnet-instr-deployer-add-on/assets/static/appIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..a0ef506fb16a135cf44245afe71e6a6dd7fbc246 GIT binary patch literal 1216 zcmV;x1V8(UP)srfkUI2pAMpPKv z1e;y&c4op_L^3%GIB6?!r1h?M&z|!;Gyj=63;q2L7l4aE@YR{G|HUInlmDmM36RPi z|6dCQ0s+VV7h7vA+ip)R4RqR!86EocVlH`89#hKiLI^t-m@kY ziv@v{8^`!j0(oPzsCRcQ#N%;{j(&vGrw8#zb_tV{cNz+&1&!1#=VbwqDB`N|deij~ zfmG1b(}VW*cIdhei(D89N6?kY;M}?MXlqL&yR?XMc?YiRiYqN^SFT?lP5n;^#4wRa z1W%v-jBy6=vgFD;x4*58#p34(W$US$Zy+8h91g=U z;>hPWW!(N#1Gs$o3i|r{<-ToOX?Q}lK3?p;|3=Pynf2Q{UJ>b>YVRT6L+oDw*D|M@(J zCr^IE5((Qh6KH8^7V)#j4035tZy%!3C>9qNkVqy`sZ{C>EBAbdeZ3Jl+Sp1Qc`YsP z;qQ$NeDn2J()GrdH%ViCqAySx^fJ4uA|4BfXO0;LLX;X_y!cB%#>OvU=3od8hQt{{@9<>^1&*Ypx zIBI_WX$HSMdb9_UB#WFrD7g(Xq*V}BqfEa*3f8Iq?eg?e@i2ZY%0PVL%z3UST e)w9a}d;b8;sR<^DGk1Xi0000-YF~#;>_I%rlR1NPAA~1nQIj8pQwIl>Zj`OQ~V(-@N5(XK|n?A zG9v|3@H|lY(i^s{0GW~nR_F7KKd7@fzI=c7d7gEkI-Xdl`&bNhPm90^jKBztzzB@M z2#ml8jKKcai)FI=3G3_Y`|9g&j7F0LVKPM*pGzIx?!_F(ee&sN@7rt!L+|g$$ET+! z_XMU^t8F%Wu~h7lM@JuEg zPMuy~PA?^Cm{1ql?AGSy(yPUEI<4b%-Q8-Mrf%Yyz;ih8S70@Q~rdM-R(9MWK+tfj3~Y+mUeMC~07Z(@khZPrKBg0_0OE5geOgmlAo=vJ$Dv&anO!YMg z5c41&|MhmAqt!617c)-R#Ke2`Ni@Uk#$xmCxfS1v)M4)q41hE~K7rPk&1UP6c4FHl z((-b}0FWGPaByhGgGa3bHZFRLtB++2w z6B9UixT9#Axx56aSd#=rG#bIdTU+%Nsis#$FpY-${EIKmX0!0moazMrA{8T%Fq$}0 zYT3+e4900J77KbqbvOH)6b`%RX8r!P7VkF=!QiP5>Y5Y|Z-5l=``faMirE!QB$kDC zBNPH@eLc{|=LWfGBqduY=0m}C_v~yixZd{1JbB|JR;9}4a=~B#DTRVTN*dJ=3{x1p zMIhiuN}-TcNPku%@8afp9;+ZF%_474ColpdFajem0wXX2BQOFZFajemG3yTj1^{z3 V$958hq`3e9002ovPDHLkV1oUEMU(&l literal 0 HcmV?d00001 diff --git a/packaging/dotnet-instr-deployer-add-on/assets/windows_x86_64/bin/installer-wrapper.ps1 b/packaging/dotnet-instr-deployer-add-on/assets/windows_x86_64/bin/installer-wrapper.ps1 new file mode 100644 index 0000000000..ca949aeed7 --- /dev/null +++ b/packaging/dotnet-instr-deployer-add-on/assets/windows_x86_64/bin/installer-wrapper.ps1 @@ -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" +} diff --git a/packaging/dotnet-instr-deployer-add-on/cmd/splunk_otel_dotnet_deployer/deployer_windows.go b/packaging/dotnet-instr-deployer-add-on/cmd/splunk_otel_dotnet_deployer/deployer_windows.go new file mode 100644 index 0000000000..f588b24649 --- /dev/null +++ b/packaging/dotnet-instr-deployer-add-on/cmd/splunk_otel_dotnet_deployer/deployer_windows.go @@ -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 +} diff --git a/packaging/dotnet-instr-deployer-add-on/cmd/splunk_otel_dotnet_deployer/main.go b/packaging/dotnet-instr-deployer-add-on/cmd/splunk_otel_dotnet_deployer/main.go new file mode 100644 index 0000000000..58bfffa636 --- /dev/null +++ b/packaging/dotnet-instr-deployer-add-on/cmd/splunk_otel_dotnet_deployer/main.go @@ -0,0 +1,105 @@ +// 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. + +package main + +import ( + "encoding/xml" + "flag" + "io" + "log" + "os" + "path/filepath" + + "github.com/splunk/splunk_otel_dotnet_deployer/internal/modularinput" +) + +const ( + modularinputName = "splunk_otel_dotnet_deployer" +) + +func main() { + logCloseFunc := setupLogger() + defer logCloseFunc() + + schemeFlag := flag.Bool("scheme", false, "Print the scheme and exit") + validateFlag := flag.Bool("validate-arguments", false, "Validate the arguments and exit") + flag.Parse() + + if *schemeFlag { + os.Exit(0) + } + + if *validateFlag { + os.Exit(0) + } + + os.Exit(run()) +} + +func run() int { + input, err := modularinput.ReadXML(os.Stdin) + if err != nil { + log.Println("Error:", err) + return 1 + } + + prettyInput, err := xml.MarshalIndent(input, "", " ") + if err != nil { + log.Println("Error:", err) + return 1 + } + + log.Printf("Input:\n%s\n", prettyInput) + + if err := runDeployer(input, os.Stdin, os.Stdout, os.Stderr); err != nil { + log.Println("Error:", err) + return 1 + } + + return 0 +} + +// setupStandardLogger intializes the standard logger with settings appropriate for the deployer. +func setupLogger() (closer func()) { + // Setup the logger prefix to the proper date time format. + log.SetFlags(log.LstdFlags | log.Lmicroseconds | log.LUTC | log.Lshortfile) + + logFilePath, ok := buildLogFilePath() + if !ok { + return func() {} + } + + logFile, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + log.Printf("Error: failed to open log file %s: %v", logFilePath, err) + return func() {} + } + + multiWriter := io.MultiWriter(os.Stdout, logFile) + log.SetOutput(multiWriter) + + return func() { _ = logFile.Close() } +} + +// buildLogFilePath returns the path to the log file. +func buildLogFilePath() (string, bool) { + splunkHome, ok := os.LookupEnv("SPLUNK_HOME") + if !ok { + // Do not log to a file if SPLUNK_HOME is not set. + return "", false + } + + return filepath.Join(splunkHome, "var", "log", "splunk", modularinputName+".log"), true +} diff --git a/packaging/dotnet-instr-deployer-add-on/go.mod b/packaging/dotnet-instr-deployer-add-on/go.mod new file mode 100644 index 0000000000..240c5c014f --- /dev/null +++ b/packaging/dotnet-instr-deployer-add-on/go.mod @@ -0,0 +1,13 @@ +module github.com/splunk/splunk_otel_dotnet_deployer + +go 1.23.0 + +require github.com/stretchr/testify v1.10.0 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace github.com/splunk/splunk_otel_dotnet_deployer/internal/modularinput => ./internal/modularinput diff --git a/packaging/dotnet-instr-deployer-add-on/go.sum b/packaging/dotnet-instr-deployer-add-on/go.sum new file mode 100644 index 0000000000..713a0b4f0a --- /dev/null +++ b/packaging/dotnet-instr-deployer-add-on/go.sum @@ -0,0 +1,10 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/packaging/dotnet-instr-deployer-add-on/internal/modularinput/inputs_xml.go b/packaging/dotnet-instr-deployer-add-on/internal/modularinput/inputs_xml.go new file mode 100644 index 0000000000..928cf36ef9 --- /dev/null +++ b/packaging/dotnet-instr-deployer-add-on/internal/modularinput/inputs_xml.go @@ -0,0 +1,76 @@ +// 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. + +package modularinput + +import ( + "bufio" + "encoding/xml" + "fmt" + "io" + "strings" +) + +type Param struct { + Name string `xml:"name,attr"` + Value string `xml:",chardata"` +} + +type Stanza struct { + Name string `xml:"name,attr"` + App string `xml:"app,attr"` + Param []Param `xml:"param"` +} + +type Configuration struct { + Stanza []Stanza `xml:"stanza"` +} + +type Input struct { + XMLName xml.Name `xml:"input"` + ServerHost string `xml:"server_host"` + ServerURI string `xml:"server_uri"` + SessionKey string `xml:"session_key"` + CheckpointDir string `xml:"checkpoint_dir"` + Configuration Configuration `xml:"configuration"` +} + +func UnmarshalInputXML(data []byte) (*Input, error) { + var input Input + err := xml.Unmarshal(data, &input) + if err != nil { + return nil, fmt.Errorf("error unmarshaling 'input.conf' XML: %w", err) + } + + return &input, nil +} + +func ReadXML(reader io.Reader) (*Input, error) { + var xmlData strings.Builder + scanner := bufio.NewScanner(reader) + + for scanner.Scan() { + line := scanner.Text() + xmlData.WriteString(line) + if strings.Contains(line, "") { + break + } + } + + if err := scanner.Err(); err != nil { + return nil, fmt.Errorf("error reading input: %w", err) + } + + return UnmarshalInputXML([]byte(xmlData.String())) +} diff --git a/packaging/dotnet-instr-deployer-add-on/internal/modularinput/inputs_xml_test.go b/packaging/dotnet-instr-deployer-add-on/internal/modularinput/inputs_xml_test.go new file mode 100644 index 0000000000..2d1ef478bc --- /dev/null +++ b/packaging/dotnet-instr-deployer-add-on/internal/modularinput/inputs_xml_test.go @@ -0,0 +1,49 @@ +// 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. + +package modularinput + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestUnmarshalInputXML(t *testing.T) { + xmlPath := "testdata/Splunk_TA_otel.inputs.xml" + xmlData, err := os.ReadFile(xmlPath) + require.NoError(t, err, "Failed to read file %s", xmlPath) + + input, err := UnmarshalInputXML(xmlData) + require.NoError(t, err, "Expected no error") + + assert.Equal(t, "R91395DV", input.ServerHost, "Expected ServerHost to be 'R91395DV'") + assert.Equal(t, "https://127.0.0.1:8089", input.ServerURI, "Expected ServerURI to be 'https://127.0.0.1:8089'") + assert.Equal(t, "_fake_session_key", input.SessionKey, "Expected SessionKey to be '_fake_session_key'") + assert.Equal(t, `C:\Program Files\Splunk\var\lib\splunk\modinputs\Splunk_TA_otel`, input.CheckpointDir, "Expected CheckpointDir to be 'C:\\Program Files\\Splunk\\var\\lib\\splunk\\modinputs\\Splunk_TA_otel'") + require.Len(t, input.Configuration.Stanza, 1, "Expected 1 Stanza") + stanza := input.Configuration.Stanza[0] + assert.Equal(t, "Splunk_TA_otel://Splunk_TA_otel", stanza.Name, "Expected Stanza Name to be 'Splunk_TA_otel://Splunk_TA_otel'") + assert.Equal(t, "Splunk_TA_otel", stanza.App, "Expected Stanza App to be 'Splunk_TA_otel'") + assert.Len(t, stanza.Param, 16, "Expected 16 Params") +} + +func TestUnmarshalInputXML_InvalidXML(t *testing.T) { + invalidXMLData := `R91395DV` + + _, err := UnmarshalInputXML([]byte(invalidXMLData)) + require.Error(t, err, "Expected error") +} diff --git a/packaging/dotnet-instr-deployer-add-on/internal/modularinput/testdata/Splunk_TA_otel.inputs.xml b/packaging/dotnet-instr-deployer-add-on/internal/modularinput/testdata/Splunk_TA_otel.inputs.xml new file mode 100644 index 0000000000..e8a47773af --- /dev/null +++ b/packaging/dotnet-instr-deployer-add-on/internal/modularinput/testdata/Splunk_TA_otel.inputs.xml @@ -0,0 +1,27 @@ + + + R91395DV + https://127.0.0.1:8089 + _fake_session_key + C:\Program Files\Splunk\var\lib\splunk\modinputs\Splunk_TA_otel + + + false + $decideOnStartup + _internal + 60 + Splunk_TA_otel + $SPLUNK_OTEL_TA_HOME/local/access_token + https://api.us0.signalfx.com + $SPLUNK_OTEL_TA_PLATFORM_HOME/bin/agent-bundle + $SPLUNK_OTEL_TA_PLATFORM_HOME/bin/agent-bundle/run/collectd + $SPLUNK_OTEL_TA_HOME/configs/ta-agent-config.yaml + https://ingest.us0.signalfx.com + localhost + $SPLUNK_HOME/var/log/splunk/otel.log + us0 + https://ingest.us0.signalfx.com/v2/trace + false + + + diff --git a/packaging/dotnet-instr-deployer-add-on/internal/modularinput/testdata/install.inputs.xml b/packaging/dotnet-instr-deployer-add-on/internal/modularinput/testdata/install.inputs.xml new file mode 100644 index 0000000000..1bd332219d --- /dev/null +++ b/packaging/dotnet-instr-deployer-add-on/internal/modularinput/testdata/install.inputs.xml @@ -0,0 +1,13 @@ + + IP-ACA-BABA + https://127.0.0.1:9089 + _fake_session_key + C:\Program Files\SplunkUniversalForwarder\var\lib\splunk\modinputs\splunk_otel_dotnet_deployer + + + $decideOnStartup + default + false + + + diff --git a/packaging/dotnet-instr-deployer-add-on/internal/modularinput/testdata/uninstall.inputs.xml b/packaging/dotnet-instr-deployer-add-on/internal/modularinput/testdata/uninstall.inputs.xml new file mode 100644 index 0000000000..00dbe0a0e4 --- /dev/null +++ b/packaging/dotnet-instr-deployer-add-on/internal/modularinput/testdata/uninstall.inputs.xml @@ -0,0 +1,13 @@ + + IP-ACA-BABA + https://127.0.0.1:9089 + _fake_session_key + C:\Program Files\SplunkUniversalForwarder\var\lib\splunk\modinputs\splunk_otel_dotnet_deployer + + + $decideOnStartup + default + true + + + From 4df992df1210b40c77a3d93b58e8467c9564f955 Mon Sep 17 00:00:00 2001 From: Paulo Janotti Date: Thu, 6 Mar 2025 11:21:28 -0800 Subject: [PATCH 2/2] Upload Splunk_TA_otel as asset of each splunk-ta-otel workflow (#5952) --- .github/workflows/splunk-ta-otel.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/splunk-ta-otel.yml b/.github/workflows/splunk-ta-otel.yml index 10fa80e513..2d12a93bda 100644 --- a/.github/workflows/splunk-ta-otel.yml +++ b/.github/workflows/splunk-ta-otel.yml @@ -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