Skip to content

[TA] Linux Java autoinstrumentation TA #6308

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions packaging/technical-addon/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ SPLUNK_OTELCOL_DOWNLOAD_BASE?=https://github.com/signalfx/splunk-otel-collector/
PLATFORM?=linux
ARCH?=amd64

# include autoinstrumentation
AUTOINSTRUMENTATION_DIR:=$(SRC_ROOT)/instrumentation

# Used for testing & validation
ORCA_CLOUD?=kubernetes
UF_VERSION?=8.2.7
Expand All @@ -29,27 +32,33 @@ MODINPUT_CONFIG_GENERATOR := $(TOOLS_DIR)/modinput_config_generator
ta-build-tools:
@echo "Building tools..."
@mkdir -p $(TOOLS_DIR)
go build -o $(MODINPUT_CONFIG_GENERATOR) ./cmd/modinput_config_generator
cd $(ADDONS_SOURCE_DIR) && go build -o $(MODINPUT_CONFIG_GENERATOR) ./cmd/modinput_config_generator

.PHONY: test-ta-build-tools
test-ta-build-tools: ta-build-tools
$(MODINPUT_CONFIG_GENERATOR) -source-dir=$(ADDONS_SOURCE_DIR)/cmd/modinput_config_generator/internal/testdata -schema-name=Sample_Addon --build-dir=$(BUILD_DIR) || exit 1; \
mkdir -p $(BUILD_DIR)/Sample_Addon/$(PLATFORM)_$(SPLUNK_ARCH)/bin; \
go build $(GO_BUILD_FLAGS) -o $(BUILD_DIR)/Sample_Addon/$(PLATFORM)_$(SPLUNK_ARCH)/bin/Sample_Addon $(ADDONS_SOURCE_DIR)/cmd/modinput_config_generator/internal/testdata/pkg/sample_addon/runner || exit 1; \
cd $(ADDONS_SOURCE_DIR) && go build $(GO_BUILD_FLAGS) -o $(BUILD_DIR)/Sample_Addon/$(PLATFORM)_$(SPLUNK_ARCH)/bin/Sample_Addon $(ADDONS_SOURCE_DIR)/cmd/modinput_config_generator/internal/testdata/pkg/sample_addon/runner || exit 1; \
echo "built addon, testing..."
go test -v ./...
cd $(ADDONS_SOURCE_DIR) && go test -v `go list ./... | grep --invert-match pkg`


.PHONY: gen-modinput-config
gen-modinput-config:
@echo "Generating runner configs..."
@for schema in $(MODULAR_INPUT_SCHEMAS); do \
schema_lower=$$(echo $$schema | tr '[:upper:]' '[:lower:]'); \
echo "Generating config and TA scaffold for $$schema..."; \
rm -rf $(BUILD_DIR)/$$schema/; \
mkdir -p $(BUILD_DIR)/$$schema/; \
$(MODINPUT_CONFIG_GENERATOR) -source-dir=$(ADDONS_SOURCE_DIR) -schema-name=$$schema --build-dir=$(BUILD_DIR) || exit 1; \
ls -lAh $(BUILD_DIR); \
done

.PHONY: build-tas
build-tas: gen-modinput-config ta-build-deps-all build-ta-runners

.PHONY: build-ta-runners
build-ta-runners:
@echo "Building runner binaries..."
@for schema in $(MODULAR_INPUT_SCHEMAS); do \
Expand All @@ -65,6 +74,21 @@ build-ta-runners:
done \
done

.PHONY: generate-technical-addon-linux-autoinstrumentation
generate-technical-addon-linux-autoinstrumentation:
cd $(AUTOINSTRUMENTATION_DIR) && $(MAKE) dist
mkdir -p $(BUILD_DIR)/Splunk_TA_otel_linux_autoinstrumentation/linux_x86_64/bin;
mkdir -p $(BUILD_DIR)
PLATFORM="all" \
BUILD_DIR="$(BUILD_DIR)" \
SOURCE_DIR="$(ADDONS_SOURCE_DIR)" \
AUTOINSTRUMENTATION_DIR="$(AUTOINSTRUMENTATION_DIR)" \
$(ADDONS_SOURCE_DIR)/packaging-scripts/download-autoinstrumentation.sh


.PHONY: ta-build-deps-all
ta-build-deps-all: generate-technical-addon-linux-autoinstrumentation

