From 023f5749b0cfeb1371ff330393e854d9c4601260 Mon Sep 17 00:00:00 2001 From: unifi-poller-bot Date: Wed, 12 Jun 2019 20:32:33 -0700 Subject: [PATCH] Add json dump debug feature. --- .../inputunifi/cmd/unifi-poller/config.go | 17 +++- .../inputunifi/cmd/unifi-poller/jsondebug.go | 87 +++++++++++++++++++ .../inputunifi/cmd/unifi-poller/main.go | 63 ++++++++------ 3 files changed, 140 insertions(+), 27 deletions(-) create mode 100644 integrations/inputunifi/cmd/unifi-poller/jsondebug.go diff --git a/integrations/inputunifi/cmd/unifi-poller/config.go b/integrations/inputunifi/cmd/unifi-poller/config.go index 1b75860a..203a88fd 100644 --- a/integrations/inputunifi/cmd/unifi-poller/config.go +++ b/integrations/inputunifi/cmd/unifi-poller/config.go @@ -1,6 +1,10 @@ package main -import "time" +import ( + "time" + + "github.com/spf13/pflag" +) // Version is injected by the Makefile var Version = "development" @@ -17,11 +21,20 @@ const ( defaultUnifURL = "https://127.0.0.1:8443" ) +// UnifiPoller contains the application startup data. +type UnifiPoller struct { + ConfigFile string + DumpJSON string + ShowVer bool + *Config + Flag *pflag.FlagSet +} + // Config represents the data needed to poll a controller and report to influxdb. type Config struct { Interval Dur `json:"interval,_omitempty" toml:"interval,_omitempty" xml:"interval" yaml:"interval"` Debug bool `json:"debug" toml:"debug" xml:"debug" yaml:"debug"` - Quiet bool `json:"quiet" toml:"quiet" xml:"quiet" yaml:"quiet"` + 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"` 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"` diff --git a/integrations/inputunifi/cmd/unifi-poller/jsondebug.go b/integrations/inputunifi/cmd/unifi-poller/jsondebug.go new file mode 100644 index 00000000..011738bd --- /dev/null +++ b/integrations/inputunifi/cmd/unifi-poller/jsondebug.go @@ -0,0 +1,87 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + + "github.com/golift/unifi" + "github.com/pkg/errors" +) + +// DumpJSON prints raw json from the Unifi Controller. +func (c *Config) DumpJSON(filter string) error { + c.Quiet = true + controller, err := unifi.NewUnifi(c.UnifiUser, c.UnifiPass, c.UnifiBase, c.VerifySSL) + if err != nil { + return err + } + fmt.Fprintln(os.Stderr, "Authenticated to Unifi Controller @", c.UnifiBase, "as user", c.UnifiUser) + if err := c.CheckSites(controller); err != nil { + return err + } + controller.ErrorLog = func(m string, v ...interface{}) { + fmt.Fprintf(os.Stderr, m, v...) + } // Log all errors to stderr. + + switch sites, err := filterSites(controller, c.Sites); { + case err != nil: + return err + case StringInSlice(filter, []string{"d", "device", "devices"}): + return c.DumpClientsJSON(sites, controller) + case StringInSlice(filter, []string{"client", "clients", "c"}): + return c.DumpDeviceJSON(sites, controller) + default: + return errors.New("must provide filter: devices, clients") + } +} + +func errorLog(m string, v ...interface{}) { + fmt.Fprintf(os.Stderr, m, v...) +} + +// DumpClientsJSON prints the raw json for clients in a Unifi Controller. +func (c *Config) DumpClientsJSON(sites []unifi.Site, controller *unifi.Unifi) error { + for _, s := range sites { + path := fmt.Sprintf(unifi.ClientPath, s.Name) + req, err := controller.UniReq(path, "") + if err != nil { + return err + } + resp, err := controller.Do(req) + if err != nil { + return err + } + body, err := ioutil.ReadAll(resp.Body) + resp.Body.Close() + if err != nil { + return err + } + fmt.Fprintf(os.Stderr, "Dumping Client JSON for site %s (%s)\n", s.Desc, s.Name) + fmt.Println(string(body)) + } + return nil +} + +// DumpDeviceJSON prints the raw json for devices in a Unifi Controller. +func (c *Config) DumpDeviceJSON(sites []unifi.Site, controller *unifi.Unifi) error { + for _, s := range sites { + path := fmt.Sprintf(unifi.DevicePath, s.Name) + req, err := controller.UniReq(path, "") + if err != nil { + return err + } + resp, err := controller.Do(req) + if err != nil { + return err + } + body, err := ioutil.ReadAll(resp.Body) + resp.Body.Close() + if err != nil { + return err + } + fmt.Fprintf(os.Stderr, "Dumping Device JSON for site %s (%s)\n", s.Desc, s.Name) + fmt.Println(string(body)) + } + return nil +} diff --git a/integrations/inputunifi/cmd/unifi-poller/main.go b/integrations/inputunifi/cmd/unifi-poller/main.go index f7a233e2..562dfc22 100644 --- a/integrations/inputunifi/cmd/unifi-poller/main.go +++ b/integrations/inputunifi/cmd/unifi-poller/main.go @@ -21,20 +21,29 @@ type Asset interface { } func main() { - configFile := parseFlags() - log.Println("Unifi-Poller Starting Up! PID:", os.Getpid()) - config, err := GetConfig(configFile) - if err != nil { - flag.Usage() - log.Fatalf("[ERROR] config file '%v': %v", configFile, err) + u := &UnifiPoller{} + if u.ParseFlags(os.Args[1:]); u.ShowVer { + fmt.Printf("unifi-poller v%s\n", Version) + os.Exit(0) // don't run anything else. } - if err := config.Run(); err != nil { + if err := u.GetConfig(); err != nil { + u.Flag.Usage() + log.Fatalf("[ERROR] config file '%v': %v", u.ConfigFile, err) + } + if u.DumpJSON != "" { + if err := u.Config.DumpJSON(u.DumpJSON); err != nil { + log.Fatalln("[ERROR] dumping JSON:", err) + } + return + } + if err := u.Config.Run(); err != nil { log.Fatalln("[ERROR]", err) } } // Run invokes all the application logic and routines. func (c *Config) Run() error { + log.Println("Unifi-Poller Starting Up! PID:", os.Getpid()) // Create an authenticated session to the Unifi Controller. controller, err := unifi.NewUnifi(c.UnifiUser, c.UnifiPass, c.UnifiBase, c.VerifySSL) if err != nil { @@ -71,18 +80,17 @@ func (c *Config) Run() error { return nil } -func parseFlags() string { - flag.Usage = func() { +// ParseFlags runs the parser. +func (u *UnifiPoller) ParseFlags(args []string) { + u.Flag = flag.NewFlagSet("unifi-poller", flag.ExitOnError) + u.Flag.Usage = func() { fmt.Println("Usage: unifi-poller [--config=filepath] [--version]") - flag.PrintDefaults() + u.Flag.PrintDefaults() } - configFile := flag.StringP("config", "c", defaultConfFile, "Poller Config File (TOML Format)") - version := flag.BoolP("version", "v", false, "Print the version and exit") - if flag.Parse(); *version { - fmt.Printf("unifi-poller v%s\n", Version) - os.Exit(0) // don't run anything else. - } - return *configFile + u.Flag.StringVarP(&u.DumpJSON, "dumpjson", "j", "", "This debug option prints the json payload for a device and exits.") + u.Flag.StringVarP(&u.ConfigFile, "config", "c", defaultConfFile, "Poller Config File (TOML Format)") + u.Flag.BoolVarP(&u.ShowVer, "version", "v", false, "Print the version and exit") + _ = u.Flag.Parse(args) } // CheckSites makes sure the list of provided sites exists on the controller. @@ -114,9 +122,9 @@ FIRST: } // GetConfig parses and returns our configuration data. -func GetConfig(configFile string) (Config, error) { +func (u *UnifiPoller) GetConfig() error { // Preload our defaults. - config := Config{ + u.Config = &Config{ InfluxURL: defaultInfxURL, InfluxUser: defaultInfxUser, InfluxPass: defaultInfxPass, @@ -127,14 +135,19 @@ func GetConfig(configFile string) (Config, error) { Interval: Dur{value: defaultInterval}, Sites: []string{"default"}, } - if buf, err := ioutil.ReadFile(configFile); err != nil { - return config, err + if buf, err := ioutil.ReadFile(u.ConfigFile); err != nil { + return err // This is where the defaults in the config variable are overwritten. - } else if err := toml.Unmarshal(buf, &config); err != nil { - return config, err + } else if err := toml.Unmarshal(buf, u.Config); err != nil { + return err } - log.Println("Loaded Configuration:", configFile) - return config, nil + if u.DumpJSON != "" { + u.Quiet = true + } + if !u.Config.Quiet { + log.Println("Loaded Configuration:", u.ConfigFile) + } + return nil } // PollUnifiController runs forever, polling and pushing.