From d2862befc037b1de70cb490ce623fbb2daf8f32a Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 26 Jan 2019 04:15:41 -0800 Subject: [PATCH] Rename a few pieces. --- core/unifi/clients.go | 167 +++++++++++++++++++------------------- core/unifi/uap.go | 5 +- core/unifi/uap_type.go | 2 +- core/unifi/unidev.go | 56 ++++++++----- core/unifi/unidev_test.go | 4 +- core/unifi/unifi.go | 40 ++++----- core/unifi/usg.go | 5 +- core/unifi/usg_type.go | 2 +- core/unifi/usw.go | 5 +- core/unifi/usw_type.go | 2 +- 10 files changed, 147 insertions(+), 141 deletions(-) diff --git a/core/unifi/clients.go b/core/unifi/clients.go index 2b98ece8..1a87c9cd 100644 --- a/core/unifi/clients.go +++ b/core/unifi/clients.go @@ -7,95 +7,96 @@ import ( influx "github.com/influxdata/influxdb/client/v2" ) -// Points generates a client's datapoints for InfluxDB. -func (u UCL) Points() ([]*influx.Point, error) { +// Points generates Unifi Client datapoints for InfluxDB. +// These points can be passed directly to influx. +func (c *UCL) Points() ([]*influx.Point, error) { var points []*influx.Point // Fix name and hostname fields. Sometimes one or the other is blank. - if u.Name == "" && u.Hostname != "" { - u.Name = u.Hostname - } else if u.Hostname == "" && u.Name != "" { - u.Hostname = u.Name - } else if u.Hostname == "" && u.Name == "" { - u.Hostname = "-no-name-" - u.Name = "-no-name-" + if c.Name == "" && c.Hostname != "" { + c.Name = c.Hostname + } else if c.Hostname == "" && c.Name != "" { + c.Hostname = c.Name + } else if c.Hostname == "" && c.Name == "" { + c.Hostname = "-no-name-" + c.Name = "-no-name-" } tags := map[string]string{ - "id": u.ID, - "mac": u.Mac, - "user_id": u.UserID, - "site_id": u.SiteID, - "network_id": u.NetworkID, - "usergroup_id": u.UserGroupID, - "ap_mac": u.ApMac, - "gw_mac": u.GwMac, - "sw_mac": u.SwMac, - "oui": u.Oui, - "radio_name": u.RadioName, - "radio": u.Radio, - "radio_proto": u.RadioProto, - "name": u.Name, - "fixed_ip": u.FixedIP, - "sw_port": strconv.Itoa(u.SwPort), - "os_class": strconv.Itoa(u.OsClass), - "os_name": strconv.Itoa(u.OsName), - "dev_cat": strconv.Itoa(u.DevCat), - "dev_id": strconv.Itoa(u.DevID), - "dev_family": strconv.Itoa(u.DevFamily), - "authorized": strconv.FormatBool(u.Authorized), - "is_11r": strconv.FormatBool(u.Is11R), - "is_wired": strconv.FormatBool(u.IsWired), - "is_guest": strconv.FormatBool(u.IsGuest), - "is_guest_by_uap": strconv.FormatBool(u.IsGuestByUAP), - "is_guest_by_ugw": strconv.FormatBool(u.IsGuestByUGW), - "is_guest_by_usw": strconv.FormatBool(u.IsGuestByUSW), - "noted": strconv.FormatBool(u.Noted), - "powersave_enabled": strconv.FormatBool(u.PowersaveEnabled), - "qos_policy_applied": strconv.FormatBool(u.QosPolicyApplied), - "use_fixedip": strconv.FormatBool(u.UseFixedIP), - "channel": strconv.Itoa(u.Channel), - "vlan": strconv.Itoa(u.Vlan), + "id": c.ID, + "mac": c.Mac, + "user_id": c.UserID, + "site_id": c.SiteID, + "network_id": c.NetworkID, + "usergroup_id": c.UserGroupID, + "ap_mac": c.ApMac, + "gw_mac": c.GwMac, + "sw_mac": c.SwMac, + "oui": c.Oui, + "radio_name": c.RadioName, + "radio": c.Radio, + "radio_proto": c.RadioProto, + "name": c.Name, + "fixed_ip": c.FixedIP, + "sw_port": strconv.Itoa(c.SwPort), + "os_class": strconv.Itoa(c.OsClass), + "os_name": strconv.Itoa(c.OsName), + "dev_cat": strconv.Itoa(c.DevCat), + "dev_id": strconv.Itoa(c.DevID), + "dev_family": strconv.Itoa(c.DevFamily), + "authorized": strconv.FormatBool(c.Authorized), + "is_11r": strconv.FormatBool(c.Is11R), + "is_wired": strconv.FormatBool(c.IsWired), + "is_guest": strconv.FormatBool(c.IsGuest), + "is_guest_by_uap": strconv.FormatBool(c.IsGuestByUAP), + "is_guest_by_ugw": strconv.FormatBool(c.IsGuestByUGW), + "is_guest_by_usw": strconv.FormatBool(c.IsGuestByUSW), + "noted": strconv.FormatBool(c.Noted), + "powersave_enabled": strconv.FormatBool(c.PowersaveEnabled), + "qos_policy_applied": strconv.FormatBool(c.QosPolicyApplied), + "use_fixedip": strconv.FormatBool(c.UseFixedIP), + "channel": strconv.Itoa(c.Channel), + "vlan": strconv.Itoa(c.Vlan), } fields := map[string]interface{}{ - "ip": u.IP, - "essid": u.Essid, - "bssid": u.Bssid, - "hostname": u.Hostname, - "dpi_stats_last_updated": u.DpiStatsLastUpdated, - "last_seen_by_uap": u.LastSeenByUAP, - "last_seen_by_ugw": u.LastSeenByUGW, - "last_seen_by_usw": u.LastSeenByUSW, - "uptime_by_uap": u.UptimeByUAP, - "uptime_by_ugw": u.UptimeByUGW, - "uptime_by_usw": u.UptimeByUSW, - "assoc_time": u.AssocTime, - "bytes_r": u.BytesR, - "ccq": u.Ccq, - "first_seen": u.FirstSeen, - "idle_time": u.IdleTime, - "last_seen": u.LastSeen, - "latest_assoc_time": u.LatestAssocTime, - "network": u.Network, - "noise": u.Noise, - "note": u.Note, - "roam_count": u.RoamCount, - "rssi": u.Rssi, - "rx_bytes": u.RxBytes, - "rx_bytes_r": u.RxBytesR, - "rx_packets": u.RxPackets, - "rx_rate": u.RxRate, - "signal": u.Signal, - "tx_bytes": u.TxBytes, - "tx_bytes_r": u.TxBytesR, - "tx_packets": u.TxPackets, - "tx_power": u.TxPower, - "tx_rate": u.TxRate, - "uptime": u.Uptime, - "wired-rx_bytes": u.WiredRxBytes, - "wired-rx_bytes-r": u.WiredRxBytesR, - "wired-rx_packets": u.WiredRxPackets, - "wired-tx_bytes": u.WiredTxBytes, - "wired-tx_bytes-r": u.WiredTxBytesR, - "wired-tx_packets": u.WiredTxPackets, + "ip": c.IP, + "essid": c.Essid, + "bssid": c.Bssid, + "hostname": c.Hostname, + "dpi_stats_last_updated": c.DpiStatsLastUpdated, + "last_seen_by_uap": c.LastSeenByUAP, + "last_seen_by_ugw": c.LastSeenByUGW, + "last_seen_by_usw": c.LastSeenByUSW, + "uptime_by_uap": c.UptimeByUAP, + "uptime_by_ugw": c.UptimeByUGW, + "uptime_by_usw": c.UptimeByUSW, + "assoc_time": c.AssocTime, + "bytes_r": c.BytesR, + "ccq": c.Ccq, + "first_seen": c.FirstSeen, + "idle_time": c.IdleTime, + "last_seen": c.LastSeen, + "latest_assoc_time": c.LatestAssocTime, + "network": c.Network, + "noise": c.Noise, + "note": c.Note, + "roam_count": c.RoamCount, + "rssi": c.Rssi, + "rx_bytes": c.RxBytes, + "rx_bytes_r": c.RxBytesR, + "rx_packets": c.RxPackets, + "rx_rate": c.RxRate, + "signal": c.Signal, + "tx_bytes": c.TxBytes, + "tx_bytes_r": c.TxBytesR, + "tx_packets": c.TxPackets, + "tx_power": c.TxPower, + "tx_rate": c.TxRate, + "uptime": c.Uptime, + "wired-rx_bytes": c.WiredRxBytes, + "wired-rx_bytes-r": c.WiredRxBytesR, + "wired-rx_packets": c.WiredRxPackets, + "wired-tx_bytes": c.WiredTxBytes, + "wired-tx_bytes-r": c.WiredTxBytesR, + "wired-tx_packets": c.WiredTxPackets, } pt, err := influx.NewPoint("clients", tags, fields, time.Now()) if err == nil { diff --git a/core/unifi/uap.go b/core/unifi/uap.go index a35db906..6f62a107 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -7,8 +7,9 @@ import ( influx "github.com/influxdata/influxdb/client/v2" ) -// Points generates a device's datapoints for InfluxDB. -func (u UAP) Points() ([]*influx.Point, error) { +// Points generates Wireless-Access-Point datapoints for InfluxDB. +// These points can be passed directly to influx. +func (u *UAP) Points() ([]*influx.Point, error) { /* I generally suck at InfluxDB, so if I got the tags/fields wrong, please send me a PR or open an Issue to address my faults. Thanks! */ diff --git a/core/unifi/uap_type.go b/core/unifi/uap_type.go index 78506b74..2d61b324 100644 --- a/core/unifi/uap_type.go +++ b/core/unifi/uap_type.go @@ -1,6 +1,6 @@ package unifi -// UAP is a Unifi Access Point. +// UAP represents all the data from the Ubiquit Controller for a Unifi Access Point. type UAP struct { /* This was auto generated and then slowly edited by hand to get all the data types right and graphable. diff --git a/core/unifi/unidev.go b/core/unifi/unidev.go index 68b4f82a..af2bf02c 100644 --- a/core/unifi/unidev.go +++ b/core/unifi/unidev.go @@ -11,12 +11,22 @@ import ( "github.com/pkg/errors" ) +const ( + // ClientPath is Unifi Clients API Path + ClientPath = "/api/s/default/stat/sta" + // DevicePath is where we get data about Unifi devices. + DevicePath = "/api/s/default/stat/device" + // NetworkPath contains network-configuration data. Not really graphable. + NetworkPath = "/api/s/default/rest/networkconf" + // UserGroupPath contains usergroup configurations. + UserGroupPath = "/api/s/default/rest/usergroup" + // LoginPath is Unifi Controller Login API Path + LoginPath = "/api/login" +) + // Logger is a base type to deal with changing log outs. type Logger func(msg string, fmt ...interface{}) -// LoginPath is Unifi Controller Login API Path -const LoginPath = "/api/login" - // Devices contains a list of all the unifi devices from a controller. type Devices struct { UAPs []UAP @@ -24,8 +34,8 @@ type Devices struct { USWs []USW } -// AuthedReq is what you get in return for providing a password! -type AuthedReq struct { +// Unifi is what you get in return for providing a password! +type Unifi struct { *http.Client baseURL string ErrorLog Logger @@ -61,40 +71,40 @@ func (f *FlexInt) UnmarshalJSON(b []byte) error { // AuthController creates a http.Client with authenticated cookies. // Used to make additional, authenticated requests to the APIs. -func AuthController(user, pass, url string, verifySSL bool) (*AuthedReq, error) { +func AuthController(user, pass, url string, verifySSL bool) (*Unifi, error) { json := `{"username": "` + user + `","password": "` + pass + `"}` jar, err := cookiejar.New(nil) if err != nil { return nil, errors.Wrap(err, "cookiejar.New(nil)") } - a := &AuthedReq{Client: &http.Client{ + u := &Unifi{Client: &http.Client{ Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !verifySSL}}, Jar: jar, }, baseURL: url} - req, err := a.UniReq(LoginPath, json) + req, err := u.UniReq(LoginPath, json) if err != nil { - return a, errors.Wrap(err, "UniReq(LoginPath, json)") + return u, errors.Wrap(err, "UniReq(LoginPath, json)") } - resp, err := a.Do(req) + resp, err := u.Do(req) if err != nil { - return a, errors.Wrap(err, "authReq.Do(req)") + return u, errors.Wrap(err, "authReq.Do(req)") } defer func() { _ = resp.Body.Close() }() if resp.StatusCode != http.StatusOK { - return a, errors.Errorf("authentication failed (%v): %v (status: %v/%v)", + return u, errors.Errorf("authentication failed (%v): %v (status: %v/%v)", user, url+LoginPath, resp.StatusCode, resp.Status) } - return a, nil + return u, nil } // UniReq is a small helper function that adds an Accept header. -func (a AuthedReq) UniReq(apiPath string, params string) (req *http.Request, err error) { +func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err error) { if params != "" { - req, err = http.NewRequest("POST", a.baseURL+apiPath, bytes.NewBufferString(params)) + req, err = http.NewRequest("POST", u.baseURL+apiPath, bytes.NewBufferString(params)) } else { - req, err = http.NewRequest("GET", a.baseURL+apiPath, nil) + req, err = http.NewRequest("GET", u.baseURL+apiPath, nil) } if err == nil { req.Header.Add("Accept", "application/json") @@ -102,14 +112,16 @@ func (a AuthedReq) UniReq(apiPath string, params string) (req *http.Request, err return } -func (a AuthedReq) dLogf(msg string, v ...interface{}) { - if a.DebugLog != nil { - a.DebugLog("[DEBUG] "+msg, v...) +// dLogf logs a debug message. +func (u *Unifi) dLogf(msg string, v ...interface{}) { + if u.DebugLog != nil { + u.DebugLog("[DEBUG] "+msg, v...) } } -func (a AuthedReq) eLogf(msg string, v ...interface{}) { - if a.ErrorLog != nil { - a.ErrorLog("[ERROR] "+msg, v...) +// dLogf logs an error message. +func (u *Unifi) eLogf(msg string, v ...interface{}) { + if u.ErrorLog != nil { + u.ErrorLog("[ERROR] "+msg, v...) } } diff --git a/core/unifi/unidev_test.go b/core/unifi/unidev_test.go index ba654e94..32f3d266 100644 --- a/core/unifi/unidev_test.go +++ b/core/unifi/unidev_test.go @@ -43,7 +43,7 @@ func TestUniReq(t *testing.T) { u := "/test/path" url := "http://some.url:8443" // Test empty parameters. - authReq := &AuthedReq{Client: &http.Client{}, baseURL: url} + authReq := &Unifi{Client: &http.Client{}, baseURL: url} r, err := authReq.UniReq(u, "") a.Nil(err, "newrequest must not produce an error") a.EqualValues(u, r.URL.Path, @@ -54,7 +54,7 @@ func TestUniReq(t *testing.T) { // Test with parameters p := "key1=value9&key2=value7" - authReq = &AuthedReq{Client: &http.Client{}, baseURL: "http://some.url:8443"} + authReq = &Unifi{Client: &http.Client{}, baseURL: "http://some.url:8443"} r, err = authReq.UniReq(u, p) a.Nil(err, "newrequest must not produce an error") a.EqualValues(u, r.URL.Path, diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 1f8a3cc8..92893292 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -7,27 +7,16 @@ import ( "github.com/pkg/errors" ) -const ( - // ClientPath is Unifi Clients API Path - ClientPath = "/api/s/default/stat/sta" - // DevicePath is where we get data about Unifi devices. - DevicePath = "/api/s/default/stat/device" - // NetworkPath contains network-configuration data. Not really graphable. - NetworkPath = "/api/s/default/rest/networkconf" - // UserGroupPath contains usergroup configurations. - UserGroupPath = "/api/s/default/rest/usergroup" -) - // GetUnifiClients returns a response full of clients' data from the Unifi Controller. -func (c *AuthedReq) GetUnifiClients() ([]UCL, error) { +func (u *Unifi) GetUnifiClients() ([]UCL, error) { var response struct { Clients []UCL `json:"data"` } - req, err := c.UniReq(ClientPath, "") + req, err := u.UniReq(ClientPath, "") if err != nil { return nil, errors.Wrap(err, "c.UniReq(ClientPath)") } - resp, err := c.Do(req) + resp, err := u.Do(req) if err != nil { return nil, errors.Wrap(err, "c.Do(req)") } @@ -43,15 +32,15 @@ func (c *AuthedReq) GetUnifiClients() ([]UCL, error) { } // GetUnifiDevices returns a response full of devices' data from the Unifi Controller. -func (c *AuthedReq) GetUnifiDevices() (*Devices, error) { +func (u *Unifi) GetUnifiDevices() (*Devices, error) { var parsed struct { Data []json.RawMessage `json:"data"` } - req, err := c.UniReq(DevicePath, "") + req, err := u.UniReq(DevicePath, "") if err != nil { return nil, errors.Wrap(err, "c.UniReq(DevicePath)") } - resp, err := c.Do(req) + resp, err := u.Do(req) if err != nil { return nil, errors.Wrap(err, "c.Do(req)") } @@ -63,10 +52,11 @@ func (c *AuthedReq) GetUnifiDevices() (*Devices, error) { } else if err = json.Unmarshal(body, &parsed); err != nil { return nil, errors.Wrap(err, "json.Unmarshal([]json.RawMessage)") } - return c.parseUnifiDevices(parsed.Data), nil + return u.parseUnifiDevices(parsed.Data), nil } -func (c *AuthedReq) parseUnifiDevices(data []json.RawMessage) *Devices { +// parseUnifiDevices parses the raw JSON from the Unifi Controller into device structures. +func (u *Unifi) parseUnifiDevices(data []json.RawMessage) *Devices { devices := new(Devices) // Loop each item in the raw JSON message, detect its type and unmarshal it. for i, r := range data { @@ -76,36 +66,36 @@ func (c *AuthedReq) parseUnifiDevices(data []json.RawMessage) *Devices { // Unamrshal into a map and check "type" var obj map[string]interface{} if err := json.Unmarshal(r, &obj); err != nil { - c.eLogf("[%d] json.Unmarshal(interfce{}): %v", i, err) + u.eLogf("%d: json.Unmarshal(interfce{}): %v", i, err) continue } assetType := "" if t, ok := obj["type"].(string); ok { assetType = t } - c.dLogf("Unmarshalling Device Type:", assetType) + u.dLogf("Unmarshalling Device Type:", assetType) // Unmarshal again into the correct type.. switch assetType { case "uap": if err := json.Unmarshal(r, &uap); err != nil { - c.eLogf("[%d] json.Unmarshal([]UAP): %v", i, err) + u.eLogf("%d: json.Unmarshal([]UAP): %v", i, err) continue } devices.UAPs = append(devices.UAPs, uap) case "ugw", "usg": // in case they ever fix the name in the api. if err := json.Unmarshal(r, &usg); err != nil { - c.eLogf("[%d] json.Unmarshal([]USG): %v", i, err) + u.eLogf("%d: json.Unmarshal([]USG): %v", i, err) continue } devices.USGs = append(devices.USGs, usg) case "usw": if err := json.Unmarshal(r, &usw); err != nil { - c.eLogf("[%d] json.Unmarshal([]USW): %v", i, err) + u.eLogf("%d: json.Unmarshal([]USW): %v", i, err) continue } devices.USWs = append(devices.USWs, usw) default: - c.dLogf("unknown asset type -", assetType, "- skipping") + u.dLogf("unknown asset type -", assetType, "- skipping") continue } } diff --git a/core/unifi/usg.go b/core/unifi/usg.go index 9d3bfa73..1794d6c2 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg.go @@ -7,8 +7,9 @@ import ( influx "github.com/influxdata/influxdb/client/v2" ) -// Points generates a device's datapoints for InfluxDB. -func (u USG) Points() ([]*influx.Point, error) { +// Points generates Unifi Gateway datapoints for InfluxDB. +// These points can be passed directly to influx. +func (u *USG) Points() ([]*influx.Point, error) { var points []*influx.Point tags := map[string]string{ "id": u.ID, diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index 54fe09e4..ebbe1b8d 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -2,7 +2,7 @@ package unifi import "encoding/json" -// USG is a Unifi Security Gateway +// USG represents all the data from the Ubiquit Controller for a Unifi Security Gateway. type USG struct { ID string `json:"_id"` UUptime float64 `json:"_uptime"` diff --git a/core/unifi/usw.go b/core/unifi/usw.go index d19346fa..b6b4bc25 100644 --- a/core/unifi/usw.go +++ b/core/unifi/usw.go @@ -7,8 +7,9 @@ import ( influx "github.com/influxdata/influxdb/client/v2" ) -// Points generates a device's datapoints for InfluxDB. -func (u USW) Points() ([]*influx.Point, error) { +// Points generates Unifi Switch datapoints for InfluxDB. +// These points can be passed directly to influx. +func (u *USW) Points() ([]*influx.Point, error) { var points []*influx.Point tags := map[string]string{ "id": u.ID, diff --git a/core/unifi/usw_type.go b/core/unifi/usw_type.go index 42b36b4c..7fa68de4 100644 --- a/core/unifi/usw_type.go +++ b/core/unifi/usw_type.go @@ -1,6 +1,6 @@ package unifi -// USW is a Unifi Switch +// USW represents all the data from the Ubiquit Controller for a Unifi Switch. type USW struct { ID string `json:"_id"` UUptime float64 `json:"_uptime"`