diff --git a/integrations/inputunifi/.gitignore b/integrations/inputunifi/.gitignore new file mode 100644 index 00000000..4170155f --- /dev/null +++ b/integrations/inputunifi/.gitignore @@ -0,0 +1 @@ +/go.sum diff --git a/integrations/inputunifi/.travis.yml b/integrations/inputunifi/.travis.yml index 654efb02..8e951c55 100644 --- a/integrations/inputunifi/.travis.yml +++ b/integrations/inputunifi/.travis.yml @@ -1,9 +1,9 @@ language: go go: -- 1.14.x +- 1.15.x before_install: # download super-linter: golangci-lint - curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin latest script: -- golangci-lint run --enable-all +- golangci-lint run --enable-all -D nlreturn,exhaustivestruct - go test ./... diff --git a/integrations/inputunifi/collectevents.go b/integrations/inputunifi/collectevents.go new file mode 100644 index 00000000..4f13780e --- /dev/null +++ b/integrations/inputunifi/collectevents.go @@ -0,0 +1,158 @@ +package inputunifi + +import ( + "fmt" + "time" + + "github.com/unifi-poller/unifi" + "github.com/unifi-poller/webserver" +) + +/* Event collection. Events are also sent to the webserver for display. */ + +func (u *InputUnifi) collectControllerEvents(c *Controller) ([]interface{}, error) { + if u.isNill(c) { + u.Logf("Re-authenticating to UniFi Controller: %s", c.URL) + + if err := u.getUnifi(c); err != nil { + return nil, fmt.Errorf("re-authenticating to %s: %w", c.URL, err) + } + } + + var ( + logs = []interface{}{} + newLogs []interface{} + ) + + // Get the sites we care about. + sites, err := u.getFilteredSites(c) + if err != nil { + return nil, fmt.Errorf("unifi.GetSites(): %w", err) + } + + type caller func([]interface{}, []*unifi.Site, *Controller) ([]interface{}, error) + + for _, call := range []caller{u.collectIDS, u.collectAnomalies, u.collectAlarms, u.collectEvents} { + if newLogs, err = call(logs, sites, c); err != nil { + return logs, err + } + + logs = append(logs, newLogs...) + } + + return logs, nil +} + +func (u *InputUnifi) collectAlarms(logs []interface{}, sites []*unifi.Site, c *Controller) ([]interface{}, error) { + if *c.SaveAlarms { + for _, s := range sites { + events, err := c.Unifi.GetAlarmsSite(s) + if err != nil { + return logs, fmt.Errorf("unifi.GetAlarms(): %w", err) + } + + for _, e := range events { + logs = append(logs, e) + + webserver.NewInputEvent(PluginName, s.ID+"_alarms", &webserver.Event{ + Ts: e.Datetime, Msg: e.Msg, Tags: map[string]string{ + "type": "alarm", "key": e.Key, "site_id": e.SiteID, + "site_name": e.SiteName, "source": e.SourceName, + }, + }) + } + } + } + + return logs, nil +} + +func (u *InputUnifi) collectAnomalies(logs []interface{}, sites []*unifi.Site, c *Controller) ([]interface{}, error) { + if *c.SaveAnomal { + for _, s := range sites { + events, err := c.Unifi.GetAnomaliesSite(s) + if err != nil { + return logs, fmt.Errorf("unifi.GetAnomalies(): %w", err) + } + + for _, e := range events { + logs = append(logs, e) + + webserver.NewInputEvent(PluginName, s.ID+"_anomalies", &webserver.Event{ + Ts: e.Datetime, Msg: e.Anomaly, Tags: map[string]string{ + "type": "anomaly", "site_name": e.SiteName, "source": e.SourceName, + }, + }) + } + } + } + + return logs, nil +} + +func (u *InputUnifi) collectEvents(logs []interface{}, sites []*unifi.Site, c *Controller) ([]interface{}, error) { + if *c.SaveEvents { + for _, s := range sites { + events, err := c.Unifi.GetSiteEvents(s, time.Hour) + if err != nil { + return logs, fmt.Errorf("unifi.GetEvents(): %w", err) + } + + for _, e := range events { + e := redactEvent(e, c.HashPII) + logs = append(logs, e) + + webserver.NewInputEvent(PluginName, s.ID+"_events", &webserver.Event{ + Msg: e.Msg, Ts: e.Datetime, Tags: map[string]string{ + "type": "event", "key": e.Key, "site_id": e.SiteID, + "site_name": e.SiteName, "source": e.SourceName, + }, + }) + } + } + } + + return logs, nil +} + +func (u *InputUnifi) collectIDS(logs []interface{}, sites []*unifi.Site, c *Controller) ([]interface{}, error) { + if *c.SaveIDS { + for _, s := range sites { + events, err := c.Unifi.GetIDSSite(s) + if err != nil { + return logs, fmt.Errorf("unifi.GetIDS(): %w", err) + } + + for _, e := range events { + logs = append(logs, e) + + webserver.NewInputEvent(PluginName, s.ID+"_ids", &webserver.Event{ + Ts: e.Datetime, Msg: e.Msg, Tags: map[string]string{ + "type": "ids", "key": e.Key, "site_id": e.SiteID, + "site_name": e.SiteName, "source": e.SourceName, + }, + }) + } + } + } + + return logs, nil +} + +// redactEvent attempts to mask personally identying information from log messages. +// This currently misses the "msg" value entirely and leaks PII information. +func redactEvent(e *unifi.Event, hash *bool) *unifi.Event { + if !*hash { + return e + } + + // metrics.Events[i].Msg <-- not sure what to do here. + e.DestIPGeo = unifi.IPGeo{} + e.SourceIPGeo = unifi.IPGeo{} + e.Host = RedactNamePII(e.Host, hash) + e.Hostname = RedactNamePII(e.Hostname, hash) + e.DstMAC = RedactMacPII(e.DstMAC, hash) + e.SrcMAC = RedactMacPII(e.SrcMAC, hash) + + return e +} diff --git a/integrations/inputunifi/collector.go b/integrations/inputunifi/collector.go index 2d6d76fb..8771618b 100644 --- a/integrations/inputunifi/collector.go +++ b/integrations/inputunifi/collector.go @@ -1,19 +1,17 @@ package inputunifi +// nolint: gosec import ( - "crypto/md5" // nolint: gosec + "crypto/md5" "fmt" "strings" "time" - "github.com/pkg/errors" "github.com/unifi-poller/poller" "github.com/unifi-poller/unifi" ) -var ( - errScrapeFilterMatchFailed = fmt.Errorf("scrape filter match failed, and filter is not http URL") -) +var ErrScrapeFilterMatchFailed = fmt.Errorf("scrape filter match failed, and filter is not http URL") func (u *InputUnifi) isNill(c *Controller) bool { u.RLock() @@ -42,17 +40,17 @@ func (u *InputUnifi) newDynamicCntrlr(url string) (bool, *Controller) { func (u *InputUnifi) dynamicController(filter *poller.Filter) (*poller.Metrics, error) { if !strings.HasPrefix(filter.Path, "http") { - return nil, errScrapeFilterMatchFailed + return nil, ErrScrapeFilterMatchFailed } - new, c := u.newDynamicCntrlr(filter.Path) + newCntrlr, c := u.newDynamicCntrlr(filter.Path) - if new { + if newCntrlr { u.Logf("Authenticating to Dynamic UniFi Controller: %s", filter.Path) if err := u.getUnifi(c); err != nil { u.logController(c) - return nil, errors.Wrapf(err, "authenticating to %s", filter.Path) + return nil, fmt.Errorf("authenticating to %s: %w", filter.Path, err) } u.logController(c) @@ -66,7 +64,7 @@ func (u *InputUnifi) collectController(c *Controller) (*poller.Metrics, error) { u.Logf("Re-authenticating to UniFi Controller: %s", c.URL) if err := u.getUnifi(c); err != nil { - return nil, errors.Wrapf(err, "re-authenticating to %s", c.URL) + return nil, fmt.Errorf("re-authenticating to %s: %w", c.URL, err) } } @@ -75,69 +73,13 @@ func (u *InputUnifi) collectController(c *Controller) (*poller.Metrics, error) { u.Logf("Re-authenticating to UniFi Controller: %s", c.URL) if err := u.getUnifi(c); err != nil { - return metrics, errors.Wrapf(err, "re-authenticating to %s", c.URL) + return metrics, fmt.Errorf("re-authenticating to %s: %w", c.URL, err) } } return metrics, err } -func (u *InputUnifi) collectControllerEvents(c *Controller) ([]interface{}, error) { - logs := []interface{}{} - - // Get the sites we care about. - sites, err := u.getFilteredSites(c) - if err != nil { - return nil, errors.Wrap(err, "unifi.GetSites()") - } - - if *c.SaveAnomal { - anom, err := c.Unifi.GetAnomalies(sites, time.Now().Add(-time.Hour)) - if err != nil { - return nil, errors.Wrap(err, "unifi.GetAnomalies()") - } - - for _, a := range anom { - logs = append(logs, a) - } - } - - if *c.SaveAlarms { - alarms, err := c.Unifi.GetAlarms(sites) - if err != nil { - return nil, errors.Wrap(err, "unifi.GetAlarms()") - } - - for _, a := range alarms { - logs = append(logs, a) - } - } - - if *c.SaveEvents { - events, err := c.Unifi.GetEvents(sites, time.Hour) - if err != nil { - return nil, errors.Wrap(err, "unifi.GetEvents()") - } - - for _, e := range events { - logs = append(logs, redactEvent(e, c.HashPII)) - } - } - - if *c.SaveIDS { - events, err := c.Unifi.GetIDS(sites, time.Now().Add(-time.Hour)) - if err != nil { - return nil, errors.Wrap(err, "unifi.GetIDS()") - } - - for _, e := range events { - logs = append(logs, e) - } - } - - return logs, nil -} - func (u *InputUnifi) pollController(c *Controller) (*poller.Metrics, error) { u.RLock() defer u.RUnlock() @@ -145,28 +87,29 @@ func (u *InputUnifi) pollController(c *Controller) (*poller.Metrics, error) { // Get the sites we care about. sites, err := u.getFilteredSites(c) if err != nil { - return nil, errors.Wrap(err, "unifi.GetSites()") + return nil, fmt.Errorf("unifi.GetSites(): %w", err) } m := &Metrics{TS: time.Now(), Sites: sites} + defer updateWeb(c, m) if c.SaveDPI != nil && *c.SaveDPI { if m.SitesDPI, err = c.Unifi.GetSiteDPI(sites); err != nil { - return nil, errors.Wrapf(err, "unifi.GetSiteDPI(%s)", c.URL) + return nil, fmt.Errorf("unifi.GetSiteDPI(%s): %w", c.URL, err) } if m.ClientsDPI, err = c.Unifi.GetClientsDPI(sites); err != nil { - return nil, errors.Wrapf(err, "unifi.GetClientsDPI(%s)", c.URL) + return nil, fmt.Errorf("unifi.GetClientsDPI(%s): %w", c.URL, err) } } // Get all the points. if m.Clients, err = c.Unifi.GetClients(sites); err != nil { - return nil, errors.Wrapf(err, "unifi.GetClients(%s)", c.URL) + return nil, fmt.Errorf("unifi.GetClients(%s): %w", c.URL, err) } if m.Devices, err = c.Unifi.GetDevices(sites); err != nil { - return nil, errors.Wrapf(err, "unifi.GetDevices(%s)", c.URL) + return nil, fmt.Errorf("unifi.GetDevices(%s): %w", c.URL, err) } return u.augmentMetrics(c, m), nil @@ -257,24 +200,6 @@ func extractDevices(metrics *Metrics) (*poller.Metrics, map[string]string, map[s return m, devices, bssdIDs } -// redactEvent attempts to mask personally identying information from log messages. -// This currently misses the "msg" value entirely and leaks PII information. -func redactEvent(e *unifi.Event, hash *bool) *unifi.Event { - if !*hash { - return e - } - - // metrics.Events[i].Msg <-- not sure what to do here. - e.DestIPGeo = unifi.IPGeo{} - e.SourceIPGeo = unifi.IPGeo{} - e.Host = RedactNamePII(e.Host, hash) - e.Hostname = RedactNamePII(e.Hostname, hash) - e.DstMAC = RedactMacPII(e.DstMAC, hash) - e.SrcMAC = RedactMacPII(e.SrcMAC, hash) - - return e -} - // RedactNamePII converts a name string to an md5 hash (first 24 chars only). // Useful for maskiing out personally identifying information. func RedactNamePII(pii string, hash *bool) string { @@ -308,7 +233,7 @@ func (u *InputUnifi) getFilteredSites(c *Controller) ([]*unifi.Site, error) { sites, err := c.Unifi.GetSites() if err != nil { - return nil, err + return nil, fmt.Errorf("controller: %w", err) } else if len(c.Sites) == 0 || StringInSlice("all", c.Sites) { return sites, nil } diff --git a/integrations/inputunifi/go.mod b/integrations/inputunifi/go.mod index 1718ea14..5fc42637 100644 --- a/integrations/inputunifi/go.mod +++ b/integrations/inputunifi/go.mod @@ -1,9 +1,9 @@ module github.com/unifi-poller/inputunifi -go 1.14 +go 1.15 require ( - github.com/pkg/errors v0.9.1 - github.com/unifi-poller/poller v0.0.8-0.20200621214016-5d1ed3324a46 - github.com/unifi-poller/unifi v0.0.6-0.20200625090439-421046871a37 + github.com/unifi-poller/poller v0.0.8 + github.com/unifi-poller/unifi v0.0.7-0.20210308061543-395de2119e12 + github.com/unifi-poller/webserver v0.0.0-20200704065911-79e4fe954ce1 ) diff --git a/integrations/inputunifi/go.sum b/integrations/inputunifi/go.sum deleted file mode 100644 index 5a7d916b..00000000 --- a/integrations/inputunifi/go.sum +++ /dev/null @@ -1,176 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A= -github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.1.1 h1:/ZKcW+ixpq2dOl4yeH4qvACNXnkiDCp5e/F5Tq07X7o= -github.com/prometheus/procfs v0.1.1/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/unifi-poller/poller v0.0.8-0.20200621084019-8e9b2f223849 h1:/xyUMrTm5Yc+Tobmmd4FCZjzhIJDPMQEmnHaAp4tTz4= -github.com/unifi-poller/poller v0.0.8-0.20200621084019-8e9b2f223849/go.mod h1:+Ppksi2wBCrByJke0B0lTutxFtKfv1zx6L1haALBrN4= -github.com/unifi-poller/poller v0.0.8-0.20200621091816-fd5c7abd9f4b h1:AJKt/ZIDtlEOWxwpL/a7pcrWmqdJaaNE9odNn4JSRj0= -github.com/unifi-poller/poller v0.0.8-0.20200621091816-fd5c7abd9f4b/go.mod h1:+Ppksi2wBCrByJke0B0lTutxFtKfv1zx6L1haALBrN4= -github.com/unifi-poller/poller v0.0.8-0.20200621101255-6d0d0b288ece h1:EsyR6cKuwAKzddS4gsKDugfN+OEHCm7bhNOvEfBCWWA= -github.com/unifi-poller/poller v0.0.8-0.20200621101255-6d0d0b288ece/go.mod h1:+Ppksi2wBCrByJke0B0lTutxFtKfv1zx6L1haALBrN4= -github.com/unifi-poller/poller v0.0.8-0.20200621103717-5f3d60890ed6 h1:V19WgXwjXxGY75Mn8Hc5Whl3+BC71YSGatRvKVRh9pA= -github.com/unifi-poller/poller v0.0.8-0.20200621103717-5f3d60890ed6/go.mod h1:+Ppksi2wBCrByJke0B0lTutxFtKfv1zx6L1haALBrN4= -github.com/unifi-poller/poller v0.0.8-0.20200621110949-33f1a1454d10 h1:1rGP4ISFpBj9xjJDXNak7EdaQtyoy3MwMZzo2+W1PLo= -github.com/unifi-poller/poller v0.0.8-0.20200621110949-33f1a1454d10/go.mod h1:+Ppksi2wBCrByJke0B0lTutxFtKfv1zx6L1haALBrN4= -github.com/unifi-poller/poller v0.0.8-0.20200621214016-5d1ed3324a46 h1:OhbVj3VVgbpUMQFSwD0NszDsbEL7DdbTcJuU+p9DwIM= -github.com/unifi-poller/poller v0.0.8-0.20200621214016-5d1ed3324a46/go.mod h1:pJ/MeYaakLOOpbyc7s4zeZ92UzNK/rir5jkA7t5jIjo= -github.com/unifi-poller/unifi v0.0.5-0.20200620103801-b927287ea1cd/go.mod h1:L1kMRH2buZhB31vZnRC1im7Tk/4uD3ET4biwl2faYy8= -github.com/unifi-poller/unifi v0.0.5-0.20200621075746-253ccae7e106 h1:eKErSqWD656pLSWgxFwhDhHe/zfAXrm7F39Zn4R+si8= -github.com/unifi-poller/unifi v0.0.5-0.20200621075746-253ccae7e106/go.mod h1:L1kMRH2buZhB31vZnRC1im7Tk/4uD3ET4biwl2faYy8= -github.com/unifi-poller/unifi v0.0.5-0.20200622073824-4a29471d80f6 h1:KzQDaEhDxtDzoyfBPXzM/pwpD76+4Y74Y66XMhKt2pI= -github.com/unifi-poller/unifi v0.0.5-0.20200622073824-4a29471d80f6/go.mod h1:L1kMRH2buZhB31vZnRC1im7Tk/4uD3ET4biwl2faYy8= -github.com/unifi-poller/unifi v0.0.6-0.20200625090439-421046871a37 h1:T2y8JWkjZd1vz2ZKu4vmmAk9s6PUwupuTldwhfww5xY= -github.com/unifi-poller/unifi v0.0.6-0.20200625090439-421046871a37/go.mod h1:L1kMRH2buZhB31vZnRC1im7Tk/4uD3ET4biwl2faYy8= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200610111108-226ff32320da h1:bGb80FudwxpeucJUjPYJXuJ8Hk91vNtfvrymzwiei38= -golang.org/x/sys v0.0.0-20200610111108-226ff32320da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golift.io/cnfg v0.0.5 h1:HnMU8Z9C/igKvir1dqaHx5BPuNGZrp99FCtdJyP2Z4I= -golift.io/cnfg v0.0.5/go.mod h1:ScFDIJg/rJGHbRaed/i7g1lBhywEjB0JiP2uZr3xC3A= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/integrations/inputunifi/input.go b/integrations/inputunifi/input.go index 9129aa27..b9f81841 100644 --- a/integrations/inputunifi/input.go +++ b/integrations/inputunifi/input.go @@ -3,19 +3,20 @@ package inputunifi import ( + "fmt" "io/ioutil" "strings" + "sync" "time" - "sync" - - "github.com/pkg/errors" "github.com/unifi-poller/poller" "github.com/unifi-poller/unifi" ) +// PluginName is the name of this input plugin. +const PluginName = "unifi" + const ( - PluginName = "unifi" // PluginName is the name of this input plugin. defaultURL = "https://127.0.0.1:8443" defaultUser = "unifipoller" defaultPass = "unifipoller" @@ -27,7 +28,7 @@ type InputUnifi struct { *Config `json:"unifi" toml:"unifi" xml:"unifi" yaml:"unifi"` dynamic map[string]*Controller sync.Mutex // to lock the map above. - poller.Logger + Logger poller.Logger } // Controller represents the configuration for a UniFi Controller. @@ -44,8 +45,9 @@ type Controller struct { User string `json:"user" toml:"user" xml:"user" yaml:"user"` Pass string `json:"pass" toml:"pass" xml:"pass" yaml:"pass"` URL string `json:"url" toml:"url" xml:"url" yaml:"url"` - Sites []string `json:"sites,omitempty" toml:"sites,omitempty" xml:"site" yaml:"sites"` + Sites []string `json:"sites" toml:"sites" xml:"site" yaml:"sites"` Unifi *unifi.Unifi `json:"-" toml:"-" xml:"-" yaml:"-"` + ID string `json:"id,omitempty"` // this is an output, not an input. } // Config contains our configuration data. @@ -57,6 +59,7 @@ type Config struct { Controllers []*Controller `json:"controllers" toml:"controller" xml:"controller" yaml:"controllers"` } +// Metrics is simply a useful container for everything. type Metrics struct { TS time.Time Sites []*unifi.Site @@ -100,7 +103,7 @@ func (u *InputUnifi) getUnifi(c *Controller) error { }) if err != nil { c.Unifi = nil - return errors.Wrap(err, "unifi controller") + return fmt.Errorf("unifi controller: %w", err) } u.LogDebugf("Authenticated with controller successfully, %s", c.URL) @@ -122,7 +125,7 @@ func (u *InputUnifi) checkSites(c *Controller) error { sites, err := c.Unifi.GetSites() if err != nil { - return err + return fmt.Errorf("controller: %w", err) } msg := []string{} @@ -167,7 +170,7 @@ func (u *InputUnifi) getPassFromFile(filename string) string { } // setDefaults sets the default defaults. -func (u *InputUnifi) setDefaults(c *Controller) { +func (u *InputUnifi) setDefaults(c *Controller) { //nolint:cyclop t := true f := false @@ -227,7 +230,7 @@ func (u *InputUnifi) setDefaults(c *Controller) { // setControllerDefaults sets defaults for the for controllers. // Any missing values come from defaults (above). -func (u *InputUnifi) setControllerDefaults(c *Controller) *Controller { +func (u *InputUnifi) setControllerDefaults(c *Controller) *Controller { //nolint:cyclop // Configured controller defaults. if c.SaveSites == nil { c.SaveSites = u.Default.SaveSites diff --git a/integrations/inputunifi/interface.go b/integrations/inputunifi/interface.go index b7df17da..27ba98d5 100644 --- a/integrations/inputunifi/interface.go +++ b/integrations/inputunifi/interface.go @@ -6,15 +6,15 @@ import ( "fmt" "strings" - "github.com/pkg/errors" "github.com/unifi-poller/poller" "github.com/unifi-poller/unifi" + "github.com/unifi-poller/webserver" ) var ( - errDynamicLookupsDisabled = fmt.Errorf("filter path requested but dynamic lookups disabled") - errControllerNumNotFound = fmt.Errorf("controller number not found") - errNoFilterKindProvided = fmt.Errorf("must provide filter: devices, clients, other") + ErrDynamicLookupsDisabled = fmt.Errorf("filter path requested but dynamic lookups disabled") + ErrControllerNumNotFound = fmt.Errorf("controller number not found") + ErrNoFilterKindProvided = fmt.Errorf("must provide filter: devices, clients, other") ) // Initialize gets called one time when starting up. @@ -39,20 +39,21 @@ func (u *InputUnifi) Initialize(l poller.Logger) error { } for i, c := range u.Controllers { - switch err := u.getUnifi(u.setControllerDefaults(c)); err { - case nil: - if err := u.checkSites(c); err != nil { - u.LogErrorf("checking sites on %s: %v", c.URL, err) - } - - u.Logf("Configured UniFi Controller %d of %d:", i+1, len(u.Controllers)) - default: + if err := u.getUnifi(u.setControllerDefaults(c)); err != nil { u.LogErrorf("Controller %d of %d Auth or Connection Error, retrying: %v", i+1, len(u.Controllers), err) + continue } + if err := u.checkSites(c); err != nil { + u.LogErrorf("checking sites on %s: %v", c.URL, err) + } + + u.Logf("Configured UniFi Controller %d of %d:", i+1, len(u.Controllers)) u.logController(c) } + webserver.UpdateInput(&webserver.Input{Name: PluginName, Config: formatConfig(u.Config)}) + return nil } @@ -133,7 +134,7 @@ func (u *InputUnifi) Metrics(filter *poller.Filter) (*poller.Metrics, error) { } if !u.Dynamic { - return nil, errDynamicLookupsDisabled + return nil, ErrDynamicLookupsDisabled } // Attempt a dynamic metrics fetch from an unconfigured controller. @@ -144,7 +145,7 @@ func (u *InputUnifi) Metrics(filter *poller.Filter) (*poller.Metrics, error) { // Adjust filter.Unit to pull from a controller other than the first. func (u *InputUnifi) RawMetrics(filter *poller.Filter) ([]byte, error) { if l := len(u.Controllers); filter.Unit >= l { - return nil, errors.Wrapf(errControllerNumNotFound, "%d controller(s) configured, '%d'", l, filter.Unit) + return nil, fmt.Errorf("%d controller(s) configured, '%d': %w", l, filter.Unit, ErrControllerNumNotFound) } c := u.Controllers[filter.Unit] @@ -152,7 +153,7 @@ func (u *InputUnifi) RawMetrics(filter *poller.Filter) ([]byte, error) { u.Logf("Re-authenticating to UniFi Controller: %s", c.URL) if err := u.getUnifi(c); err != nil { - return nil, errors.Wrapf(err, "re-authenticating to %s", c.URL) + return nil, fmt.Errorf("re-authenticating to %s: %w", c.URL, err) } } @@ -173,7 +174,7 @@ func (u *InputUnifi) RawMetrics(filter *poller.Filter) ([]byte, error) { case "other", "o": return c.Unifi.GetJSON(filter.Path) default: - return []byte{}, errNoFilterKindProvided + return []byte{}, ErrNoFilterKindProvided } } @@ -186,7 +187,7 @@ func (u *InputUnifi) getSitesJSON(c *Controller, path string, sites []*unifi.Sit body, err := c.Unifi.GetJSON(apiPath) if err != nil { - return allJSON, err + return allJSON, fmt.Errorf("controller: %w", err) } allJSON = append(allJSON, body...) diff --git a/integrations/inputunifi/updateweb.go b/integrations/inputunifi/updateweb.go new file mode 100644 index 00000000..e83d5314 --- /dev/null +++ b/integrations/inputunifi/updateweb.go @@ -0,0 +1,213 @@ +package inputunifi + +import ( + "fmt" + "strconv" + "time" + + "github.com/unifi-poller/unifi" + "github.com/unifi-poller/webserver" +) + +/* This code reformats our data to be displayed on the built-in web interface. */ + +func updateWeb(c *Controller, metrics *Metrics) { + webserver.UpdateInput(&webserver.Input{ + Name: PluginName, // Forgetting this leads to 3 hours of head scratching. + Sites: formatSites(c, metrics.Sites), + Clients: formatClients(c, metrics.Clients), + Devices: formatDevices(c, metrics.Devices), + }) +} + +func formatConfig(config *Config) *Config { + return &Config{ + Default: *formatControllers([]*Controller{&config.Default})[0], + Disable: config.Disable, + Dynamic: config.Dynamic, + Controllers: formatControllers(config.Controllers), + } +} + +func formatControllers(controllers []*Controller) []*Controller { + fixed := []*Controller{} + + for _, c := range controllers { + id := "" + if c.Unifi != nil { + id = c.Unifi.UUID + } + + fixed = append(fixed, &Controller{ + VerifySSL: c.VerifySSL, + SaveAnomal: c.SaveAnomal, + SaveAlarms: c.SaveAlarms, + SaveEvents: c.SaveEvents, + SaveIDS: c.SaveIDS, + SaveDPI: c.SaveDPI, + HashPII: c.HashPII, + SaveSites: c.SaveSites, + User: c.User, + Pass: strconv.FormatBool(c.Pass != ""), + URL: c.URL, + Sites: c.Sites, + ID: id, + }) + } + + return fixed +} + +func formatSites(c *Controller, sites []*unifi.Site) (s webserver.Sites) { + for _, site := range sites { + s = append(s, &webserver.Site{ + ID: site.ID, + Name: site.Name, + Desc: site.Desc, + Source: site.SourceName, + Controller: c.Unifi.UUID, + }) + } + + return s +} + +func formatClients(c *Controller, clients []*unifi.Client) (d webserver.Clients) { + for _, client := range clients { + clientType, deviceMAC := "unknown", "unknown" + if client.ApMac != "" { + clientType = "wireless" + deviceMAC = client.ApMac + } else if client.SwMac != "" { + clientType = "wired" + deviceMAC = client.SwMac + } + + if deviceMAC == "" { + deviceMAC = client.GwMac + } + + d = append(d, &webserver.Client{ + Name: client.Name, + SiteID: client.SiteID, + Source: client.SourceName, + Controller: c.Unifi.UUID, + MAC: client.Mac, + IP: client.IP, + Type: clientType, + DeviceMAC: deviceMAC, + Rx: client.RxBytes, + Tx: client.TxBytes, + Since: time.Unix(client.FirstSeen, 0), + Last: time.Unix(client.LastSeen, 0), + }) + } + + return d +} + +func formatDevices(c *Controller, devices *unifi.Devices) (d webserver.Devices) { // nolint: funlen + if devices == nil { + return d + } + + for _, device := range devices.UAPs { + d = append(d, &webserver.Device{ + Name: device.Name, + SiteID: device.SiteID, + Source: device.SourceName, + Controller: c.Unifi.UUID, + MAC: device.Mac, + IP: device.IP, + Type: device.Type, + Model: device.Model, + Version: device.Version, + Uptime: int(device.Uptime.Val), + Clients: int(device.NumSta.Val), + Config: nil, + }) + } + + for _, device := range devices.UDMs { + d = append(d, &webserver.Device{ + Name: device.Name, + SiteID: device.SiteID, + Source: device.SourceName, + Controller: c.Unifi.UUID, + MAC: device.Mac, + IP: device.IP, + Type: device.Type, + Model: device.Model, + Version: device.Version, + Uptime: int(device.Uptime.Val), + Clients: int(device.NumSta.Val), + Config: nil, + }) + } + + for _, device := range devices.USWs { + d = append(d, &webserver.Device{ + Name: device.Name, + SiteID: device.SiteID, + Source: device.SourceName, + Controller: c.Unifi.UUID, + MAC: device.Mac, + IP: device.IP, + Type: device.Type, + Model: device.Model, + Version: device.Version, + Uptime: int(device.Uptime.Val), + Clients: int(device.NumSta.Val), + Config: nil, + }) + } + + for _, device := range devices.USGs { + d = append(d, &webserver.Device{ + Name: device.Name, + SiteID: device.SiteID, + Source: device.SourceName, + Controller: c.Unifi.UUID, + MAC: device.Mac, + IP: device.IP, + Type: device.Type, + Model: device.Model, + Version: device.Version, + Uptime: int(device.Uptime.Val), + Clients: int(device.NumSta.Val), + Config: nil, + }) + } + + return d +} + +// Logf logs a message. +func (u *InputUnifi) Logf(msg string, v ...interface{}) { + webserver.NewInputEvent(PluginName, PluginName, &webserver.Event{ + Ts: time.Now(), + Msg: fmt.Sprintf(msg, v...), + Tags: map[string]string{"type": "info"}, + }) + u.Logger.Logf(msg, v...) +} + +// LogErrorf logs an error message. +func (u *InputUnifi) LogErrorf(msg string, v ...interface{}) { + webserver.NewInputEvent(PluginName, PluginName, &webserver.Event{ + Ts: time.Now(), + Msg: fmt.Sprintf(msg, v...), + Tags: map[string]string{"type": "error"}, + }) + u.Logger.LogErrorf(msg, v...) +} + +// LogDebugf logs a debug message. +func (u *InputUnifi) LogDebugf(msg string, v ...interface{}) { + webserver.NewInputEvent(PluginName, PluginName, &webserver.Event{ + Ts: time.Now(), + Msg: fmt.Sprintf(msg, v...), + Tags: map[string]string{"type": "debug"}, + }) + u.Logger.LogDebugf(msg, v...) +}