Skip to content

Commit

Permalink
set default SPLUNK_LISTEN_INTERFACE to 127.0.0.1 for agent configs
Browse files Browse the repository at this point in the history
  • Loading branch information
rmfitzpatrick committed Oct 5, 2023
1 parent bfa8a8e commit 8470072
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 63 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### 🛑 Breaking changes 🛑

- (Splunk) Set `SPLUNK_LISTEN_INTERFACE` environment variable value to 127.0.0.1 for agent mode by default, as determined by config path. 0.0.0.0 will be set otherwise, with existing environment values respected. The installers have been updated to only set the environment variable for collector service if configured directly.

## v0.85.0

***ADVANCED NOTICE - SPLUNK_LISTEN_INTERFACE DEFAULTS***
Expand Down
65 changes: 51 additions & 14 deletions internal/settings/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import (
"fmt"
"log"
"os"
"path/filepath"
"regexp"
"runtime"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -58,8 +60,19 @@ const (
DefaultMemoryLimitPercentage = 90
DefaultMemoryTotalMiB = 512
DefaultListenInterface = "0.0.0.0"
DefaultAgentConfigLinux = "/etc/otel/collector/agent_config.yaml"
)

var DefaultAgentConfigWindows = func() string {
path := filepath.Join("Splunk", "OpenTelemetry Collector", "agent_config.yaml")
if runtime.GOOS == "windows" {
if pd, ok := os.LookupEnv("ProgramData"); ok {
path = filepath.Join(pd, path)
}
}
return filepath.Clean(path)
}()

var (
envProvider = envprovider.New()
fileProvider = fileprovider.New()
Expand Down Expand Up @@ -98,7 +111,7 @@ func New(args []string) (*Settings, error) {
return nil, err
}

if err = setDefaultEnvVars(); err != nil {
if err = setDefaultEnvVars(s); err != nil {
return nil, err
}

Expand Down Expand Up @@ -346,25 +359,27 @@ func checkRuntimeParams(settings *Settings) error {
if 2*ballastSize > memLimit {
return fmt.Errorf("memory limit (%d) is less than 2x ballast (%d). Increase memory limit or decrease ballast size", memLimit, ballastSize)
}
if os.Getenv(ListenInterfaceEnvVar) == "" {
os.Setenv(ListenInterfaceEnvVar, DefaultListenInterface)
}

return nil
}

func setDefaultEnvVars() error {
type ev struct{ e, v string }
func setDefaultEnvVars(s *Settings) error {
type ev struct {
e, v string
log bool
}

envVars := []ev{{e: ConfigServerEnabledEnvVar, v: "true"}}
envVars := []ev{
{e: ListenInterfaceEnvVar, v: defaultListenAddr(s), log: true},
{e: ConfigServerEnabledEnvVar, v: "true"},
}

if realm, ok := os.LookupEnv(RealmEnvVar); ok {
envVars = append(envVars,
ev{e: APIURLEnvVar, v: fmt.Sprintf("https://api.%s.signalfx.com", realm)},
ev{e: IngestURLEnvVar, v: fmt.Sprintf("https://ingest.%s.signalfx.com", realm)},
ev{e: TraceIngestURLEnvVar, v: fmt.Sprintf("https://ingest.%s.signalfx.com/v2/trace", realm)},
ev{e: HecLogIngestURLEnvVar, v: fmt.Sprintf("https://ingest.%s.signalfx.com/v1/log", realm)},
ev{e: ListenInterfaceEnvVar, v: "0.0.0.0"},
)
}

Expand All @@ -377,11 +392,33 @@ func setDefaultEnvVars() error {
if err := os.Setenv(envVar.e, envVar.v); err != nil {
return err
}
if envVar.log {
log.Printf("set %q to %q", envVar.e, envVar.v)
}
}
}
return nil
}

func defaultListenAddr(s *Settings) string {
if s != nil {
for _, path := range s.configPaths.value {
scheme, location, isURI := parseURI(path)
if isURI && scheme == "file" {
path = location
}
cleaned := filepath.Clean(path)
if path == DefaultAgentConfigLinux ||
cleaned == DefaultAgentConfigLinux ||
path == DefaultAgentConfigWindows ||
cleaned == DefaultAgentConfigWindows {
return "127.0.0.1"
}
}
}
return DefaultListenInterface
}

// Config priority (highest to lowest):
// 1. '--config' flags (multiple supported),
// 2. SPLUNK_CONFIG env var,
Expand Down Expand Up @@ -517,19 +554,19 @@ func checkInputConfigs(settings *Settings) error {
}

func checkConfigPathEnvVar(settings *Settings) error {
configPathVar := os.Getenv(ConfigEnvVar)
configPath := os.Getenv(ConfigEnvVar)
configYaml := os.Getenv(ConfigYamlEnvVar)

if _, err := os.Stat(configPathVar); err != nil {
return fmt.Errorf("unable to find the configuration file (%s), ensure %s environment variable is set properly: %w", configPathVar, ConfigEnvVar, err)
if _, err := os.Stat(configPath); err != nil {
return fmt.Errorf("unable to find the configuration file (%s), ensure %s environment variable is set properly: %w", configPath, ConfigEnvVar, err)
}

if configYaml != "" {
log.Printf("Both %s and %s were specified. Using %s environment variable value %s for this session", ConfigEnvVar, ConfigYamlEnvVar, ConfigEnvVar, configPathVar)
log.Printf("Both %s and %s were specified. Using %s environment variable value %s for this session", ConfigEnvVar, ConfigYamlEnvVar, ConfigEnvVar, configPath)
}

if !settings.configPaths.contains(configPathVar) {
_ = settings.configPaths.Set(configPathVar)
if !settings.configPaths.contains(configPath) {
_ = settings.configPaths.Set(configPath)
}

return confirmRequiredEnvVarsForDefaultConfigs(settings.configPaths.value)
Expand Down
117 changes: 81 additions & 36 deletions internal/settings/settings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"testing"

flag "github.com/spf13/pflag"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/confmap"

Expand Down Expand Up @@ -225,11 +226,11 @@ func TestCheckRuntimeParams_MemTotalEnv(t *testing.T) {

func TestCheckRuntimeParams_ListenInterface(t *testing.T) {
t.Cleanup(setRequiredEnvVars(t))
require.NoError(t, os.Setenv(ListenInterfaceEnvVar, "127.0.0.1"))
require.NoError(t, os.Setenv(ListenInterfaceEnvVar, "1.2.3.4"))
settings, err := New([]string{})
require.NoError(t, err)
require.NotNil(t, settings)
require.Equal(t, "127.0.0.1", os.Getenv(ListenInterfaceEnvVar))
require.Equal(t, "1.2.3.4", os.Getenv(ListenInterfaceEnvVar))
}

func TestCheckRuntimeParams_MemTotalAndBallastEnvs(t *testing.T) {
Expand Down Expand Up @@ -258,55 +259,99 @@ func TestCheckRuntimeParams_LimitAndBallastEnvs(t *testing.T) {
require.Equal(t, "250", os.Getenv(MemLimitMiBEnvVar))
}

func TestSetDefaultEnvVars(t *testing.T) {
func TestSetDefaultEnvVarsOnlySetsURLsWithRealmSet(t *testing.T) {
t.Cleanup(clearEnv(t))

testArgs := []string{"SPLUNK_API_URL", "SPLUNK_INGEST_URL", "SPLUNK_TRACE_URL", "SPLUNK_HEC_URL", "SPLUNK_HEC_TOKEN", "SPLUNK_LISTEN_INTERFACE"}
for _, v := range testArgs {
setDefaultEnvVars()
envVars := []string{"SPLUNK_API_URL", "SPLUNK_INGEST_URL", "SPLUNK_TRACE_URL", "SPLUNK_HEC_URL", "SPLUNK_HEC_TOKEN"}
for _, v := range envVars {
require.NoError(t, setDefaultEnvVars(nil))
_, ok := os.LookupEnv(v)
require.False(t, ok, fmt.Sprintf("Expected %q unset given SPLUNK_ACCESS_TOKEN or SPLUNK_TOKEN is unset", v))
require.False(t, ok, fmt.Sprintf("Expected %q unset given SPLUNK_REALM is unset", v))
}
}

realm := "us1"
token := "1234"
valTest := "test"
valEmpty := ""
func TestSetDefaultEnvVarsOnlySetsHECTokenWithTokenSet(t *testing.T) {
t.Cleanup(clearEnv(t))
require.NoError(t, setDefaultEnvVars(nil))
_, ok := os.LookupEnv("SPLUNK_HEC_TOKEN")
require.False(t, ok, "Expected SPLUNK_HEC_TOKEN unset given SPLUNK_ACCESS_TOKEN is unset")
}

func TestSetDefaultEnvVarsSetsURLsFromRealm(t *testing.T) {
t.Cleanup(clearEnv(t))

realm := "us1"
os.Setenv("SPLUNK_REALM", realm)
os.Setenv("SPLUNK_ACCESS_TOKEN", token)
setDefaultEnvVars()
testArgs2 := [][]string{
require.NoError(t, setDefaultEnvVars(nil))

expectedEnvVars := [][]string{
{"SPLUNK_API_URL", fmt.Sprintf("https://api.%s.signalfx.com", realm)},
{"SPLUNK_INGEST_URL", fmt.Sprintf("https://ingest.%s.signalfx.com", realm)},
{"SPLUNK_TRACE_URL", fmt.Sprintf("https://ingest.%s.signalfx.com/v2/trace", realm)},
{"SPLUNK_HEC_URL", fmt.Sprintf("https://ingest.%s.signalfx.com/v1/log", realm)},
{"SPLUNK_HEC_TOKEN", token},
{"SPLUNK_LISTEN_INTERFACE", "0.0.0.0"},
}
for _, v := range testArgs2 {
val, _ := os.LookupEnv(v[0])
if val != v[1] {
t.Errorf("Expected %v got %v for %v", v[1], val, v[0])
}
for _, v := range expectedEnvVars {
val, ok := os.LookupEnv(v[0])
assert.True(t, ok, v[0])
assert.Equal(t, val, v[1])
}
}

for _, v := range testArgs {
os.Setenv(v, valTest)
setDefaultEnvVars()
val, _ := os.LookupEnv(v)
if val != valTest {
t.Errorf("Expected %v got %v for %v", valTest, val, v)
}
func TestSetDefaultEnvVarsSetsHECTokenFromAccessTokenEnvVar(t *testing.T) {
t.Cleanup(clearEnv(t))

token := "1234"
os.Setenv("SPLUNK_ACCESS_TOKEN", token)
require.NoError(t, setDefaultEnvVars(nil))

val, ok := os.LookupEnv("SPLUNK_HEC_TOKEN")
assert.True(t, ok)
assert.Equal(t, token, val)
}

func TestSetDefaultEnvVarsRespectsSetEnvVars(t *testing.T) {
t.Cleanup(clearEnv(t))
envVars := []string{"SPLUNK_API_URL", "SPLUNK_INGEST_URL", "SPLUNK_TRACE_URL", "SPLUNK_HEC_URL", "SPLUNK_HEC_TOKEN", "SPLUNK_LISTEN_INTERFACE"}

someValue := "some.value"
for _, v := range envVars {
os.Setenv(v, someValue)
require.NoError(t, setDefaultEnvVars(nil))
val, ok := os.LookupEnv(v)
assert.True(t, ok, v[0])
assert.Equal(t, someValue, val)
}

for _, v := range testArgs {
os.Setenv(v, valEmpty)
setDefaultEnvVars()
val, _ := os.LookupEnv(v)
if val != valEmpty {
t.Errorf("Expected %v got %v for %v", valEmpty, val, v)
}
for _, v := range envVars {
os.Setenv(v, "")
require.NoError(t, setDefaultEnvVars(nil))
val, ok := os.LookupEnv(v)
assert.True(t, ok, v[0])
assert.Empty(t, val)
}
}

func TestSetDefaultEnvVarsSetsInterfaceFromConfigOption(t *testing.T) {
for _, tc := range []struct{ config, expectedIP string }{
{"/etc/otel/collector/agent_config.yaml", "127.0.0.1"},
{"file:/etc/otel/collector/agent_config.yaml", "127.0.0.1"},
{"/etc/otel/collector/gateway_config.yaml", "0.0.0.0"},
{"file:/etc/otel/collector/gateway_config.yaml", "0.0.0.0"},
{"some-other-config.yaml", "0.0.0.0"},
{"file:some-other-config.yaml", "0.0.0.0"},
} {
tc := tc
t.Run(fmt.Sprintf("%v->%v", tc.config, tc.expectedIP), func(t *testing.T) {
t.Cleanup(clearEnv(t))
os.Setenv("SPLUNK_REALM", "noop")
os.Setenv("SPLUNK_ACCESS_TOKEN", "noop")
s, err := parseArgs([]string{"--config", tc.config})
require.NoError(t, err)
require.NoError(t, setDefaultEnvVars(s))

val, ok := os.LookupEnv("SPLUNK_LISTEN_INTERFACE")
assert.True(t, ok)
assert.Equal(t, tc.expectedIP, val)
})
}
}

Expand Down
51 changes: 51 additions & 0 deletions internal/settings/settings_windows_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// 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

package settings

import (
"fmt"
"os"
"path/filepath"
"testing"

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

func TestSetDefaultEnvVarsSetsInterfaceFromConfigOptionWithProgramData(t *testing.T) {
pd := os.Getenv("ProgramData")
for _, tc := range []struct{ config, expectedIP string }{
{filepath.Join(pd, "Splunk", "OpenTelemetry Collector", "agent_config.yaml"), "127.0.0.1"},
{fmt.Sprintf("file:%s", filepath.Join(pd, "Splunk", "OpenTelemetry Collector", "agent_config.yaml")), "127.0.0.1"},
{"\\some-other-config.yaml", "0.0.0.0"},
{"file:\\some-other-config.yaml", "0.0.0.0"},
} {
tc := tc
t.Run(fmt.Sprintf("%v->%v", tc.config, tc.expectedIP), func(t *testing.T) {
t.Cleanup(clearEnv(t))
os.Setenv("SPLUNK_REALM", "noop")
os.Setenv("SPLUNK_ACCESS_TOKEN", "noop")
s, err := parseArgs([]string{"--config", tc.config})
require.NoError(t, err)
require.NoError(t, setDefaultEnvVars(s))

val, ok := os.LookupEnv("SPLUNK_LISTEN_INTERFACE")
assert.True(t, ok)
assert.Equal(t, tc.expectedIP, val)
})
}
}
Loading

0 comments on commit 8470072

Please sign in to comment.