Rename a few pieces.

This commit is contained in:
David Newhall II 2019-01-26 04:15:41 -08:00
parent 7256b15467
commit d2862befc0
10 changed files with 147 additions and 141 deletions

View File

@ -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 {

View File

@ -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!
*/

View File

@ -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.

View File

@ -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...)
}
}

View File

@ -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,

View File

@ -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 := "<missing>"
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
}
}

View File

@ -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,

View File

@ -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"`

View File

@ -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,

View File

@ -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"`