Skip to content

Commit c432a65

Browse files
feat: add 'config validate' command to diagnose config issues without other checks (#232)
### Description Add 'config validate' command to diagnose config issues without other checks. This can be used by our helm chart to check all of the config maps. Examples: ```sh $ ./observe-agent config validate ❌ invalid config Error: service::pipelines::metrics/agent-filestats: references exporter "otlphttp/observemetrics2" which is not configured # after fixing my config $ ./observe-agent config validate ✅ configuration is valid ``` This also adds a hidden `config-mode` flag so you can (e.g.) validate the bundled docker config from a mac build: ```sh $ ./observe-agent config --render-otel | grep eventlog $ ./observe-agent --config-mode windows config --render-otel | grep eventlog windowseventlog/host_monitoring-application: windowseventlog/host_monitoring-security: windowseventlog/host_monitoring-system: - windowseventlog/host_monitoring-application - windowseventlog/host_monitoring-security - windowseventlog/host_monitoring-system ```
1 parent efde8b0 commit c432a65

File tree

5 files changed

+65
-10
lines changed

5 files changed

+65
-10
lines changed

internal/commands/config/config.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"github.com/observeinc/observe-agent/internal/commands/util/logger"
1212
"github.com/observeinc/observe-agent/internal/root"
13+
"github.com/observeinc/observe-agent/observecol"
1314
"github.com/spf13/cobra"
1415
)
1516

