Skip to content

Commit e1c6d40

Browse files
feat: use agent config for init-config command future proofing (#189)
### Description Use agent config for `init-config` command. This allows all values in the agent config to work with this command both currently and going forward. Ex: ``` $ OBSERVE_URL="http://observeinc.com/" ./observe-agent --observe-config=./empty.yaml init-config --print 2>/dev/null # Observe data token token: "" # Target Observe collection url observe_url: http://observeinc.com/ health_check: enabled: true endpoint: localhost:13133 path: /status forwarding: enabled: true internal_telemetry: enabled: true host: localhost port: 8888 # otel_config_overrides: # exporters: # debug: # verbosity: detailed # sampling_initial: 5 # sampling_thereafter: 200 # service: # pipelines: # metrics: # receivers: [hostmetrics] # processors: [memory_limiter] # exporters: [debug] ```
1 parent 0cb5550 commit e1c6d40

File tree

5 files changed

+125
-98
lines changed

5 files changed

+125
-98
lines changed

internal/commands/initconfig/initconfig.go

Lines changed: 30 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ Copyright © 2024 NAME HERE <EMAIL ADDRESS>
44
package initconfig
55

66
import (
7-
"embed"
87
"fmt"
9-
"html/template"
108
"os"
119

10+
"github.com/observeinc/observe-agent/internal/config"
1211
"github.com/observeinc/observe-agent/internal/root"
1312
"github.com/spf13/cobra"
1413
"github.com/spf13/viper"
@@ -25,43 +24,14 @@ var (
2524
host_monitoring_logs_include []string
2625
host_monitoring_metrics_host_enabled bool
2726
host_monitoring_metrics_process_enabled bool
28-
//go:embed observe-agent.tmpl
29-
configTemplateFS embed.FS
3027
)
3128

32-
const configTemplate = "observe-agent.tmpl"
33-
34-
type FlatAgentConfig struct {
35-
Token string
36-
ObserveURL string
37-
CloudResourceDetectors []string
38-
SelfMonitoring_Enabled bool
39-
HostMonitoring_Enabled bool
40-
HostMonitoring_LogsEnabled bool
41-
HostMonitoring_LogsInclude []string
42-
HostMonitoring_Metrics_HostEnabled bool
43-
HostMonitoring_Metrics_ProcessEnabled bool
44-
}
45-
4629
func NewConfigureCmd(v *viper.Viper) *cobra.Command {
4730
return &cobra.Command{
4831
Use: "init-config",
4932
Short: "Initialize agent configuration",
5033
Long: `This command takes in parameters and creates an initialized observe agent configuration file. Will overwrite existing config file and should only be used to initialize.`,
5134
RunE: func(cmd *cobra.Command, args []string) error {
52-
configValues := FlatAgentConfig{
53-
Token: v.GetString("token"),
54-
ObserveURL: v.GetString("observe_url"),
55-
CloudResourceDetectors: v.GetStringSlice("cloud_resource_detectors"),
56-
SelfMonitoring_Enabled: v.GetBool("self_monitoring::enabled"),
57-
HostMonitoring_Enabled: v.GetBool("host_monitoring::enabled"),
58-
HostMonitoring_LogsEnabled: v.GetBool("host_monitoring::logs::enabled"),
59-
HostMonitoring_Metrics_HostEnabled: v.GetBool("host_monitoring::metrics::host::enabled"),
60-
HostMonitoring_Metrics_ProcessEnabled: v.GetBool("host_monitoring::metrics::process::enabled"),
61-
}
62-
if configValues.HostMonitoring_LogsEnabled {
63-
configValues.HostMonitoring_LogsInclude = v.GetStringSlice("host_monitoring::logs::include")
64-
}
6535
var f *os.File
6636
if v.GetBool("print") {
6737
f = os.Stdout
@@ -80,10 +50,11 @@ func NewConfigureCmd(v *viper.Viper) *cobra.Command {
8050
defer f.Close()
8151
fmt.Printf("Writing configuration values to %s...\n\n", outputPath)
8252
}
83-
t := template.Must(template.New(configTemplate).ParseFS(configTemplateFS, configTemplate))
84-
if err := t.ExecuteTemplate(f, configTemplate, configValues); err != nil {
53+
agentConfig, err := config.AgentConfigFromViper(v)
54+
if err != nil {
8555
return err
8656
}
57+
writeConfigFile(f, agentConfig, v.GetBool("include-defaults"))
8758
return nil
8859
},
8960
}
@@ -98,24 +69,40 @@ func init() {
9869

9970
func RegisterConfigFlags(cmd *cobra.Command, v *viper.Viper) {
10071
cmd.Flags().StringVarP(&config_path, "config_path", "", "", "Path to write config output file to")
101-
cmd.PersistentFlags().Bool("print", false, "Print the configuration to stdout instead of writing to a file")
72+
cmd.Flags().Bool("print", false, "Print the configuration to stdout instead of writing to a file")
73+
v.BindPFlag("print", cmd.Flags().Lookup("print"))
74+
cmd.Flags().Bool("include-defaults", false, "Include the names and default values for unset config options.")
75+
v.BindPFlag("include-defaults", cmd.Flags().Lookup("include-defaults"))
76+
10277
cmd.PersistentFlags().StringVar(&token, "token", "", "Observe token")
103-
cmd.PersistentFlags().StringVar(&observe_url, "observe_url", "", "Observe data collection url")
104-
cmd.PersistentFlags().StringSliceVar(&cloud_resource_detectors, "cloud_resource_detectors", []string{}, "The cloud environments from which to detect resources")
105-
cmd.PersistentFlags().BoolVar(&self_monitoring_enabled, "self_monitoring::enabled", true, "Enable self monitoring")
106-
cmd.PersistentFlags().BoolVar(&host_monitoring_enabled, "host_monitoring::enabled", true, "Enable host monitoring")
107-
cmd.PersistentFlags().BoolVar(&host_monitoring_logs_enabled, "host_monitoring::logs::enabled", true, "Enable host monitoring logs")
108-
cmd.PersistentFlags().StringSliceVar(&host_monitoring_logs_include, "host_monitoring::logs::include", nil, "Set host monitoring log include paths")
109-
cmd.PersistentFlags().BoolVar(&host_monitoring_metrics_host_enabled, "host_monitoring::metrics::host::enabled", true, "Enable host monitoring host metrics")
110-
cmd.PersistentFlags().BoolVar(&host_monitoring_metrics_process_enabled, "host_monitoring::metrics::process::enabled", false, "Enable host monitoring process metrics")
111-
v.BindPFlag("print", cmd.PersistentFlags().Lookup("print"))
11278
v.BindPFlag("token", cmd.PersistentFlags().Lookup("token"))
79+
80+
cmd.PersistentFlags().StringVar(&observe_url, "observe_url", "", "Observe data collection url")
11381
v.BindPFlag("observe_url", cmd.PersistentFlags().Lookup("observe_url"))
82+
83+
cmd.PersistentFlags().StringSliceVar(&cloud_resource_detectors, "cloud_resource_detectors", []string{}, "The cloud environments from which to detect resources")
11484
v.BindPFlag("cloud_resource_detectors", cmd.PersistentFlags().Lookup("cloud_resource_detectors"))
85+
86+
cmd.PersistentFlags().BoolVar(&self_monitoring_enabled, "self_monitoring::enabled", true, "Enable self monitoring")
11587
v.BindPFlag("self_monitoring::enabled", cmd.PersistentFlags().Lookup("self_monitoring::enabled"))
88+
v.SetDefault("self_monitoring::enabled", true)
89+
90+
cmd.PersistentFlags().BoolVar(&host_monitoring_enabled, "host_monitoring::enabled", true, "Enable host monitoring")
11691
v.BindPFlag("host_monitoring::enabled", cmd.PersistentFlags().Lookup("host_monitoring::enabled"))
92+
v.SetDefault("host_monitoring::enabled", true)
93+
94+
cmd.PersistentFlags().BoolVar(&host_monitoring_logs_enabled, "host_monitoring::logs::enabled", true, "Enable host monitoring logs")
11795
v.BindPFlag("host_monitoring::logs::enabled", cmd.PersistentFlags().Lookup("host_monitoring::logs::enabled"))
96+
v.SetDefault("host_monitoring::logs::enabled", true)
97+
98+
cmd.PersistentFlags().StringSliceVar(&host_monitoring_logs_include, "host_monitoring::logs::include", nil, "Set host monitoring log include paths")
11899
v.BindPFlag("host_monitoring::logs::include", cmd.PersistentFlags().Lookup("host_monitoring::logs::include"))
100+
101+
cmd.PersistentFlags().BoolVar(&host_monitoring_metrics_host_enabled, "host_monitoring::metrics::host::enabled", true, "Enable host monitoring host metrics")
119102
v.BindPFlag("host_monitoring::metrics::host::enabled", cmd.PersistentFlags().Lookup("host_monitoring::metrics::host::enabled"))
103+
v.SetDefault("host_monitoring::metrics::host::enabled", true)
104+
105+
cmd.PersistentFlags().BoolVar(&host_monitoring_metrics_process_enabled, "host_monitoring::metrics::process::enabled", false, "Enable host monitoring process metrics")
120106
v.BindPFlag("host_monitoring::metrics::process::enabled", cmd.PersistentFlags().Lookup("host_monitoring::metrics::process::enabled"))
107+
v.SetDefault("host_monitoring::metrics::process::enabled", false)
121108
}

internal/commands/initconfig/initconfig_test.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@ import (
55
"testing"
66

77
"github.com/go-viper/mapstructure/v2"
8+
"github.com/mcuadros/go-defaults"
89
"github.com/observeinc/observe-agent/internal/config"
910
"github.com/spf13/viper"
1011
"github.com/stretchr/testify/assert"
1112
"gopkg.in/yaml.v3"
1213
)
1314

15+
func setConfigDefaults(agentConfig config.AgentConfig) config.AgentConfig {
16+
defaults.SetDefaults(&agentConfig)
17+
return agentConfig
18+
}
19+
1420
func Test_InitConfigCommand(t *testing.T) {
1521
t.Cleanup(func() {
1622
os.Remove("./test-config.yaml")
@@ -22,7 +28,7 @@ func Test_InitConfigCommand(t *testing.T) {
2228
}{
2329
{
2430
args: []string{"--config_path=./test-config.yaml", "--token=test-token", "--observe_url=test-url", "--host_monitoring::logs::include=/test/path,/test/path2"},
25-
expectedConfig: config.AgentConfig{
31+
expectedConfig: setConfigDefaults(config.AgentConfig{
2632
Token: "test-token",
2733
ObserveURL: "test-url",
2834
SelfMonitoring: config.SelfMonitoringConfig{
@@ -43,12 +49,12 @@ func Test_InitConfigCommand(t *testing.T) {
4349
},
4450
},
4551
},
46-
},
52+
}),
4753
expectErr: "",
4854
},
4955
{
5056
args: []string{"--config_path=./test-config.yaml", "--token=test-token", "--observe_url=test-url", "--self_monitoring::enabled=false", "--host_monitoring::enabled=false", "--host_monitoring::logs::enabled=false", "--host_monitoring::metrics::host::enabled=false", "--host_monitoring::metrics::process::enabled=false"},
51-
expectedConfig: config.AgentConfig{
57+
expectedConfig: setConfigDefaults(config.AgentConfig{
5258
Token: "test-token",
5359
ObserveURL: "test-url",
5460
HostMonitoring: config.HostMonitoringConfig{
@@ -65,14 +71,15 @@ func Test_InitConfigCommand(t *testing.T) {
6571
},
6672
},
6773
},
68-
},
74+
}),
6975
expectErr: "",
7076
},
7177
}
72-
v := viper.New()
73-
initConfigCmd := NewConfigureCmd(v)
74-
RegisterConfigFlags(initConfigCmd, v)
7578
for _, tc := range testcases {
79+
v := viper.NewWithOptions(viper.KeyDelimiter("::"))
80+
config.SetViperDefaults(v, "::")
81+
initConfigCmd := NewConfigureCmd(v)
82+
RegisterConfigFlags(initConfigCmd, v)
7683
initConfigCmd.SetArgs(tc.args)
7784
err := initConfigCmd.Execute()
7885
if err != nil {

internal/commands/initconfig/observe-agent.tmpl

Lines changed: 0 additions & 47 deletions
This file was deleted.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package initconfig
2+
3+
import (
4+
"os"
5+
"regexp"
6+
"strings"
7+
8+
"github.com/go-viper/mapstructure/v2"
9+
"github.com/observeinc/observe-agent/internal/config"
10+
"gopkg.in/yaml.v3"
11+
)
12+
13+
const otelOverrideSection = `
14+
# otel_config_overrides:
15+
# exporters:
16+
# debug:
17+
# verbosity: detailed
18+
# sampling_initial: 5
19+
# sampling_thereafter: 200
20+
# service:
21+
# pipelines:
22+
# metrics:
23+
# receivers: [hostmetrics]
24+
# processors: [memory_limiter]
25+
# exporters: [debug]
26+
`
27+
28+
var sectionComments map[string]string = map[string]string{
29+
"token": "Observe data token",
30+
"observe_url": "Target Observe collection url",
31+
"debug": "Debug mode - Sets agent log level to debug",
32+
"environment": "test env comment",
33+
}
34+
35+
func writeConfigFile(f *os.File, agentConfig *config.AgentConfig, includeAllOptions bool) error {
36+
var yamlBytes []byte
37+
var err error
38+
if includeAllOptions {
39+
var agentConfigMap map[string]any
40+
err = mapstructure.Decode(agentConfig, &agentConfigMap)
41+
if err != nil {
42+
return err
43+
}
44+
yamlBytes, err = yaml.Marshal(&agentConfigMap)
45+
if err != nil {
46+
return err
47+
}
48+
} else {
49+
yamlBytes, err = yaml.Marshal(agentConfig)
50+
if err != nil {
51+
return err
52+
}
53+
}
54+
yamlStr := string(yamlBytes)
55+
56+
// Add empty lines between top level sections.
57+
yamlStr = regexp.MustCompile(`(?m)^(\w+:.*)$`).ReplaceAllString(yamlStr, "\n$1")
58+
59+
// Add comments before yaml keys.
60+
for commentKey, commentValue := range sectionComments {
61+
yamlStr = regexp.MustCompile(`(?m)^([`+" \t"+`]*)`+commentKey+`:.*$`).ReplaceAllString(yamlStr, "$1# "+commentValue+"\n$0")
62+
}
63+
64+
// Clean up whitespace
65+
yamlStr = strings.Trim(yamlStr, " \n\t\r") + "\n"
66+
67+
// Add the otel config overrides comment if there is no section present.
68+
if !strings.Contains(yamlStr, "otel_config_overrides:") {
69+
yamlStr += "\n" + strings.Trim(otelOverrideSection, " \n\t\r") + "\n"
70+
}
71+
72+
_, err = f.WriteString(yamlStr)
73+
return err
74+
}

internal/commands/util/config_printers.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,13 @@ func PrintAllConfigsIndividually(configFilePaths []string) error {
2626
if err != nil {
2727
return err
2828
}
29-
agentConfigYaml, err := yaml.Marshal(agentConfig)
29+
// Use mapstructure as an intermediary so all values are printed.
30+
var agentConfigMap map[string]any
31+
err = mapstructure.Decode(agentConfig, &agentConfigMap)
32+
if err != nil {
33+
return err
34+
}
35+
agentConfigYaml, err := yaml.Marshal(&agentConfigMap)
3036
if err != nil {
3137
return err
3238
}

0 commit comments

Comments
 (0)