switch to config package
This commit is contained in:
parent
b8d9ac9f88
commit
f4ae4fc5e5
|
|
@ -9,22 +9,13 @@ package poller
|
|||
*/
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/davidnewhall/unifi-poller/pkg/influxunifi"
|
||||
"github.com/spf13/pflag"
|
||||
"golift.io/config"
|
||||
"golift.io/unifi"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// Version is injected by the Makefile
|
||||
|
|
@ -45,7 +36,7 @@ const (
|
|||
|
||||
// ENVConfigPrefix is the prefix appended to an env variable tag
|
||||
// name before retrieving the value from the OS.
|
||||
const ENVConfigPrefix = "UP_"
|
||||
const ENVConfigPrefix = "UP"
|
||||
|
||||
// UnifiPoller contains the application startup data, and auth info for UniFi & Influx.
|
||||
type UnifiPoller struct {
|
||||
|
|
@ -68,7 +59,6 @@ type Flag struct {
|
|||
// Controller represents the configuration for a UniFi Controller.
|
||||
// Each polled controller may have its own configuration.
|
||||
type Controller struct {
|
||||
Interval Duration `json:"interval,omitempty" toml:"interval,omitempty" xml:"interval" yaml:"interval"`
|
||||
VerifySSL bool `json:"verify_ssl" toml:"verify_ssl" xml:"verify_ssl" yaml:"verify_ssl"`
|
||||
SaveIDS bool `json:"save_ids" toml:"save_ids" xml:"save_ids" yaml:"save_ids"`
|
||||
ReAuth bool `json:"reauthenticate" toml:"reauthenticate" xml:"reauthenticate" yaml:"reauthenticate"`
|
||||
|
|
@ -83,115 +73,24 @@ type Controller struct {
|
|||
// 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 {
|
||||
Interval Duration `json:"interval,omitempty" toml:"interval,omitempty" xml:"interval" yaml:"interval"`
|
||||
Debug bool `json:"debug" toml:"debug" xml:"debug" yaml:"debug"`
|
||||
Quiet bool `json:"quiet,omitempty" toml:"quiet,omitempty" xml:"quiet" yaml:"quiet"`
|
||||
VerifySSL bool `json:"verify_ssl" toml:"verify_ssl" xml:"verify_ssl" yaml:"verify_ssl"`
|
||||
SaveIDS bool `json:"save_ids" toml:"save_ids" xml:"save_ids" yaml:"save_ids"`
|
||||
ReAuth bool `json:"reauthenticate" toml:"reauthenticate" xml:"reauthenticate" yaml:"reauthenticate"`
|
||||
InfxBadSSL bool `json:"influx_insecure_ssl" toml:"influx_insecure_ssl" xml:"influx_insecure_ssl" yaml:"influx_insecure_ssl"`
|
||||
SaveSites bool `json:"save_sites,omitempty" toml:"save_sites,omitempty" xml:"save_sites" yaml:"save_sites"`
|
||||
Mode string `json:"mode" toml:"mode" xml:"mode" yaml:"mode"`
|
||||
HTTPListen string `json:"http_listen" toml:"http_listen" xml:"http_listen" yaml:"http_listen"`
|
||||
Namespace string `json:"namespace" toml:"namespace" xml:"namespace" yaml:"namespace"`
|
||||
InfluxURL string `json:"influx_url,omitempty" toml:"influx_url,omitempty" xml:"influx_url" yaml:"influx_url"`
|
||||
InfluxUser string `json:"influx_user,omitempty" toml:"influx_user,omitempty" xml:"influx_user" yaml:"influx_user"`
|
||||
InfluxPass string `json:"influx_pass,omitempty" toml:"influx_pass,omitempty" xml:"influx_pass" yaml:"influx_pass"`
|
||||
InfluxDB string `json:"influx_db,omitempty" toml:"influx_db,omitempty" xml:"influx_db" yaml:"influx_db"`
|
||||
UnifiUser string `json:"unifi_user,omitempty" toml:"unifi_user,omitempty" xml:"unifi_user" yaml:"unifi_user"`
|
||||
UnifiPass string `json:"unifi_pass,omitempty" toml:"unifi_pass,omitempty" xml:"unifi_pass" yaml:"unifi_pass"`
|
||||
UnifiBase string `json:"unifi_url,omitempty" toml:"unifi_url,omitempty" xml:"unifi_url" yaml:"unifi_url"`
|
||||
Sites []string `json:"sites,omitempty" toml:"sites,omitempty" xml:"sites" yaml:"sites"`
|
||||
Controller []*Controller `json:"controller,omitempty" toml:"controller,omitempty" xml:"controller" yaml:"controller"`
|
||||
}
|
||||
|
||||
// Duration is used to UnmarshalTOML into a time.Duration value.
|
||||
type Duration struct{ time.Duration }
|
||||
|
||||
// UnmarshalText parses a duration type from a config file.
|
||||
func (d *Duration) UnmarshalText(data []byte) (err error) {
|
||||
d.Duration, err = time.ParseDuration(string(data))
|
||||
return
|
||||
}
|
||||
|
||||
// ParseFile parses and returns our configuration data.
|
||||
func (c *Config) ParseFile(configFile string) error {
|
||||
switch buf, err := ioutil.ReadFile(configFile); {
|
||||
case err != nil:
|
||||
return err
|
||||
case strings.Contains(configFile, ".json"):
|
||||
return json.Unmarshal(buf, c)
|
||||
case strings.Contains(configFile, ".xml"):
|
||||
return xml.Unmarshal(buf, c)
|
||||
case strings.Contains(configFile, ".yaml"):
|
||||
return yaml.Unmarshal(buf, c)
|
||||
default:
|
||||
return toml.Unmarshal(buf, c)
|
||||
}
|
||||
}
|
||||
|
||||
// ParseENV 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.
|
||||
// This method uses the json struct tag member to match environment variables.
|
||||
// Use a custom tag name by changing "json" below, but that's overkill for this app.
|
||||
func (c *Config) ParseENV() error {
|
||||
t := reflect.TypeOf(*c) // Get "types" from the Config struct.
|
||||
for i := 0; i < t.NumField(); i++ { // Loop each Config struct member
|
||||
tag := t.Field(i).Tag.Get("json") // Get the ENV variable name from "json" struct tag
|
||||
tag = strings.Split(strings.ToUpper(tag), ",")[0] // Capitalize and remove ,omitempty suffix
|
||||
|
||||
env := os.Getenv(ENVConfigPrefix + tag) // Then pull value from OS.
|
||||
if tag == "" || env == "" { // Skip if either are empty.
|
||||
continue
|
||||
}
|
||||
|
||||
if err := c.parseENV(reflect.ValueOf(c).Elem().Field(i), tag, env); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) parseENV(field reflect.Value, tag, env string) error {
|
||||
// Reflect and update the u.Config struct member at position i.
|
||||
switch field.Type().String() {
|
||||
// Handle each member type appropriately (differently).
|
||||
case "string":
|
||||
// This is a reflect package method to update a struct member by index.
|
||||
field.SetString(env)
|
||||
|
||||
case "int":
|
||||
val, err := strconv.Atoi(env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %v", tag, err)
|
||||
}
|
||||
field.Set(reflect.ValueOf(val))
|
||||
|
||||
case "[]string":
|
||||
field.Set(reflect.ValueOf(strings.Split(env, ",")))
|
||||
|
||||
case "poller.Duration":
|
||||
val, err := time.ParseDuration(env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %v", tag, err)
|
||||
}
|
||||
field.Set(reflect.ValueOf(Duration{val}))
|
||||
|
||||
case "bool":
|
||||
val, err := strconv.ParseBool(env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %v", tag, err)
|
||||
}
|
||||
field.SetBool(val)
|
||||
|
||||
case "poller.[]*Controller":
|
||||
}
|
||||
// Add more types here if more types are added to the config struct.
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) parseSlice(field reflect.Value, tag, env string) error {
|
||||
Interval config.Duration `json:"interval,omitempty" toml:"interval,omitempty" xml:"interval" yaml:"interval"`
|
||||
Debug bool `json:"debug" toml:"debug" xml:"debug" yaml:"debug"`
|
||||
Quiet bool `json:"quiet,omitempty" toml:"quiet,omitempty" xml:"quiet" yaml:"quiet"`
|
||||
VerifySSL bool `json:"verify_ssl" toml:"verify_ssl" xml:"verify_ssl" yaml:"verify_ssl"`
|
||||
SaveIDS bool `json:"save_ids" toml:"save_ids" xml:"save_ids" yaml:"save_ids"`
|
||||
ReAuth bool `json:"reauthenticate" toml:"reauthenticate" xml:"reauthenticate" yaml:"reauthenticate"`
|
||||
InfxBadSSL bool `json:"influx_insecure_ssl" toml:"influx_insecure_ssl" xml:"influx_insecure_ssl" yaml:"influx_insecure_ssl"`
|
||||
SaveSites bool `json:"save_sites,omitempty" toml:"save_sites,omitempty" xml:"save_sites" yaml:"save_sites"`
|
||||
Mode string `json:"mode" toml:"mode" xml:"mode" yaml:"mode"`
|
||||
HTTPListen string `json:"http_listen" toml:"http_listen" xml:"http_listen" yaml:"http_listen"`
|
||||
Namespace string `json:"namespace" toml:"namespace" xml:"namespace" yaml:"namespace"`
|
||||
InfluxURL string `json:"influx_url,omitempty" toml:"influx_url,omitempty" xml:"influx_url" yaml:"influx_url"`
|
||||
InfluxUser string `json:"influx_user,omitempty" toml:"influx_user,omitempty" xml:"influx_user" yaml:"influx_user"`
|
||||
InfluxPass string `json:"influx_pass,omitempty" toml:"influx_pass,omitempty" xml:"influx_pass" yaml:"influx_pass"`
|
||||
InfluxDB string `json:"influx_db,omitempty" toml:"influx_db,omitempty" xml:"influx_db" yaml:"influx_db"`
|
||||
UnifiUser string `json:"unifi_user,omitempty" toml:"unifi_user,omitempty" xml:"unifi_user" yaml:"unifi_user"`
|
||||
UnifiPass string `json:"unifi_pass,omitempty" toml:"unifi_pass,omitempty" xml:"unifi_pass" yaml:"unifi_pass"`
|
||||
UnifiBase string `json:"unifi_url,omitempty" toml:"unifi_url,omitempty" xml:"unifi_url" yaml:"unifi_url"`
|
||||
Sites []string `json:"sites,omitempty" toml:"sites,omitempty" xml:"sites" yaml:"sites"`
|
||||
Controller []Controller `json:"controller,omitempty" toml:"controller,omitempty" xml:"controller" yaml:"controller"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"golift.io/config"
|
||||
)
|
||||
|
||||
// New returns a new poller struct preloaded with default values.
|
||||
|
|
@ -23,7 +24,7 @@ func New() *UnifiPoller {
|
|||
UnifiUser: defaultUnifiUser,
|
||||
UnifiPass: "",
|
||||
UnifiBase: defaultUnifiURL,
|
||||
Interval: Duration{defaultInterval},
|
||||
Interval: config.Duration{Duration: defaultInterval},
|
||||
Sites: []string{"all"},
|
||||
SaveSites: true,
|
||||
HTTPListen: defaultHTTPListen,
|
||||
|
|
@ -53,16 +54,16 @@ func (u *UnifiPoller) Start() error {
|
|||
}
|
||||
|
||||
// Parse config file.
|
||||
if err := u.Config.ParseFile(u.Flag.ConfigFile); err != nil {
|
||||
if err := config.ParseFile(u.Config, u.Flag.ConfigFile); err != nil {
|
||||
u.Flag.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
// Update Config with ENV variable overrides.
|
||||
if err := u.Config.ParseENV(); err != nil {
|
||||
if _, err := config.ParseENV(u.Config, ENVConfigPrefix); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Println("START():", u.Config.Controller)
|
||||
if u.Flag.DumpJSON != "" {
|
||||
return u.DumpJSONPayload()
|
||||
}
|
||||
|
|
@ -71,7 +72,7 @@ func (u *UnifiPoller) Start() error {
|
|||
log.SetFlags(log.Lshortfile | log.Lmicroseconds | log.Ldate)
|
||||
u.LogDebugf("Debug Logging Enabled")
|
||||
}
|
||||
|
||||
log.Println("sites", u.Config.Sites)
|
||||
log.Printf("[INFO] UniFi Poller v%v Starting Up! PID: %d", Version, os.Getpid())
|
||||
return u.Run()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,8 +70,7 @@ FIRST:
|
|||
continue FIRST
|
||||
}
|
||||
}
|
||||
// This is fine, it may get added later.
|
||||
u.LogErrorf("configured site not found on controller: %v", s)
|
||||
return fmt.Errorf("configured site not found on controller: %v", s)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
Loading…
Reference in New Issue