@@ -41,7 +42,32 @@ bundled OTel configuration.`,
4142
},
4243
}
4344

45+
var configValidateCmd = &cobra.Command{
46+
Use: "validate",
47+
Short: "Validates the configuration for this agent.",
48+
SilenceUsage: true,
49+
RunE: func(cmd *cobra.Command, args []string) error {
50+
ctx := logger.WithCtx(context.Background(), logger.GetNop())
51+
col, cleanup, err := observecol.GetOtelCollector(ctx)
52+
if cleanup != nil {
53+
defer cleanup()
54+
}
55+
if err != nil {
56+
fmt.Fprintln(os.Stderr, "❌ failed to generate config")
57+
return err
58+
}
59+
err = col.DryRun(ctx)
60+
if err != nil {
61+
fmt.Fprintln(os.Stderr, "❌ invalid config")
62+
return err
63+
}
64+
fmt.Fprintln(os.Stderr, "✅ configuration is valid")
65+
return nil
66+
},
67+
}
68+
4469
func init() {
70+
configCmd.AddCommand(configValidateCmd)
4571
configCmd.Flags().Bool("render-otel-details", false, "Print the full resolved otel configuration including default values after the otel components perform their semantic processing.")
4672
configCmd.Flags().Bool("render-otel", false, "Print a single rendered otel configuration file. This file is equivalent to the bundled configuration enabled in the observe-agent config.")
4773
root.RootCmd.AddCommand(configCmd)

internal/commands/config/config_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func runSnapshotTest(t *testing.T, test snapshotTest) {
109109
assert.True(t, ok)
110110
curPath := path.Dir(filename)
111111

112-
// Set the template base dir for all connections
112+
// Set the template overrides for all connections
113113
for _, conn := range connections.AllConnectionTypes {
114114
conn.ApplyOptions(connections.WithConfigTemplateOverrides(getTemplateOverrides(t, test.packageType, curPath)))
115115
}

internal/connections/bundledconfig/bundledconfig.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ import (
99
"github.com/observeinc/observe-agent/internal/connections/bundledconfig/windows"
1010
)
1111

12+
type ConfigTemplates = map[string]embed.FS
13+
1214
// TODO break up some of the larger connections in order to share more configs.
13-
var SharedTemplateFS = map[string]embed.FS{
15+
var SharedTemplateFS = ConfigTemplates{
1416
"common/attributes.yaml.tmpl": shared.AttributesTemplateFS,
1517
"common/internal_telemetry.yaml.tmpl": shared.InternalTelemetryTemplateFS,
1618
"common/health_check.yaml.tmpl": shared.HealthCheckTemplateFS,
@@ -23,23 +25,23 @@ var SharedTemplateFS = map[string]embed.FS{
2325
"self_monitoring/logs_and_metrics.yaml.tmpl": shared.LogsAndMetricsTemplateFS,
2426
}
2527

26-
var DockerTemplateFS = map[string]embed.FS{
28+
var DockerTemplateFS = ConfigTemplates{
2729
"common/base.yaml.tmpl": docker.BaseTemplateFS,
2830
"host_monitoring/logs.yaml.tmpl": docker.LogsTemplateFS,
2931
"host_monitoring/host_metrics.yaml.tmpl": docker.HostMetricsTemplateFS,
3032
"host_monitoring/process_metrics.yaml.tmpl": docker.ProcessMetricsTemplateFS,
3133
"self_monitoring/logs_and_metrics.yaml.tmpl": docker.LogsAndMetricsTemplateFS,
3234
}
3335

34-
var LinuxTemplateFS = map[string]embed.FS{
36+
var LinuxTemplateFS = ConfigTemplates{
3537
"host_monitoring/logs.yaml.tmpl": linux.LogsTemplateFS,
3638
"host_monitoring/host_metrics.yaml.tmpl": linux.HostMetricsTemplateFS,
3739
"self_monitoring/logs_and_metrics.yaml.tmpl": linux.LogsAndMetricsTemplateFS,
3840
}
3941

40-
var MacOSTemplateFS = map[string]embed.FS{}
42+
var MacOSTemplateFS = ConfigTemplates{}
4143

42-
var WindowsTemplateFS = map[string]embed.FS{
44+
var WindowsTemplateFS = ConfigTemplates{
4345
"common/base.yaml.tmpl": windows.BaseTemplateFS,
4446
"host_monitoring/logs.yaml.tmpl": windows.LogsTemplateFS,
4547
"host_monitoring/host_metrics.yaml.tmpl": windows.HostMetricsTemplateFS,

internal/connections/connections.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,12 @@ type BundledConfigFragment struct {
2424
colConfigFilePath string
2525
}
2626

27-
type ConfigOverrides = map[string]embed.FS
28-
2927
type ConnectionType struct {
3028
Name string
3129
BundledConfigFragments []BundledConfigFragment
3230
EnabledCheck EnabledCheckFn
3331

34-
templateOverrides ConfigOverrides
32+
templateOverrides bundledconfig.ConfigTemplates
3533
}
3634

3735
func (c *ConnectionType) getTemplate(tplName string) (*template.Template, error) {
@@ -111,7 +109,7 @@ func MakeConnectionType(name string, enabledCheck EnabledCheckFn, fragments []Bu
111109
return c
112110
}
113111

114-
func WithConfigTemplateOverrides(templateOverrides ConfigOverrides) ConnectionTypeOption {
112+
func WithConfigTemplateOverrides(templateOverrides bundledconfig.ConfigTemplates) ConnectionTypeOption {
115113
return func(c *ConnectionType) {
116114
c.templateOverrides = templateOverrides
117115
}

internal/root/root.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@ import (
1515
"github.com/observeinc/observe-agent/internal/commands/util/logger"
1616
"github.com/observeinc/observe-agent/internal/config"
1717
"github.com/observeinc/observe-agent/internal/connections"
18+
"github.com/observeinc/observe-agent/internal/connections/bundledconfig"
1819
"github.com/observeinc/observe-agent/observecol"
1920
"github.com/spf13/cobra"
2021
"github.com/spf13/viper"
2122
)
2223

2324
var CfgFile string
25+
var configMode string
2426

2527
// RootCmd represents the base command when called without any subcommands
2628
var RootCmd = &cobra.Command{
@@ -45,12 +47,39 @@ func init() {
4547

4648
flags := RootCmd.PersistentFlags()
4749
flags.StringVar(&CfgFile, "observe-config", "", "observe-agent config file path")
50+
flags.StringVar(&configMode, "config-mode", "", "The mode to use for bundled config. Valid values are Linux, Docker, Mac, and Windows.")
51+
flags.MarkHidden("config-mode")
4852
observecol.AddConfigFlags(flags)
4953
observecol.AddFeatureGateFlag(flags)
5054
}
5155

56+
func setConfigMode() {
57+
var overrides bundledconfig.ConfigTemplates
58+
switch strings.ToLower(configMode) {
59+
case "":
60+
return
61+
case "linux":
62+
overrides = bundledconfig.LinuxTemplateFS
63+
case "docker":
64+
overrides = bundledconfig.DockerTemplateFS
65+
case "mac":
66+
overrides = bundledconfig.MacOSTemplateFS
67+
case "windows":
68+
overrides = bundledconfig.WindowsTemplateFS
69+
default:
70+
fmt.Fprintf(os.Stderr, "Invalid config mode specified: %s. Valid values are Linux, Docker, Mac, and Windows.\n", configMode)
71+
os.Exit(1)
72+
}
73+
// Set the template overrides for all connections
74+
for _, conn := range connections.AllConnectionTypes {
75+
conn.ApplyOptions(connections.WithConfigTemplateOverrides(overrides))
76+
}
77+
78+
}
79+
5280
// InitConfig reads in config file and ENV variables if set.
5381
func InitConfig() {
82+
setConfigMode()
5483
ctx := logger.WithCtx(context.Background(), logger.Get())
5584
// Some keys in OTEL component configs use "." as part of the key but viper ends up parsing that into
5685
// a subobject since the default key delimiter is "." which causes config validation to fail.

0 commit comments

Comments
 (0)