.PHONY: generate-technical-addon
generate-technical-addon: env-guard-all
BUILD_DIR="$(BUILD_DIR)" \
Expand Down
6 changes: 6 additions & 0 deletions packaging/technical-addon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,9 @@ Further, they may remove the agent bundle downloaded to the `bin/` folder in the
As with all TAs, any changes made to `configs` will be overwritten.
Customers should copy any relevant custom configuration from `configs/` or `defaults/`
to `local/`.

# Autoinstrumentation
For all, you may run `build-linux-autoinstrumentation-ta`.
For specific targets, you may run
1. `make generate-technical-addon-linux-autoinstrumentation` (makes autoinstrumentation and dependencies)
2. `make gen-modinput-config && make build-ta-runners`
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
"testing"
"time"

"github.com/splunk/splunk-technical-addon/internal/testaddon"

"github.com/splunk/splunk-technical-addon/internal/packaging"
"github.com/splunk/splunk-technical-addon/internal/testcommon"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -81,7 +83,7 @@ func TestRunner(t *testing.T) {
require.NotEmpty(t, buildDir)
err := packaging.PackageAddon(filepath.Join(buildDir, "Sample_Addon"), addonPath)
require.NoError(t, err)
tc := testcommon.StartSplunk(t, testcommon.SplunkStartOpts{
tc := testaddon.StartSplunk(t, testaddon.SplunkStartOpts{
AddonPaths: []string{addonPath},
WaitStrategy: wait.ForExec([]string{"sudo", "stat", "/opt/splunk/var/log/splunk/Sample_Addon.log"}).WithStartupTimeout(time.Minute * 4),
})
Expand Down
1 change: 0 additions & 1 deletion packaging/technical-addon/internal/modularinput/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ type GenericModularInput struct {
ModularInputs map[string]*ModInput
SchemaName string
}

type TemplateData struct {
ModularInputs map[string]ModInputConfig `yaml:"modular-inputs"`
SchemaName string `yaml:"modular-input-schema-name"`
Expand Down
49 changes: 49 additions & 0 deletions packaging/technical-addon/internal/modularinput/spec_test.go
Original file line number Diff line number Diff line change
@@ -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 (
"path/filepath"
"testing"

"github.com/splunk/splunk-technical-addon/internal/testcommon"
"github.com/stretchr/testify/require"
)

func TestLoadConfig(t *testing.T) {
actual, err := LoadConfig("./testdata/sample-modular-inputs.yaml")
require.NoError(t, err)
require.EqualValues(t,
&TemplateData{
ModularInputs: map[string]ModInputConfig{
"everything_set": {Description: "SET ALL THE THINGS", Default: "$SPLUNK_OTEL_TA_HOME/local/access_token", Flag: Flag{Name: "test-flag", IsUnary: false}, Required: false, PassthroughEnvVar: true, ReplaceableEnvVar: true},
"minimal_set": {Description: "This is all you need", Default: "", Flag: Flag{Name: "", IsUnary: false}, Required: false, PassthroughEnvVar: false, ReplaceableEnvVar: false},
"minimal_set_required": {Description: "hello", Default: "", Flag: Flag{Name: "", IsUnary: false}, Required: true, PassthroughEnvVar: false, ReplaceableEnvVar: false},
"unary_flag_with_everything_set": {Description: "Unary flags don't take arguments/values and are either present or not", Default: "$SPLUNK_OTEL_TA_HOME/local/access_token", Flag: Flag{Name: "test-flag", IsUnary: true}, Required: false, PassthroughEnvVar: true, ReplaceableEnvVar: true},
},
SchemaName: "Sample_Addon",
Version: "1.2.3",
}, actual)

}

func TestRenderTemplate(t *testing.T) {
sampleTemplateData, err := LoadConfig("./testdata/sample-modular-inputs.yaml")
require.NoError(t, err)
actualRender := filepath.Join(t.TempDir(), "render_template.txt")
err = RenderTemplate("./testdata/sample-template.tmpl", actualRender, sampleTemplateData)
require.NoError(t, err)
testcommon.AssertFilesMatch(t, "./testdata/expected-template-rendered.txt", actualRender)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[Sample_Addon://Sample_Addon]
disabled=false
start_by_shell=false
interval=60
index=_internal
sourcetype=Sample_Addon
everything_set=$SPLUNK_OTEL_TA_HOME/local/access_token
minimal_set_required=
unary_flag_with_everything_set=$SPLUNK_OTEL_TA_HOME/local/access_token
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
modular-input-schema-name: Sample_Addon
version: "1.2.3"
modular-inputs:
everything_set:
description: "SET ALL THE THINGS"
default: "$SPLUNK_OTEL_TA_HOME/local/access_token"
passthrough: true
replaceable: true
flag:
name: "test-flag"
is-unary: false

minimal_set:
description: "This is all you need"

unary_flag_with_everything_set:
description: "Unary flags don't take arguments/values and are either present or not"
default: "$SPLUNK_OTEL_TA_HOME/local/access_token"
passthrough: true
replaceable: true
flag:
name: "test-flag"
is-unary: true

minimal_set_required:
description: "hello"
required: true

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[{{ .SchemaName }}://{{ .SchemaName }}]
disabled=false
start_by_shell=false
interval=60
index=_internal
sourcetype={{ .SchemaName }}

{{- range $name, $inputConfig := .ModularInputs }}
{{- if $inputConfig.Default }}
{{ $name }}={{ $inputConfig.Default }}
{{- else if $inputConfig.Required }}
{{ $name }}=
{{- end }}
{{- end }}
83 changes: 83 additions & 0 deletions packaging/technical-addon/internal/packaging/targz.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ package packaging
import (
"archive/tar"
"compress/gzip"
"fmt"
"io"
"os"
"path/filepath"
"strings"
)

func PackageAddon(sourceDir, outputFile string) error {
Expand Down Expand Up @@ -76,3 +78,84 @@ func PackageAddon(sourceDir, outputFile string) error {

return err
}

// ExtractAddon extracts a .tar.gz file from sourcePath to destinationPath
func ExtractAddon(sourcePath, destinationPath string) error {
file, err := os.Open(sourcePath)
if err != nil {
return fmt.Errorf("failed to open archive: %w", err)
}
defer file.Close()

gzipReader, err := gzip.NewReader(file)
if err != nil {
return fmt.Errorf("failed to create gzip reader: %w", err)
}
defer gzipReader.Close()

tarReader := tar.NewReader(gzipReader)

for {
header, err := tarReader.Next()
if err == io.EOF {
// End of archive
break
}
if err != nil {
return fmt.Errorf("error reading tar header: %w", err)
}

// Create the full path for the file
target := filepath.Join(destinationPath, header.Name) // #nosec G305

// Mitigation for gosec G305
if !isInDirectory(target, destinationPath) {
return fmt.Errorf("illegal path traversal attempt: %s", header.Name)
}

switch header.Typeflag {
case tar.TypeDir:
if err := os.MkdirAll(target, header.FileInfo().Mode()); err != nil {
return fmt.Errorf("failed to create directory %s: %w", target, err)
}

case tar.TypeReg:
if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
return fmt.Errorf("failed to create directory for file %s: %w", target, err)
}

file, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, header.FileInfo().Mode())
if err != nil {
return fmt.Errorf("failed to create file %s: %w", target, err)
}

// #nosec G110 We only use this for packaging on our systems, this module not included for code in addon itself
if _, err := io.Copy(file, tarReader); err != nil {
file.Close()
return fmt.Errorf("failed to write file %s: %w", target, err)
}
file.Close()

default:
fmt.Printf("Skipping unsupported file type: %c for %s\n", header.Typeflag, header.Name)
}
}

return nil
}

// isInDirectory checks if the path is inside the specified directory (prevents path traversal)
func isInDirectory(path, directory string) bool {
// Convert to absolute paths
absPath, err := filepath.Abs(path)
if err != nil {
return false
}
absDir, err := filepath.Abs(directory)
if err != nil {
return false
}

// Check if the path is within the directory
return strings.HasPrefix(absPath, absDir)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello, World!
36 changes: 36 additions & 0 deletions packaging/technical-addon/internal/packaging/validation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// 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 packaging

import (
"crypto/sha256"
"encoding/hex"
"io"
"os"
"strings"
)

func Sha256Sum(filePath string) (string, error) {
file, err := os.Open(filePath)
if err != nil {
return "", err
}
data, err := io.ReadAll(file)
if err != nil {
return "", err
}
sum := sha256.Sum256([]byte(strings.TrimSpace(string(data))))
return hex.EncodeToString(sum[:]), nil
}
29 changes: 29 additions & 0 deletions packaging/technical-addon/internal/packaging/validation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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 packaging

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestSha256(t *testing.T) {
sum, err := Sha256Sum("./testdata/sampletosha.txt")
require.NoError(t, err)
// Expected generated with linux sha256sum utility
assert.Equal(t, "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f", sum)
}
Loading
Loading