Merge pull request #3 from unifi-poller/dn2_events
Add Events input and update poller interface
This commit is contained in:
		
						commit
						2d68035a3c
					
				|  | @ -40,19 +40,19 @@ func (u *InputUnifi) newDynamicCntrlr(url string) (bool, *Controller) { | ||||||
| 	return true, u.dynamic[url] | 	return true, u.dynamic[url] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (u *InputUnifi) dynamicController(url string) (*poller.Metrics, error) { | func (u *InputUnifi) dynamicController(filter *poller.Filter) (*poller.Metrics, error) { | ||||||
| 	if !strings.HasPrefix(url, "http") { | 	if !strings.HasPrefix(filter.Path, "http") { | ||||||
| 		return nil, errScrapeFilterMatchFailed | 		return nil, errScrapeFilterMatchFailed | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	new, c := u.newDynamicCntrlr(url) | 	new, c := u.newDynamicCntrlr(filter.Path) | ||||||
| 
 | 
 | ||||||
| 	if new { | 	if new { | ||||||
| 		u.Logf("Authenticating to Dynamic UniFi Controller: %s", url) | 		u.Logf("Authenticating to Dynamic UniFi Controller: %s", filter.Path) | ||||||
| 
 | 
 | ||||||
| 		if err := u.getUnifi(c); err != nil { | 		if err := u.getUnifi(c); err != nil { | ||||||
| 			u.logController(c) | 			u.logController(c) | ||||||
| 			return nil, errors.Wrapf(err, "authenticating to %s", url) | 			return nil, errors.Wrapf(err, "authenticating to %s", filter.Path) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		u.logController(c) | 		u.logController(c) | ||||||
|  | @ -82,42 +82,90 @@ func (u *InputUnifi) collectController(c *Controller) (*poller.Metrics, error) { | ||||||
| 	return metrics, err | 	return metrics, err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (u *InputUnifi) pollController(c *Controller) (*poller.Metrics, error) { | func (u *InputUnifi) collectControllerEvents(c *Controller) ([]interface{}, error) { | ||||||
| 	var err error | 	logs := []interface{}{} | ||||||
| 
 |  | ||||||
| 	u.RLock() |  | ||||||
| 	defer u.RUnlock() |  | ||||||
| 
 |  | ||||||
| 	m := &poller.Metrics{TS: time.Now()} // At this point, it's the Current Check.
 |  | ||||||
| 
 | 
 | ||||||
| 	// Get the sites we care about.
 | 	// Get the sites we care about.
 | ||||||
| 	if m.Sites, err = u.getFilteredSites(c); err != nil { | 	sites, err := u.getFilteredSites(c) | ||||||
|  | 	if err != nil { | ||||||
| 		return nil, errors.Wrap(err, "unifi.GetSites()") | 		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() | ||||||
|  | 
 | ||||||
|  | 	// Get the sites we care about.
 | ||||||
|  | 	sites, err := u.getFilteredSites(c) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, errors.Wrap(err, "unifi.GetSites()") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	m := &Metrics{TS: time.Now(), Sites: sites} | ||||||
|  | 
 | ||||||
| 	if c.SaveDPI != nil && *c.SaveDPI { | 	if c.SaveDPI != nil && *c.SaveDPI { | ||||||
| 		if m.SitesDPI, err = c.Unifi.GetSiteDPI(m.Sites); err != nil { | 		if m.SitesDPI, err = c.Unifi.GetSiteDPI(sites); err != nil { | ||||||
| 			return nil, errors.Wrapf(err, "unifi.GetSiteDPI(%s)", c.URL) | 			return nil, errors.Wrapf(err, "unifi.GetSiteDPI(%s)", c.URL) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if m.ClientsDPI, err = c.Unifi.GetClientsDPI(m.Sites); err != nil { | 		if m.ClientsDPI, err = c.Unifi.GetClientsDPI(sites); err != nil { | ||||||
| 			return nil, errors.Wrapf(err, "unifi.GetClientsDPI(%s)", c.URL) | 			return nil, errors.Wrapf(err, "unifi.GetClientsDPI(%s)", c.URL) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if c.SaveIDS != nil && *c.SaveIDS { |  | ||||||
| 		m.IDSList, err = c.Unifi.GetIDS(m.Sites, time.Now().Add(time.Minute), time.Now()) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, errors.Wrapf(err, "unifi.GetIDS(%s)", c.URL) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Get all the points.
 | 	// Get all the points.
 | ||||||
| 	if m.Clients, err = c.Unifi.GetClients(m.Sites); err != nil { | 	if m.Clients, err = c.Unifi.GetClients(sites); err != nil { | ||||||
| 		return nil, errors.Wrapf(err, "unifi.GetClients(%s)", c.URL) | 		return nil, errors.Wrapf(err, "unifi.GetClients(%s)", c.URL) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if m.Devices, err = c.Unifi.GetDevices(m.Sites); err != nil { | 	if m.Devices, err = c.Unifi.GetDevices(sites); err != nil { | ||||||
| 		return nil, errors.Wrapf(err, "unifi.GetDevices(%s)", c.URL) | 		return nil, errors.Wrapf(err, "unifi.GetDevices(%s)", c.URL) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -126,72 +174,111 @@ func (u *InputUnifi) pollController(c *Controller) (*poller.Metrics, error) { | ||||||
| 
 | 
 | ||||||
| // augmentMetrics is our middleware layer between collecting metrics and writing them.
 | // augmentMetrics is our middleware layer between collecting metrics and writing them.
 | ||||||
| // This is where we can manipuate the returned data or make arbitrary decisions.
 | // This is where we can manipuate the returned data or make arbitrary decisions.
 | ||||||
| // This function currently adds parent device names to client metrics.
 | // This method currently adds parent device names to client metrics and hashes PII.
 | ||||||
| func (u *InputUnifi) augmentMetrics(c *Controller, metrics *poller.Metrics) *poller.Metrics { | // This method also converts our local *Metrics type into a slice of interfaces for poller.
 | ||||||
| 	if metrics == nil || metrics.Devices == nil || metrics.Clients == nil { | func (u *InputUnifi) augmentMetrics(c *Controller, metrics *Metrics) *poller.Metrics { | ||||||
| 		return metrics | 	if metrics == nil { | ||||||
|  | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	m, devices, bssdIDs := extractDevices(metrics) | ||||||
|  | 
 | ||||||
|  | 	// These come blank, so set them here.
 | ||||||
|  | 	for _, client := range metrics.Clients { | ||||||
|  | 		if devices[client.Mac] = client.Name; client.Name == "" { | ||||||
|  | 			devices[client.Mac] = client.Hostname | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		client.Mac = RedactMacPII(client.Mac, c.HashPII) | ||||||
|  | 		client.Name = RedactNamePII(client.Name, c.HashPII) | ||||||
|  | 		client.Hostname = RedactNamePII(client.Hostname, c.HashPII) | ||||||
|  | 		client.SwName = devices[client.SwMac] | ||||||
|  | 		client.ApName = devices[client.ApMac] | ||||||
|  | 		client.GwName = devices[client.GwMac] | ||||||
|  | 		client.RadioDescription = bssdIDs[client.Bssid] + client.RadioProto | ||||||
|  | 		m.Clients = append(m.Clients, client) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, client := range metrics.ClientsDPI { | ||||||
|  | 		// Name on Client DPI data also comes blank, find it based on MAC address.
 | ||||||
|  | 		client.Name = devices[client.MAC] | ||||||
|  | 		if client.Name == "" { | ||||||
|  | 			client.Name = client.MAC | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		client.Name = RedactNamePII(client.Name, c.HashPII) | ||||||
|  | 		client.MAC = RedactMacPII(client.MAC, c.HashPII) | ||||||
|  | 		m.ClientsDPI = append(m.ClientsDPI, client) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if *c.SaveSites { | ||||||
|  | 		for _, site := range metrics.Sites { | ||||||
|  | 			m.Sites = append(m.Sites, site) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		for _, site := range metrics.SitesDPI { | ||||||
|  | 			m.SitesDPI = append(m.SitesDPI, site) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return m | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // this is a helper function for augmentMetrics.
 | ||||||
|  | func extractDevices(metrics *Metrics) (*poller.Metrics, map[string]string, map[string]string) { | ||||||
|  | 	m := &poller.Metrics{TS: metrics.TS} | ||||||
| 	devices := make(map[string]string) | 	devices := make(map[string]string) | ||||||
| 	bssdIDs := make(map[string]string) | 	bssdIDs := make(map[string]string) | ||||||
| 
 | 
 | ||||||
| 	for _, r := range metrics.UAPs { | 	for _, r := range metrics.Devices.UAPs { | ||||||
| 		devices[r.Mac] = r.Name | 		devices[r.Mac] = r.Name | ||||||
|  | 		m.Devices = append(m.Devices, r) | ||||||
| 
 | 
 | ||||||
| 		for _, v := range r.VapTable { | 		for _, v := range r.VapTable { | ||||||
| 			bssdIDs[v.Bssid] = fmt.Sprintf("%s %s %s:", r.Name, v.Radio, v.RadioName) | 			bssdIDs[v.Bssid] = fmt.Sprintf("%s %s %s:", r.Name, v.Radio, v.RadioName) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for _, r := range metrics.USGs { | 	for _, r := range metrics.Devices.USGs { | ||||||
| 		devices[r.Mac] = r.Name | 		devices[r.Mac] = r.Name | ||||||
|  | 		m.Devices = append(m.Devices, r) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for _, r := range metrics.USWs { | 	for _, r := range metrics.Devices.USWs { | ||||||
| 		devices[r.Mac] = r.Name | 		devices[r.Mac] = r.Name | ||||||
|  | 		m.Devices = append(m.Devices, r) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for _, r := range metrics.UDMs { | 	for _, r := range metrics.Devices.UDMs { | ||||||
| 		devices[r.Mac] = r.Name | 		devices[r.Mac] = r.Name | ||||||
|  | 		m.Devices = append(m.Devices, r) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// These come blank, so set them here.
 | 	return m, devices, bssdIDs | ||||||
| 	for i, client := range metrics.Clients { |  | ||||||
| 		if devices[client.Mac] = client.Name; client.Name == "" { |  | ||||||
| 			devices[client.Mac] = client.Hostname |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 		metrics.Clients[i].Mac = RedactMacPII(metrics.Clients[i].Mac, c.HashPII) | // redactEvent attempts to mask personally identying information from log messages.
 | ||||||
| 		metrics.Clients[i].Name = RedactNamePII(metrics.Clients[i].Name, c.HashPII) | // This currently misses the "msg" value entirely and leaks PII information.
 | ||||||
| 		metrics.Clients[i].Hostname = RedactNamePII(metrics.Clients[i].Hostname, c.HashPII) | func redactEvent(e *unifi.Event, hash *bool) *unifi.Event { | ||||||
| 		metrics.Clients[i].SwName = devices[client.SwMac] | 	if !*hash { | ||||||
| 		metrics.Clients[i].ApName = devices[client.ApMac] | 		return e | ||||||
| 		metrics.Clients[i].GwName = devices[client.GwMac] |  | ||||||
| 		metrics.Clients[i].RadioDescription = bssdIDs[metrics.Clients[i].Bssid] + metrics.Clients[i].RadioProto |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for i := range metrics.ClientsDPI { | 	// metrics.Events[i].Msg <-- not sure what to do here.
 | ||||||
| 		// Name on Client DPI data also comes blank, find it based on MAC address.
 | 	e.DestIPGeo = unifi.IPGeo{} | ||||||
| 		metrics.ClientsDPI[i].Name = devices[metrics.ClientsDPI[i].MAC] | 	e.SourceIPGeo = unifi.IPGeo{} | ||||||
| 		if metrics.ClientsDPI[i].Name == "" { | 	e.Host = RedactNamePII(e.Host, hash) | ||||||
| 			metrics.ClientsDPI[i].Name = metrics.ClientsDPI[i].MAC | 	e.Hostname = RedactNamePII(e.Hostname, hash) | ||||||
| 		} | 	e.DstMAC = RedactMacPII(e.DstMAC, hash) | ||||||
|  | 	e.SrcMAC = RedactMacPII(e.SrcMAC, hash) | ||||||
| 
 | 
 | ||||||
| 		metrics.ClientsDPI[i].Name = RedactNamePII(metrics.ClientsDPI[i].Name, c.HashPII) | 	return e | ||||||
| 		metrics.ClientsDPI[i].MAC = RedactMacPII(metrics.ClientsDPI[i].MAC, c.HashPII) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if !*c.SaveSites { |  | ||||||
| 		metrics.Sites = nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return metrics |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // RedactNamePII converts a name string to an md5 hash (first 24 chars only).
 | // RedactNamePII converts a name string to an md5 hash (first 24 chars only).
 | ||||||
| // Useful for maskiing out personally identifying information.
 | // Useful for maskiing out personally identifying information.
 | ||||||
| func RedactNamePII(pii string, hash *bool) string { | func RedactNamePII(pii string, hash *bool) string { | ||||||
| 	if hash == nil || !*hash { | 	if hash == nil || !*hash || pii == "" { | ||||||
| 		return pii | 		return pii | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -203,7 +290,7 @@ func RedactNamePII(pii string, hash *bool) string { | ||||||
| // RedactMacPII converts a MAC address to an md5 hashed version (first 14 chars only).
 | // RedactMacPII converts a MAC address to an md5 hashed version (first 14 chars only).
 | ||||||
| // Useful for maskiing out personally identifying information.
 | // Useful for maskiing out personally identifying information.
 | ||||||
| func RedactMacPII(pii string, hash *bool) (output string) { | func RedactMacPII(pii string, hash *bool) (output string) { | ||||||
| 	if hash == nil || !*hash { | 	if hash == nil || !*hash || pii == "" { | ||||||
| 		return pii | 		return pii | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -215,7 +302,7 @@ func RedactMacPII(pii string, hash *bool) (output string) { | ||||||
| // getFilteredSites returns a list of sites to fetch data for.
 | // getFilteredSites returns a list of sites to fetch data for.
 | ||||||
| // Omits requested but unconfigured sites. Grabs the full list from the
 | // Omits requested but unconfigured sites. Grabs the full list from the
 | ||||||
| // controller and returns the sites provided in the config file.
 | // controller and returns the sites provided in the config file.
 | ||||||
| func (u *InputUnifi) getFilteredSites(c *Controller) (unifi.Sites, error) { | func (u *InputUnifi) getFilteredSites(c *Controller) ([]*unifi.Site, error) { | ||||||
| 	u.RLock() | 	u.RLock() | ||||||
| 	defer u.RUnlock() | 	defer u.RUnlock() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -4,7 +4,6 @@ go 1.14 | ||||||
| 
 | 
 | ||||||
| require ( | require ( | ||||||
| 	github.com/pkg/errors v0.9.1 | 	github.com/pkg/errors v0.9.1 | ||||||
| 	github.com/prometheus/procfs v0.1.2 // indirect | 	github.com/unifi-poller/poller v0.0.8-0.20200621214016-5d1ed3324a46 | ||||||
| 	github.com/unifi-poller/poller v0.0.6 | 	github.com/unifi-poller/unifi v0.0.6-0.20200625090439-421046871a37 | ||||||
| 	github.com/unifi-poller/unifi v0.0.5 |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | @ -28,8 +28,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb | ||||||
| github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | 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.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.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||||||
| github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= |  | ||||||
| github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= |  | ||||||
| github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= | 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.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.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= | ||||||
|  | @ -59,15 +57,12 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN | ||||||
| github.com/modern-go/reflect2 v1.0.1/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/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.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||||
| github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= |  | ||||||
| github.com/pkg/errors v0.8.1/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 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | ||||||
| github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | 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/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 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.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= | ||||||
| github.com/prometheus/client_golang v1.4.0 h1:YVIb/fVcOTMSqtqZWSKnHpSLBxu8DKgxq8z6RuBZwqI= |  | ||||||
| github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= |  | ||||||
| github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A= | 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_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-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= | ||||||
|  | @ -76,19 +71,14 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: | ||||||
| github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= | 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/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.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= | ||||||
| github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= |  | ||||||
| github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= | 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 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= | ||||||
| github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= | 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.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.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= | ||||||
| github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= |  | ||||||
| github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= |  | ||||||
| github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= | 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 h1:/ZKcW+ixpq2dOl4yeH4qvACNXnkiDCp5e/F5Tq07X7o= | ||||||
| github.com/prometheus/procfs v0.1.1/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= | github.com/prometheus/procfs v0.1.1/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= | ||||||
| github.com/prometheus/procfs v0.1.2 h1:DS2izEFqEVp1gPg5yvEF/YzS6Ajo8YdKRJjQKiQm59A= |  | ||||||
| github.com/prometheus/procfs v0.1.2/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= |  | ||||||
| github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= | 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/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 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= | ||||||
|  | @ -98,14 +88,25 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ | ||||||
| github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | 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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||||||
| github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | ||||||
| github.com/unifi-poller/poller v0.0.5 h1:qnofARTx0JveNc9PqGJmNUs7xsjwFqCWpS8pwDSjW78= | github.com/unifi-poller/poller v0.0.8-0.20200621084019-8e9b2f223849 h1:/xyUMrTm5Yc+Tobmmd4FCZjzhIJDPMQEmnHaAp4tTz4= | ||||||
| github.com/unifi-poller/poller v0.0.5/go.mod h1:45TyAHk+xYF4KoFKaaZyjMmSdhbq2I1pLniYWfOXdHs= | github.com/unifi-poller/poller v0.0.8-0.20200621084019-8e9b2f223849/go.mod h1:+Ppksi2wBCrByJke0B0lTutxFtKfv1zx6L1haALBrN4= | ||||||
| github.com/unifi-poller/poller v0.0.6 h1:KhOWUeYI029Nn/4NOIk/yblQ3tEd9QhS+u/8/S9ZoDs= | github.com/unifi-poller/poller v0.0.8-0.20200621091816-fd5c7abd9f4b h1:AJKt/ZIDtlEOWxwpL/a7pcrWmqdJaaNE9odNn4JSRj0= | ||||||
| github.com/unifi-poller/poller v0.0.6/go.mod h1:RkRJ4pAc2dAN8Xu9+VOumeE3BdN5QDQ3PC+jBx8hWW0= | github.com/unifi-poller/poller v0.0.8-0.20200621091816-fd5c7abd9f4b/go.mod h1:+Ppksi2wBCrByJke0B0lTutxFtKfv1zx6L1haALBrN4= | ||||||
| github.com/unifi-poller/unifi v0.0.4 h1:NDTxHTdF0MAt1y1RU8J+MSqdYlO0CEIqlrktcj3y/og= | github.com/unifi-poller/poller v0.0.8-0.20200621101255-6d0d0b288ece h1:EsyR6cKuwAKzddS4gsKDugfN+OEHCm7bhNOvEfBCWWA= | ||||||
| github.com/unifi-poller/unifi v0.0.4/go.mod h1:bTUtctrf56aapjKH+L+98eThBaVFbQXw5iNGZI0g/+E= | github.com/unifi-poller/poller v0.0.8-0.20200621101255-6d0d0b288ece/go.mod h1:+Ppksi2wBCrByJke0B0lTutxFtKfv1zx6L1haALBrN4= | ||||||
| github.com/unifi-poller/unifi v0.0.5 h1:Izeun32YxcQOeKZUXY0Sy4ltKYFuYxWGcN9JS6xkIJU= | github.com/unifi-poller/poller v0.0.8-0.20200621103717-5f3d60890ed6 h1:V19WgXwjXxGY75Mn8Hc5Whl3+BC71YSGatRvKVRh9pA= | ||||||
| github.com/unifi-poller/unifi v0.0.5/go.mod h1:L1kMRH2buZhB31vZnRC1im7Tk/4uD3ET4biwl2faYy8= | 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-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | 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/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | ||||||
|  | @ -118,8 +119,6 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r | ||||||
| golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/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-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-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||||
| golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= |  | ||||||
| golang.org/x/net v0.0.0-20200202094626-16171245cfb2/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 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= | ||||||
| golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= | 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/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | ||||||
|  | @ -134,9 +133,6 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h | ||||||
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-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-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |  | ||||||
| golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0= |  | ||||||
| golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |  | ||||||
| golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/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-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 h1:bGb80FudwxpeucJUjPYJXuJ8Hk91vNtfvrymzwiei38= | ||||||
|  | @ -174,8 +170,6 @@ 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.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.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.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||||
| gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= |  | ||||||
| gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |  | ||||||
| gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= | ||||||
| gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | 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-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||||||
|  |  | ||||||
|  | @ -3,10 +3,9 @@ | ||||||
| package inputunifi | package inputunifi | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"fmt" |  | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"os" |  | ||||||
| 	"strings" | 	"strings" | ||||||
|  | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"sync" | 	"sync" | ||||||
| 
 | 
 | ||||||
|  | @ -16,6 +15,7 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
|  | 	PluginName  = "unifi" // PluginName is the name of this input plugin.
 | ||||||
| 	defaultURL  = "https://127.0.0.1:8443" | 	defaultURL  = "https://127.0.0.1:8443" | ||||||
| 	defaultUser = "unifipoller" | 	defaultUser = "unifipoller" | ||||||
| 	defaultPass = "unifipoller" | 	defaultPass = "unifipoller" | ||||||
|  | @ -34,6 +34,9 @@ type InputUnifi struct { | ||||||
| // Each polled controller may have its own configuration.
 | // Each polled controller may have its own configuration.
 | ||||||
| type Controller struct { | type Controller struct { | ||||||
| 	VerifySSL  *bool        `json:"verify_ssl" toml:"verify_ssl" xml:"verify_ssl" yaml:"verify_ssl"` | 	VerifySSL  *bool        `json:"verify_ssl" toml:"verify_ssl" xml:"verify_ssl" yaml:"verify_ssl"` | ||||||
|  | 	SaveAnomal *bool        `json:"save_anomalies" toml:"save_anomalies" xml:"save_anomalies" yaml:"save_anomalies"` | ||||||
|  | 	SaveAlarms *bool        `json:"save_alarms" toml:"save_alarms" xml:"save_alarms" yaml:"save_alarms"` | ||||||
|  | 	SaveEvents *bool        `json:"save_events" toml:"save_events" xml:"save_events" yaml:"save_events"` | ||||||
| 	SaveIDS    *bool        `json:"save_ids" toml:"save_ids" xml:"save_ids" yaml:"save_ids"` | 	SaveIDS    *bool        `json:"save_ids" toml:"save_ids" xml:"save_ids" yaml:"save_ids"` | ||||||
| 	SaveDPI    *bool        `json:"save_dpi" toml:"save_dpi" xml:"save_dpi" yaml:"save_dpi"` | 	SaveDPI    *bool        `json:"save_dpi" toml:"save_dpi" xml:"save_dpi" yaml:"save_dpi"` | ||||||
| 	HashPII    *bool        `json:"hash_pii" toml:"hash_pii" xml:"hash_pii" yaml:"hash_pii"` | 	HashPII    *bool        `json:"hash_pii" toml:"hash_pii" xml:"hash_pii" yaml:"hash_pii"` | ||||||
|  | @ -54,11 +57,22 @@ type Config struct { | ||||||
| 	Controllers  []*Controller `json:"controllers" toml:"controller" xml:"controller" yaml:"controllers"` | 	Controllers  []*Controller `json:"controllers" toml:"controller" xml:"controller" yaml:"controllers"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | type Metrics struct { | ||||||
|  | 	TS         time.Time | ||||||
|  | 	Sites      []*unifi.Site | ||||||
|  | 	Clients    []*unifi.Client | ||||||
|  | 	SitesDPI   []*unifi.DPITable | ||||||
|  | 	ClientsDPI []*unifi.DPITable | ||||||
|  | 	Devices    *unifi.Devices | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func init() { // nolint: gochecknoinits
 | func init() { // nolint: gochecknoinits
 | ||||||
| 	u := &InputUnifi{} | 	u := &InputUnifi{ | ||||||
|  | 		dynamic: make(map[string]*Controller), | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	poller.NewInput(&poller.InputPlugin{ | 	poller.NewInput(&poller.InputPlugin{ | ||||||
| 		Name:   "unifi", | 		Name:   PluginName, | ||||||
| 		Input:  u, // this library implements poller.Input interface for Metrics().
 | 		Input:  u, // this library implements poller.Input interface for Metrics().
 | ||||||
| 		Config: u, // Defines our config data interface.
 | 		Config: u, // Defines our config data interface.
 | ||||||
| 	}) | 	}) | ||||||
|  | @ -143,24 +157,6 @@ FIRST: | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (u *InputUnifi) dumpSitesJSON(c *Controller, path, name string, sites unifi.Sites) ([]byte, error) { |  | ||||||
| 	allJSON := []byte{} |  | ||||||
| 
 |  | ||||||
| 	for _, s := range sites { |  | ||||||
| 		apiPath := fmt.Sprintf(path, s.Name) |  | ||||||
| 		_, _ = fmt.Fprintf(os.Stderr, "[INFO] Dumping %s: '%s' JSON for site: %s (%s):\n", name, apiPath, s.Desc, s.Name) |  | ||||||
| 
 |  | ||||||
| 		body, err := c.Unifi.GetJSON(apiPath) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return allJSON, err |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		allJSON = append(allJSON, body...) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return allJSON, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (u *InputUnifi) getPassFromFile(filename string) string { | func (u *InputUnifi) getPassFromFile(filename string) string { | ||||||
| 	b, err := ioutil.ReadFile(filename) | 	b, err := ioutil.ReadFile(filename) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | @ -196,6 +192,18 @@ func (u *InputUnifi) setDefaults(c *Controller) { | ||||||
| 		c.SaveIDS = &f | 		c.SaveIDS = &f | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if c.SaveEvents == nil { | ||||||
|  | 		c.SaveEvents = &f | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if c.SaveAlarms == nil { | ||||||
|  | 		c.SaveAlarms = &f | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if c.SaveAnomal == nil { | ||||||
|  | 		c.SaveAnomal = &f | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if c.URL == "" { | 	if c.URL == "" { | ||||||
| 		c.URL = defaultURL | 		c.URL = defaultURL | ||||||
| 	} | 	} | ||||||
|  | @ -241,6 +249,18 @@ func (u *InputUnifi) setControllerDefaults(c *Controller) *Controller { | ||||||
| 		c.SaveIDS = u.Default.SaveIDS | 		c.SaveIDS = u.Default.SaveIDS | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if c.SaveEvents == nil { | ||||||
|  | 		c.SaveEvents = u.Default.SaveEvents | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if c.SaveAlarms == nil { | ||||||
|  | 		c.SaveAlarms = u.Default.SaveAlarms | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if c.SaveAnomal == nil { | ||||||
|  | 		c.SaveAnomal = u.Default.SaveAnomal | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if c.URL == "" { | 	if c.URL == "" { | ||||||
| 		c.URL = u.Default.URL | 		c.URL = u.Default.URL | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -4,7 +4,6 @@ package inputunifi | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"os" |  | ||||||
| 	"strings" | 	"strings" | ||||||
| 
 | 
 | ||||||
| 	"github.com/pkg/errors" | 	"github.com/pkg/errors" | ||||||
|  | @ -25,8 +24,8 @@ func (u *InputUnifi) Initialize(l poller.Logger) error { | ||||||
| 		u.Config = &Config{Disable: true} | 		u.Config = &Config{Disable: true} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if u.Disable { | 	if u.Logger = l; u.Disable { | ||||||
| 		l.Logf("UniFi input plugin disabled or missing configuration!") | 		u.Logf("UniFi input plugin disabled or missing configuration!") | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -35,12 +34,10 @@ func (u *InputUnifi) Initialize(l poller.Logger) error { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if len(u.Controllers) == 0 { | 	if len(u.Controllers) == 0 { | ||||||
| 		l.Logf("No controllers configured. Polling dynamic controllers only!") | 		u.Logf("No controllers configured. Polling dynamic controllers only! Defaults:") | ||||||
|  | 		u.logController(&u.Default) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	u.dynamic = make(map[string]*Controller) |  | ||||||
| 	u.Logger = l |  | ||||||
| 
 |  | ||||||
| 	for i, c := range u.Controllers { | 	for i, c := range u.Controllers { | ||||||
| 		switch err := u.getUnifi(u.setControllerDefaults(c)); err { | 		switch err := u.getUnifi(u.setControllerDefaults(c)); err { | ||||||
| 		case nil: | 		case nil: | ||||||
|  | @ -48,9 +45,9 @@ func (u *InputUnifi) Initialize(l poller.Logger) error { | ||||||
| 				u.LogErrorf("checking sites on %s: %v", c.URL, err) | 				u.LogErrorf("checking sites on %s: %v", c.URL, err) | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			u.Logf("Configured UniFi Controller %d:", i+1) | 			u.Logf("Configured UniFi Controller %d of %d:", i+1, len(u.Controllers)) | ||||||
| 		default: | 		default: | ||||||
| 			u.LogErrorf("Controller %d Auth or Connection Error, retrying: %v", i+1, err) | 			u.LogErrorf("Controller %d of %d Auth or Connection Error, retrying: %v", i+1, len(u.Controllers), err) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		u.logController(c) | 		u.logController(c) | ||||||
|  | @ -60,62 +57,91 @@ func (u *InputUnifi) Initialize(l poller.Logger) error { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (u *InputUnifi) logController(c *Controller) { | func (u *InputUnifi) logController(c *Controller) { | ||||||
| 	u.Logf("   => URL: %s", c.URL) | 	u.Logf("   => URL: %s (verify SSL: %v)", c.URL, *c.VerifySSL) | ||||||
| 
 | 
 | ||||||
| 	if c.Unifi != nil { | 	if c.Unifi != nil { | ||||||
| 		u.Logf("   => Version: %s", c.Unifi.ServerVersion) | 		u.Logf("   => Version: %s (%s)", c.Unifi.ServerVersion, c.Unifi.UUID) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	u.Logf("   => Username: %s (has password: %v)", c.User, c.Pass != "") | 	u.Logf("   => Username: %s (has password: %v)", c.User, c.Pass != "") | ||||||
| 	u.Logf("   => Hash PII: %v", *c.HashPII) | 	u.Logf("   => Hash PII / Poll Sites: %v / %s", *c.HashPII, strings.Join(c.Sites, ", ")) | ||||||
| 	u.Logf("   => Verify SSL: %v", *c.VerifySSL) | 	u.Logf("   => Save Sites / Save DPI: %v / %v (metrics)", *c.SaveSites, *c.SaveDPI) | ||||||
| 	u.Logf("   => Save DPI: %v", *c.SaveDPI) | 	u.Logf("   => Save Events / Save IDS: %v / %v (logs)", *c.SaveEvents, *c.SaveIDS) | ||||||
| 	u.Logf("   => Save IDS: %v", *c.SaveIDS) | 	u.Logf("   => Save Alarms / Anomalies: %v / %v (logs)", *c.SaveAlarms, *c.SaveAnomal) | ||||||
| 	u.Logf("   => Save Sites: %v", *c.SaveSites) | } | ||||||
|  | 
 | ||||||
|  | // Events allows you to pull only events (and IDS) from the UniFi Controller.
 | ||||||
|  | // This does not fully respect HashPII, but it may in the future!
 | ||||||
|  | // Use Filter.Path to pick a specific controller, otherwise poll them all!
 | ||||||
|  | func (u *InputUnifi) Events(filter *poller.Filter) (*poller.Events, error) { | ||||||
|  | 	if u.Disable { | ||||||
|  | 		return nil, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	logs := []interface{}{} | ||||||
|  | 
 | ||||||
|  | 	if filter == nil { | ||||||
|  | 		filter = &poller.Filter{} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, c := range u.Controllers { | ||||||
|  | 		if filter.Path != "" && !strings.EqualFold(c.URL, filter.Path) { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		events, err := u.collectControllerEvents(c) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		logs = append(logs, events...) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return &poller.Events{Logs: logs}, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Metrics grabs all the measurements from a UniFi controller and returns them.
 | // Metrics grabs all the measurements from a UniFi controller and returns them.
 | ||||||
| func (u *InputUnifi) Metrics() (*poller.Metrics, bool, error) { | // Set Filter.Path to a controller URL for a specific controller (or get them all).
 | ||||||
| 	return u.MetricsFrom(nil) | func (u *InputUnifi) Metrics(filter *poller.Filter) (*poller.Metrics, error) { | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // MetricsFrom grabs all the measurements from a UniFi controller and returns them.
 |  | ||||||
| func (u *InputUnifi) MetricsFrom(filter *poller.Filter) (*poller.Metrics, bool, error) { |  | ||||||
| 	if u.Disable { | 	if u.Disable { | ||||||
| 		return nil, false, nil | 		return nil, nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	metrics := &poller.Metrics{} | 	metrics := &poller.Metrics{} | ||||||
| 
 | 
 | ||||||
|  | 	if filter == nil { | ||||||
|  | 		filter = &poller.Filter{} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// Check if the request is for an existing, configured controller (or all controllers)
 | 	// Check if the request is for an existing, configured controller (or all controllers)
 | ||||||
| 	for _, c := range u.Controllers { | 	for _, c := range u.Controllers { | ||||||
| 		if filter != nil && !strings.EqualFold(c.URL, filter.Path) { | 		if filter.Path != "" && !strings.EqualFold(c.URL, filter.Path) { | ||||||
|  | 			// continue only if we have a filter path and it doesn't match.
 | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		m, err := u.collectController(c) | 		m, err := u.collectController(c) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return metrics, false, err | 			return metrics, err | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		metrics = poller.AppendMetrics(metrics, m) | 		metrics = poller.AppendMetrics(metrics, m) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if filter == nil || len(metrics.Clients) != 0 { | 	if filter.Path == "" || len(metrics.Clients) != 0 { | ||||||
| 		return metrics, true, nil | 		return metrics, nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if !u.Dynamic { | 	if !u.Dynamic { | ||||||
| 		return nil, false, errDynamicLookupsDisabled | 		return nil, errDynamicLookupsDisabled | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Attempt a dynamic metrics fetch from an unconfigured controller.
 | 	// Attempt a dynamic metrics fetch from an unconfigured controller.
 | ||||||
| 	m, err := u.dynamicController(filter.Path) | 	return u.dynamicController(filter) | ||||||
| 
 |  | ||||||
| 	return m, err == nil && m != nil, err |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // RawMetrics returns API output from the first configured unifi controller.
 | // RawMetrics returns API output from the first configured UniFi controller.
 | ||||||
|  | // Adjust filter.Unit to pull from a controller other than the first.
 | ||||||
| func (u *InputUnifi) RawMetrics(filter *poller.Filter) ([]byte, error) { | func (u *InputUnifi) RawMetrics(filter *poller.Filter) ([]byte, error) { | ||||||
| 	if l := len(u.Controllers); filter.Unit >= l { | 	if l := len(u.Controllers); filter.Unit >= l { | ||||||
| 		return nil, errors.Wrapf(errControllerNumNotFound, "%d controller(s) configured, '%d'", l, filter.Unit) | 		return nil, errors.Wrapf(errControllerNumNotFound, "%d controller(s) configured, '%d'", l, filter.Unit) | ||||||
|  | @ -141,13 +167,30 @@ func (u *InputUnifi) RawMetrics(filter *poller.Filter) ([]byte, error) { | ||||||
| 
 | 
 | ||||||
| 	switch filter.Kind { | 	switch filter.Kind { | ||||||
| 	case "d", "device", "devices": | 	case "d", "device", "devices": | ||||||
| 		return u.dumpSitesJSON(c, unifi.APIDevicePath, "Devices", sites) | 		return u.getSitesJSON(c, unifi.APIDevicePath, sites) | ||||||
| 	case "client", "clients", "c": | 	case "client", "clients", "c": | ||||||
| 		return u.dumpSitesJSON(c, unifi.APIClientPath, "Clients", sites) | 		return u.getSitesJSON(c, unifi.APIClientPath, sites) | ||||||
| 	case "other", "o": | 	case "other", "o": | ||||||
| 		_, _ = fmt.Fprintf(os.Stderr, "[INFO] Dumping Path '%s':\n", filter.Path) |  | ||||||
| 		return c.Unifi.GetJSON(filter.Path) | 		return c.Unifi.GetJSON(filter.Path) | ||||||
| 	default: | 	default: | ||||||
| 		return []byte{}, errNoFilterKindProvided | 		return []byte{}, errNoFilterKindProvided | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (u *InputUnifi) getSitesJSON(c *Controller, path string, sites []*unifi.Site) ([]byte, error) { | ||||||
|  | 	allJSON := []byte{} | ||||||
|  | 
 | ||||||
|  | 	for _, s := range sites { | ||||||
|  | 		apiPath := fmt.Sprintf(path, s.Name) | ||||||
|  | 		u.LogDebugf("Returning Path '%s' for site: %s (%s):\n", apiPath, s.Desc, s.Name) | ||||||
|  | 
 | ||||||
|  | 		body, err := c.Unifi.GetJSON(apiPath) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return allJSON, err | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		allJSON = append(allJSON, body...) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return allJSON, nil | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue