diff --git a/core/unifi/clients_influx.go b/core/unifi/clients_influx.go index 194f3fa4..29f76f03 100644 --- a/core/unifi/clients_influx.go +++ b/core/unifi/clients_influx.go @@ -8,14 +8,14 @@ import ( // Points generates Unifi Client datapoints for InfluxDB. // These points can be passed directly to influx. -func (c Client) Points() ([]*influx.Point, error) { +func (c *Client) Points() ([]*influx.Point, error) { return c.PointsAt(time.Now()) } // PointsAt generates Unifi Client datapoints for InfluxDB. // These points can be passed directly to influx. // This is just like Points(), but specify when points were created. -func (c Client) PointsAt(now time.Time) ([]*influx.Point, error) { +func (c *Client) PointsAt(now time.Time) ([]*influx.Point, error) { tags := map[string]string{ "id": c.ID, "mac": c.Mac, diff --git a/core/unifi/clients_type.go b/core/unifi/clients_type.go index 1004f1ce..3d37b30c 100644 --- a/core/unifi/clients_type.go +++ b/core/unifi/clients_type.go @@ -1,7 +1,7 @@ package unifi // Clients contains a list that contains all of the unifi clients from a controller. -type Clients []Client +type Clients []*Client // Client defines all the data a connected-network client contains. type Client struct { diff --git a/core/unifi/devices.go b/core/unifi/devices.go index 072cf31e..4f9829e6 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -17,20 +17,20 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { // Choose which type to unmarshal into based on the "type" json key. switch assetType { // Unmarshal again into the correct type.. case "uap": - dev := UAP{SiteName: siteName} - if u.unmarshalDevice(assetType, r, &dev) == nil { + dev := &UAP{SiteName: siteName} + if u.unmarshalDevice(assetType, r, dev) == nil { dev.Name = pick(dev.Name, dev.Mac) devices.UAPs = append(devices.UAPs, dev) } case "ugw", "usg": // in case they ever fix the name in the api. - dev := USG{SiteName: siteName} - if u.unmarshalDevice(assetType, r, &dev) == nil { + dev := &USG{SiteName: siteName} + if u.unmarshalDevice(assetType, r, dev) == nil { dev.Name = pick(dev.Name, dev.Mac) devices.USGs = append(devices.USGs, dev) } case "usw": - dev := USW{SiteName: siteName} - if u.unmarshalDevice(assetType, r, &dev) == nil { + dev := &USW{SiteName: siteName} + if u.unmarshalDevice(assetType, r, dev) == nil { dev.Name = pick(dev.Name, dev.Mac) devices.USWs = append(devices.USWs, dev) } diff --git a/core/unifi/ids.go b/core/unifi/ids.go index 47da5aa2..634644a6 100644 --- a/core/unifi/ids.go +++ b/core/unifi/ids.go @@ -12,7 +12,7 @@ import ( ) // IDSList contains a list that contains all of the IDS Events on a controller. -type IDSList []IDS +type IDSList []*IDS // IDS holds an Intrusion Prevention System Event. type IDS struct { @@ -87,8 +87,8 @@ type IDS struct { // GetIDS returns Intrusion Detection Systems events. // Returns all events that happened in site between from and to. -func (u *Unifi) GetIDS(sites []Site, from, to time.Time) ([]IDS, error) { - data := []IDS{} +func (u *Unifi) GetIDS(sites Sites, from, to time.Time) ([]*IDS, error) { + data := []*IDS{} for _, site := range sites { u.DebugLog("Polling Controller for IDS/IPS Data, site %s (%s) ", site.Name, site.Desc) ids, err := u.GetSiteIDS(site, from, to) @@ -102,9 +102,9 @@ func (u *Unifi) GetIDS(sites []Site, from, to time.Time) ([]IDS, error) { // GetSiteIDS is a helper to offload the for-loop work. // This method retreives the Intrusion Detection System Data for 1 Site. -func (u *Unifi) GetSiteIDS(site Site, from, to time.Time) ([]IDS, error) { +func (u *Unifi) GetSiteIDS(site *Site, from, to time.Time) ([]*IDS, error) { var response struct { - Data []IDS `json:"data"` + Data []*IDS `json:"data"` } URIpath := fmt.Sprintf(IPSEvents, site.Name) params := fmt.Sprintf(`{"start":"%v000","end":"%v000","_limit":50000}`, from.Unix(), to.Unix()) @@ -139,13 +139,13 @@ func (u *Unifi) GetSiteIDS(site Site, from, to time.Time) ([]IDS, error) { // These events have a timestamp, so that is used instead of any passed-in value. // This method generates intrusion detection datapoints for InfluxDB. // These points can be passed directly to influx. -func (i IDS) PointsAt(now time.Time) ([]*influx.Point, error) { +func (i *IDS) PointsAt(now time.Time) ([]*influx.Point, error) { return i.Points() } // Points generates intrusion detection datapoints for InfluxDB. // These points can be passed directly to influx. -func (i IDS) Points() ([]*influx.Point, error) { +func (i *IDS) Points() ([]*influx.Point, error) { tags := map[string]string{ "in_iface": i.InIface, "event_type": i.EventType, diff --git a/core/unifi/site_influx.go b/core/unifi/site_influx.go index 82dc53fd..ac6f8045 100644 --- a/core/unifi/site_influx.go +++ b/core/unifi/site_influx.go @@ -9,14 +9,14 @@ import ( // Points generates Unifi Sites' datapoints for InfluxDB. // These points can be passed directly to influx. -func (u Site) Points() ([]*influx.Point, error) { +func (u *Site) Points() ([]*influx.Point, error) { return u.PointsAt(time.Now()) } // PointsAt generates Unifi Sites' datapoints for InfluxDB. // These points can be passed directly to influx. // This is just like Points(), but specify when points were created. -func (u Site) PointsAt(now time.Time) ([]*influx.Point, error) { +func (u *Site) PointsAt(now time.Time) ([]*influx.Point, error) { points := []*influx.Point{} for _, s := range u.Health { tags := map[string]string{ diff --git a/core/unifi/site_type.go b/core/unifi/site_type.go index fd695457..08213757 100644 --- a/core/unifi/site_type.go +++ b/core/unifi/site_type.go @@ -1,7 +1,7 @@ package unifi // Sites is a struct to match Devices and Clients. -type Sites []Site +type Sites []*Site // Site represents a site's data. type Site struct { diff --git a/core/unifi/types.go b/core/unifi/types.go index 6b2e6f55..64dccd9a 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -42,9 +42,9 @@ func DiscardLogs(msg string, v ...interface{}) { // Devices contains a list of all the unifi devices from a controller. // Contains Access points, security gateways and switches. type Devices struct { - UAPs []UAP - USGs []USG - USWs []USW + UAPs []*UAP + USGs []*USG + USWs []*USW } // Unifi is what you get in return for providing a password! Unifi represents diff --git a/core/unifi/uap_influx.go b/core/unifi/uap_influx.go index 6ed3ec1a..44d721a0 100644 --- a/core/unifi/uap_influx.go +++ b/core/unifi/uap_influx.go @@ -8,14 +8,18 @@ import ( // Points generates Wireless-Access-Point datapoints for InfluxDB. // These points can be passed directly to influx. -func (u UAP) Points() ([]*influx.Point, error) { +func (u *UAP) Points() ([]*influx.Point, error) { return u.PointsAt(time.Now()) } // PointsAt generates Wireless-Access-Point datapoints for InfluxDB. // These points can be passed directly to influx. // This is just like Points(), but specify when points were created. -func (u UAP) PointsAt(now time.Time) ([]*influx.Point, error) { +func (u *UAP) PointsAt(now time.Time) ([]*influx.Point, error) { + if u.Stat.ap == nil { + // Disabled devices lack stats. + u.Stat.ap = &ap{} + } tags := map[string]string{ "id": u.ID, "mac": u.Mac, diff --git a/core/unifi/uap_influx_test.go b/core/unifi/uap_influx_test.go new file mode 100644 index 00000000..7f03f20f --- /dev/null +++ b/core/unifi/uap_influx_test.go @@ -0,0 +1,18 @@ +package unifi + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestUAPPoints(t *testing.T) { + t.Parallel() + a := assert.New(t) + // We're just making sure an empty dataset does not crash the method. + // https://github.com/davidnewhall/unifi-poller/issues/82 + u := &UAP{} + pts, err := u.Points() + a.Nil(err) + a.NotNil(pts) +} diff --git a/core/unifi/uap_type.go b/core/unifi/uap_type.go index 7858a1f8..538f09f4 100644 --- a/core/unifi/uap_type.go +++ b/core/unifi/uap_type.go @@ -308,7 +308,7 @@ type UAP struct { UplinkMac string `json:"uplink_mac"` UplinkRemotePort int `json:"uplink_remote_port"` } `json:"last_uplink"` - Stat *UAPStat `json:"stat"` + Stat UAPStat `json:"stat"` TxBytes FlexInt `json:"tx_bytes"` RxBytes FlexInt `json:"rx_bytes"` Bytes FlexInt `json:"bytes"` diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 8d985f21..3404c55c 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -71,11 +71,11 @@ func (u *Unifi) getServer() error { } // GetClients returns a response full of clients' data from the UniFi Controller. -func (u *Unifi) GetClients(sites []Site) (Clients, error) { - data := make([]Client, 0) +func (u *Unifi) GetClients(sites Sites) (Clients, error) { + data := make([]*Client, 0) for _, site := range sites { var response struct { - Data []Client `json:"data"` + Data []*Client `json:"data"` } u.DebugLog("Polling Controller, retreiving UniFi Clients, site %s (%s) ", site.Name, site.Desc) clientPath := fmt.Sprintf(ClientPath, site.Name) @@ -95,7 +95,7 @@ func (u *Unifi) GetClients(sites []Site) (Clients, error) { } // GetDevices returns a response full of devices' data from the UniFi Controller. -func (u *Unifi) GetDevices(sites []Site) (*Devices, error) { +func (u *Unifi) GetDevices(sites Sites) (*Devices, error) { devices := new(Devices) for _, site := range sites { var response struct { @@ -116,7 +116,7 @@ func (u *Unifi) GetDevices(sites []Site) (*Devices, error) { // GetSites returns a list of configured sites on the UniFi controller. func (u *Unifi) GetSites() (Sites, error) { var response struct { - Data []Site `json:"data"` + Data []*Site `json:"data"` } if err := u.GetData(SiteList, &response); err != nil { return nil, err diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index a989804e..5f766539 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -9,14 +9,14 @@ import ( // Points generates Unifi Gateway datapoints for InfluxDB. // These points can be passed directly to influx. -func (u USG) Points() ([]*influx.Point, error) { +func (u *USG) Points() ([]*influx.Point, error) { return u.PointsAt(time.Now()) } // PointsAt generates Unifi Gateway datapoints for InfluxDB. // These points can be passed directly to influx. // This is just like Points(), but specify when points were created. -func (u USG) PointsAt(now time.Time) ([]*influx.Point, error) { +func (u *USG) PointsAt(now time.Time) ([]*influx.Point, error) { tags := map[string]string{ "id": u.ID, "mac": u.Mac, diff --git a/core/unifi/usw_influx.go b/core/unifi/usw_influx.go index 1dee7de9..8a745d26 100644 --- a/core/unifi/usw_influx.go +++ b/core/unifi/usw_influx.go @@ -8,14 +8,14 @@ import ( // Points generates Unifi Switch datapoints for InfluxDB. // These points can be passed directly to influx. -func (u USW) Points() ([]*influx.Point, error) { +func (u *USW) Points() ([]*influx.Point, error) { return u.PointsAt(time.Now()) } // PointsAt generates Unifi Switch datapoints for InfluxDB. // These points can be passed directly to influx. // This is just like Points(), but specify when points were created. -func (u USW) PointsAt(now time.Time) ([]*influx.Point, error) { +func (u *USW) PointsAt(now time.Time) ([]*influx.Point, error) { tags := map[string]string{ "id": u.ID, "mac": u.Mac,