From fc4c3b9c1e770fd18f037dd7da14024103e2f854 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 25 Aug 2019 23:53:03 -0700 Subject: [PATCH] return error on bad parsed env variable --- core/poller/unifipoller/config.go | 33 ++++++++++++++++++------------- core/poller/unifipoller/start.go | 29 ++++++++++++++++++++------- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/core/poller/unifipoller/config.go b/core/poller/unifipoller/config.go index 008caf7b..89e7e821 100644 --- a/core/poller/unifipoller/config.go +++ b/core/poller/unifipoller/config.go @@ -22,6 +22,10 @@ const ( defaultUnifURL = "https://127.0.0.1:8443" ) +// ENVConfigPrefix is the prefix appended to an env variable tag +// name before retrieving the value from the OS. +const ENVConfigPrefix = "UP_" + // UnifiPoller contains the application startup data, and auth info for UniFi & Influx. type UnifiPoller struct { Influx influx.Client @@ -52,23 +56,24 @@ type Metrics struct { // Config represents the data needed to poll a controller and report to influxdb. // This is all of the data stored in the config file. +// Any with explicit defaults have _omitempty on json and toml tags. type Config struct { - MaxErrors int `json:"max_errors,_omitempty" toml:"max_errors,_omitempty" xml:"max_errors" yaml:"max_errors" env:"UP_MAX_ERRORS"` - Interval Duration `json:"interval,_omitempty" toml:"interval,_omitempty" xml:"interval" yaml:"interval" env:"UP_POLLING_INTERVAL"` - Debug bool `json:"debug" toml:"debug" xml:"debug" yaml:"debug" env:"UP_DEBUG_MODE"` - Quiet bool `json:"quiet,_omitempty" toml:"quiet,_omitempty" xml:"quiet" yaml:"quiet" env:"UP_QUIET_MODE"` - VerifySSL bool `json:"verify_ssl" toml:"verify_ssl" xml:"verify_ssl" yaml:"verify_ssl" env:"UP_VERIFY_SSL"` - CollectIDS bool `json:"collect_ids" toml:"collect_ids" xml:"collect_ids" yaml:"collect_ids" env:"UP_COLLECT_IDS"` - ReAuth bool `json:"reauthenticate" toml:"reauthenticate" xml:"reauthenticate" yaml:"reauthenticate" env:"UP_REAUTHENTICATE"` - Mode string `json:"mode" toml:"mode" xml:"mode" yaml:"mode" env:"UP_POLLING_MODE"` - InfluxURL string `json:"influx_url,_omitempty" toml:"influx_url,_omitempty" xml:"influx_url" yaml:"influx_url" env:"UP_INFLUX_URL"` + MaxErrors int `json:"max_errors" toml:"max_errors" xml:"max_errors" yaml:"max_errors" env:"MAX_ERRORS"` + Interval Duration `json:"interval,_omitempty" toml:"interval,_omitempty" xml:"interval" yaml:"interval" env:"POLLING_INTERVAL"` + Debug bool `json:"debug" toml:"debug" xml:"debug" yaml:"debug" env:"DEBUG_MODE"` + Quiet bool `json:"quiet,_omitempty" toml:"quiet,_omitempty" xml:"quiet" yaml:"quiet" env:"QUIET_MODE"` + VerifySSL bool `json:"verify_ssl" toml:"verify_ssl" xml:"verify_ssl" yaml:"verify_ssl" env:"VERIFY_SSL"` + CollectIDS bool `json:"collect_ids" toml:"collect_ids" xml:"collect_ids" yaml:"collect_ids" env:"COLLECT_IDS"` + ReAuth bool `json:"reauthenticate" toml:"reauthenticate" xml:"reauthenticate" yaml:"reauthenticate" env:"REAUTHENTICATE"` + Mode string `json:"mode" toml:"mode" xml:"mode" yaml:"mode" env:"POLLING_MODE"` + InfluxURL string `json:"influx_url,_omitempty" toml:"influx_url,_omitempty" xml:"influx_url" yaml:"influx_url" env:"INFLUX_URL"` InfluxUser string `json:"influx_user,_omitempty" toml:"influx_user,_omitempty" xml:"influx_user" yaml:"influx_user" env:"INFLUX_USER"` InfluxPass string `json:"influx_pass,_omitempty" toml:"influx_pass,_omitempty" xml:"influx_pass" yaml:"influx_pass" env:"INFLUX_PASS"` - InfluxDB string `json:"influx_db,_omitempty" toml:"influx_db,_omitempty" xml:"influx_db" yaml:"influx_db" env:"UP_INFLUX_DB"` - UnifiUser string `json:"unifi_user,_omitempty" toml:"unifi_user,_omitempty" xml:"unifi_user" yaml:"unifi_user" env:"UP_UNIFI_USER"` - UnifiPass string `json:"unifi_pass,_omitempty" toml:"unifi_pass,_omitempty" xml:"unifi_pass" yaml:"unifi_pass" env:"UP_UNIFI_PASS"` - UnifiBase string `json:"unifi_url,_omitempty" toml:"unifi_url,_omitempty" xml:"unifi_url" yaml:"unifi_url" env:"UP_UNIFI_URL"` - Sites []string `json:"sites,_omitempty" toml:"sites,_omitempty" xml:"sites" yaml:"sites" env:"UP_POLL_SITES"` + InfluxDB string `json:"influx_db,_omitempty" toml:"influx_db,_omitempty" xml:"influx_db" yaml:"influx_db" env:"INFLUX_DB"` + UnifiUser string `json:"unifi_user,_omitempty" toml:"unifi_user,_omitempty" xml:"unifi_user" yaml:"unifi_user" env:"UNIFI_USER"` + UnifiPass string `json:"unifi_pass,_omitempty" toml:"unifi_pass,_omitempty" xml:"unifi_pass" yaml:"unifi_pass" env:"UNIFI_PASS"` + UnifiBase string `json:"unifi_url,_omitempty" toml:"unifi_url,_omitempty" xml:"unifi_url" yaml:"unifi_url" env:"UNIFI_URL"` + Sites []string `json:"sites,_omitempty" toml:"sites,_omitempty" xml:"sites" yaml:"sites" env:"POLL_SITES"` } // Duration is used to UnmarshalTOML into a time.Duration value. diff --git a/core/poller/unifipoller/start.go b/core/poller/unifipoller/start.go index 5e257806..f1c2e49c 100644 --- a/core/poller/unifipoller/start.go +++ b/core/poller/unifipoller/start.go @@ -29,10 +29,15 @@ func Start() error { fmt.Printf("unifi-poller v%s\n", Version) return nil // don't run anything else w/ version request. } + // Parse config file. if err := up.GetConfig(); err != nil { up.Flag.Usage() return err } + // Update Config with ENV variable overrides. + if err := up.setEnvVarOptions(); err != nil { + return err + } return up.Run() } @@ -53,13 +58,14 @@ func (f *Flag) Parse(args []string) { // setEnvVarOptions copies environment variables into configuration values. // This is useful for Docker users that find it easier to pass ENV variables // than a specific configuration file. Uses reflection to find struct tags. -func (u *UnifiPoller) setEnvVarOptions() { +func (u *UnifiPoller) setEnvVarOptions() error { t := reflect.TypeOf(Config{}) // Loop each Config struct member; get reflect tag & env var value; update config. for i := 0; i < t.NumField(); i++ { // Get the ENV variable name from "env" struct tag then pull value from OS. - env := os.Getenv(t.Field(i).Tag.Get("env")) - if env == "" { + tag := t.Field(i).Tag.Get("env") + env := os.Getenv(ENVConfigPrefix + tag) + if tag == "" || env == "" { continue } // Reflect and update the u.Config struct member at position i. @@ -69,18 +75,28 @@ func (u *UnifiPoller) setEnvVarOptions() { // This is a reflect package method to update a struct member by index. c.SetString(env) case "int": - val, _ := strconv.Atoi(env) + val, err := strconv.Atoi(env) + if err != nil { + return err + } c.Set(reflect.ValueOf(val)) case "[]string": c.Set(reflect.ValueOf(strings.Split(env, ","))) case "Duration": - val, _ := time.ParseDuration(env) + val, err := time.ParseDuration(env) + if err != nil { + return err + } c.Set(reflect.ValueOf(Duration{val})) case "bool": - val, _ := strconv.ParseBool(env) + val, err := strconv.ParseBool(env) + if err != nil { + return err + } c.SetBool(val) } } + return nil } // GetConfig parses and returns our configuration data. @@ -99,7 +115,6 @@ func (u *UnifiPoller) GetConfig() error { Quiet: u.Flag.DumpJSON != "", //s uppress the following u.Logf line. } u.Logf("Loading Configuration File: %s", u.Flag.ConfigFile) - defer u.setEnvVarOptions() // Set env variable overrides when done here. switch buf, err := ioutil.ReadFile(u.Flag.ConfigFile); { case err != nil: return err