From 1d82214491bba36e3f4f396952790f8beb22a9fe Mon Sep 17 00:00:00 2001 From: Kent Quirk Date: Thu, 8 Jun 2023 22:12:22 -0400 Subject: [PATCH] feat: write out parsed configs (#707) ## Which problem is this PR solving? We have often been asked for the ability to see what refinery thinks its configurations are. We support this with a debug command, but it requires a running refinery configured to allow debug queries, and a configuration that allows connecting to it. This PR adds command-line switches to read the configs, apply defaults and environment variables, and write the data back out to a file. If you use this feature, refinery doesn't start, it just writes the file and exits. ## Short description of the changes - Add function to write YAML out - Add cmdline parameters to control it Dependent on #706 --- config/cmdenv.go | 2 ++ config/file_config.go | 37 +++++++++++++++++++++++++++++++++++-- config_complete.yaml | 2 +- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/config/cmdenv.go b/config/cmdenv.go index 5a7f7e4ff9..60c4c7ad90 100644 --- a/config/cmdenv.go +++ b/config/cmdenv.go @@ -45,6 +45,8 @@ type CmdEnv struct { InterfaceNames bool `long:"interface-names" description:"Print system's network interface names and exit."` Validate bool `short:"V" long:"validate" description:"Validate the configuration files, writing results to stdout, and exit with 0 if valid, 1 if invalid."` NoValidate bool `long:"no-validate" description:"Do not attempt to validate the configuration files. Makes --validate meaningless."` + WriteConfig string `long:"write-config" description:"After applying defaults, environment variables, and command line values, write the loaded configuration to the specified file as YAML and exit."` + WriteRules string `long:"write-rules" description:"After applying defaults, write the loaded rules to the specified file as YAML and exit."` } func NewCmdEnvOptions(args []string) (*CmdEnv, error) { diff --git a/config/file_config.go b/config/file_config.go index 4617f6816c..da57e13a5e 100644 --- a/config/file_config.go +++ b/config/file_config.go @@ -2,10 +2,14 @@ package config import ( "errors" + "fmt" "net" + "os" "strings" "sync" "time" + + "gopkg.in/yaml.v3" ) // In order to be able to unmarshal "15s" etc. into time.Duration, we need to @@ -295,9 +299,22 @@ func newFileConfig(opts *CmdEnv) (*fileConfig, error) { return cfg, nil } +// writeYAMLToFile renders the given data item to a YAML file +func writeYAMLToFile(data any, filename string) error { + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + encoder := yaml.NewEncoder(f) + encoder.SetIndent(2) + return encoder.Encode(data) +} + // NewConfig creates a new Config object from the given arguments; if args is -// nil, it uses the command line arguments. Because errors may be caused by -// validation problems, it returns the config even in the case of errors. +// nil, it uses the command line arguments. +// It also dumps the config and rules to the given files, if specified, which +// will cause the program to exit. func NewConfig(opts *CmdEnv, errorCallback func(error)) (Config, error) { cfg, err := newFileConfig(opts) // only exit if we have no config at all; if it fails validation, we'll @@ -306,6 +323,22 @@ func NewConfig(opts *CmdEnv, errorCallback func(error)) (Config, error) { return nil, err } + if opts.WriteConfig != "" { + if err := writeYAMLToFile(cfg.mainConfig, opts.WriteConfig); err != nil { + fmt.Printf("Error writing config: %s\n", err) + os.Exit(1) + } + } + if opts.WriteRules != "" { + if err := writeYAMLToFile(cfg.rulesConfig, opts.WriteRules); err != nil { + fmt.Printf("Error writing rules: %s\n", err) + os.Exit(1) + } + } + if opts.WriteConfig != "" || opts.WriteRules != "" { + os.Exit(0) + } + cfg.callbacks = make([]func(), 0) cfg.errorCallback = errorCallback diff --git a/config_complete.yaml b/config_complete.yaml index 735708dd68..618fa19220 100644 --- a/config_complete.yaml +++ b/config_complete.yaml @@ -470,7 +470,7 @@ LegacyMetrics: ## metrics. ## ## Not eligible for live reload. - APIKey: abcd1234 + APIKey: SetThisToAHoneycombKey ## Dataset is the Honeycomb dataset to which metrics will be sent. ##