Skip to content

Commit

Permalink
support core service validate command
Browse files Browse the repository at this point in the history
  • Loading branch information
rmfitzpatrick committed Jan 18, 2024
1 parent 8995a63 commit f5aa2c6
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 5 deletions.
21 changes: 16 additions & 5 deletions internal/settings/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,8 @@ func parseArgs(args []string) (*Settings, error) {
settings.setProperties, settings.discoveryProperties = parseSetOptionArguments(settings.setOptionArguments.value)

// Pass flags that are handled by the collector core service as raw command line arguments.
settings.colCoreArgs = flagSetToArgs(colCoreFlags, flagSet)
colCoreCommands := []string{"validate"}
settings.colCoreArgs = flagSetToArgs(colCoreFlags, colCoreCommands, flagSet)

return settings, nil
}
Expand All @@ -320,12 +321,12 @@ func parseSetOptionArguments(arguments []string) (setProperties, discoveryProper
return
}

// flagSetToArgs takes a list of flag names and returns a list of corresponding command line arguments
// using values from the provided flagSet.
// flagSetToArgs takes slices of core service flag names and arguments and returns a slice of corresponding command line
// arguments using values suitable for being passed to the underlying collector service.
// The flagSet must be populated (flagSet.Parse is called), otherwise the returned list of arguments will be empty.
func flagSetToArgs(flagNames []string, flagSet *flag.FlagSet) []string {
func flagSetToArgs(colFlagNames, colCommands []string, flagSet *flag.FlagSet) []string {
var out []string
for _, flagName := range flagNames {
for _, flagName := range colFlagNames {
flag := flagSet.Lookup(flagName)
if flag.Changed {
switch fv := flag.Value.(type) {
Expand All @@ -338,6 +339,16 @@ func flagSetToArgs(flagNames []string, flagSet *flag.FlagSet) []string {
}
}
}

allowed := map[string]struct{}{}
for _, cmd := range colCommands {
allowed[cmd] = struct{}{}
}
for _, arg := range flagSet.Args() {
if _, ok := allowed[arg]; ok {
out = append(out, arg)
}
}
return out
}

Expand Down
8 changes: 8 additions & 0 deletions internal/settings/settings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,14 @@ func TestSplunkConfigYamlNotUtilizedInResolverURIsWithConfigEnvVar(t *testing.T)
require.Equal(t, []string{localGatewayConfig}, settings.ResolverURIs())
}

func TestNewSettingsWithValidate(t *testing.T) {
t.Cleanup(setRequiredEnvVars(t))
settings, err := New([]string{"validate"})
require.NoError(t, err)
require.NotNil(t, settings)
require.Equal(t, []string{"--feature-gates", "-telemetry.useOtelForInternalMetrics", "validate"}, settings.ColCoreArgs())
}

func TestCheckRuntimeParams_Default(t *testing.T) {
t.Cleanup(setRequiredEnvVars(t))
require.NoError(t, os.Setenv(ConfigEnvVar, localGatewayConfig))
Expand Down
157 changes: 157 additions & 0 deletions tests/general/validate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// 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 integration

package tests

import (
"fmt"
"regexp"
"testing"
"time"

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

"github.com/signalfx/splunk-otel-collector/tests/testutils"
)

func TestCoreValidateDefaultConfig(t *testing.T) {
tc := testutils.NewTestcase(t)
defer tc.PrintLogsOnFailure()
defer tc.ShutdownOTLPReceiverSink()

c, shutdown := tc.SplunkOtelCollectorContainer(
"", func(collector testutils.Collector) testutils.Collector {
// deferring running service for exec
c := collector.WithEnv(
map[string]string{
"SPLUNK_REALM": "noop",
"SPLUNK_ACCESS_TOKEN": "noop",
},
).WithArgs("-c", "trap exit SIGTERM ; echo ok ; while true; do : ; done")
cc := c.(*testutils.CollectorContainer)
cc.Container = cc.Container.WithEntrypoint("bash").WillWaitForLogs("ok")
return cc
},
)

defer shutdown()

for _, config := range []string{"gateway", "agent"} {
config := config
t.Run(config, func(t *testing.T) {
sc, stdout, stderr := c.Container.AssertExec(t, 15*time.Second,
"bash", "-c", fmt.Sprintf("/otelcol --config /etc/otel/collector/%s_config.yaml validate", config),
)
assert.Zero(t, sc)
require.Empty(t, stdout)
require.False(t, regexp.MustCompile("(?i)error").MatchString(stderr))
})
}
}

func TestCoreValidateYamlProvider(t *testing.T) {
tc := testutils.NewTestcase(t)
defer tc.PrintLogsOnFailure()
defer tc.ShutdownOTLPReceiverSink()

config := `exporters:
debug:
verbosity: detailed
receivers:
hostmetrics:
collection_interval: 10s
scrapers:
cpu:
service:
pipelines:
metrics:
exporters:
- debug
receivers:
- hostmetrics
`

c, shutdown := tc.SplunkOtelCollectorContainer(
"", func(collector testutils.Collector) testutils.Collector {
// deferring running service for exec
c := collector.WithEnv(
map[string]string{
"SPLUNK_CONFIG": "",
"SPLUNK_CONFIG_YAML": config,
},
).WithArgs("-c", "trap exit SIGTERM ; echo ok ; while true; do : ; done")
cc := c.(*testutils.CollectorContainer)
cc.Container = cc.Container.WithEntrypoint("bash").WillWaitForLogs("ok")
return cc
},
)

defer shutdown()

sc, stdout, stderr := c.Container.AssertExec(t, 15*time.Second,
"bash", "-c", "/otelcol validate",
)
assert.Zero(t, sc)
require.Empty(t, stdout)
require.False(t, regexp.MustCompile("(?i)error").MatchString(stderr))
}

func TestCoreValidateDetectsInvalidYamlProvider(t *testing.T) {
tc := testutils.NewTestcase(t)
defer tc.PrintLogsOnFailure()
defer tc.ShutdownOTLPReceiverSink()

config := `exporters:
not-real:
endpoint: an-endpoint
receivers:
hostmetrics:
collection_interval: 10s
scrapers:
service:
pipelines:
metrics:
exporters:
- not-real
receivers:
- hostmetrics
`

c, shutdown := tc.SplunkOtelCollectorContainer(
"", func(collector testutils.Collector) testutils.Collector {
// deferring running service for exec
c := collector.WithEnv(
map[string]string{
"SPLUNK_CONFIG": "",
"SPLUNK_CONFIG_YAML": config,
},
).WithArgs("-c", "trap exit SIGTERM ; echo ok ; while true; do : ; done")
cc := c.(*testutils.CollectorContainer)
cc.Container = cc.Container.WithEntrypoint("bash").WillWaitForLogs("ok")
return cc
},
)

defer shutdown()

sc, stdout, stderr := c.Container.AssertExec(t, 15*time.Second,
"bash", "-c", "/otelcol validate",
)
require.Equal(t, 1, sc)
require.Empty(t, stdout)
require.Contains(t, stderr, `error decoding 'exporters': unknown type: "not-real"`)
}

0 comments on commit f5aa2c6

Please sign in to comment.