From 5b50d30dce82c429d6111a27151af0982302204f Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 23 Jan 2019 18:10:28 -0800 Subject: [PATCH 001/194] Initial commit --- core/unifi/LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 core/unifi/LICENSE diff --git a/core/unifi/LICENSE b/core/unifi/LICENSE new file mode 100644 index 00000000..4257b091 --- /dev/null +++ b/core/unifi/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Go Lift - Building Strong Go Tools + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 7f57cae94e88618354974a3b258331f13cb1e6f7 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 23 Jan 2019 18:14:23 -0800 Subject: [PATCH 002/194] Initial library import. --- core/unifi/README.md | 12 ++ core/unifi/clients.go | 104 ++++++++++ core/unifi/clients_type.go | 88 ++++++++ core/unifi/uap.go | 266 ++++++++++++++++++++++++ core/unifi/uap_type.go | 361 ++++++++++++++++++++++++++++++++ core/unifi/unidev.go | 105 ++++++++++ core/unifi/unidev_test.go | 82 ++++++++ core/unifi/unifi.go | 154 ++++++++++++++ core/unifi/usg.go | 186 +++++++++++++++++ core/unifi/usg_type.go | 260 +++++++++++++++++++++++ core/unifi/usw.go | 118 +++++++++++ core/unifi/usw_type.go | 415 +++++++++++++++++++++++++++++++++++++ 12 files changed, 2151 insertions(+) create mode 100644 core/unifi/README.md create mode 100644 core/unifi/clients.go create mode 100644 core/unifi/clients_type.go create mode 100644 core/unifi/uap.go create mode 100644 core/unifi/uap_type.go create mode 100644 core/unifi/unidev.go create mode 100644 core/unifi/unidev_test.go create mode 100644 core/unifi/unifi.go create mode 100644 core/unifi/usg.go create mode 100644 core/unifi/usg_type.go create mode 100644 core/unifi/usw.go create mode 100644 core/unifi/usw_type.go diff --git a/core/unifi/README.md b/core/unifi/README.md new file mode 100644 index 00000000..20c723db --- /dev/null +++ b/core/unifi/README.md @@ -0,0 +1,12 @@ +# Go Library: `unifi` + +It connects to a Unifi Controller, given a url, username and password. Returns +an authenticated http Client you may use to query the device for data. Also +contains some built-in methods for de-serializing common client and device +data. The included asset interface currently only works for InfluxDB but could +probably be modified to support other output mechanisms; not sure really. + +Pull requests and feedback are welcomed! + +This lib is rudimentary and gets a job done for the tool at hand. It could be +used to base your own library. Good luck! diff --git a/core/unifi/clients.go b/core/unifi/clients.go new file mode 100644 index 00000000..f4694537 --- /dev/null +++ b/core/unifi/clients.go @@ -0,0 +1,104 @@ +package unidev + +import ( + "strconv" + "time" + + influx "github.com/influxdata/influxdb/client/v2" +) + +// Points generates a client's datapoints for InfluxDB. +func (u UCL) Points() ([]*influx.Point, error) { + var points []*influx.Point + 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-" + } + 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), + } + 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, + } + pt, err := influx.NewPoint("clients", tags, fields, time.Now()) + if err == nil { + points = append(points, pt) + } + return points, err +} diff --git a/core/unifi/clients_type.go b/core/unifi/clients_type.go new file mode 100644 index 00000000..45ddf1dd --- /dev/null +++ b/core/unifi/clients_type.go @@ -0,0 +1,88 @@ +package unidev + +// UCL defines all the data a connected-network client contains. +type UCL struct { + ID string `json:"_id"` + IsGuestByUAP bool `json:"_is_guest_by_uap"` + IsGuestByUGW bool `json:"_is_guest_by_ugw"` + IsGuestByUSW bool `json:"_is_guest_by_usw"` + LastSeenByUAP int64 `json:"_last_seen_by_uap"` + LastSeenByUGW int64 `json:"_last_seen_by_ugw"` + LastSeenByUSW int64 `json:"_last_seen_by_usw"` + UptimeByUAP int64 `json:"_uptime_by_uap"` + UptimeByUGW int64 `json:"_uptime_by_ugw"` + UptimeByUSW int64 `json:"_uptime_by_usw"` + ApMac string `json:"ap_mac"` + AssocTime int64 `json:"assoc_time"` + Authorized bool `json:"authorized"` + Bssid string `json:"bssid"` + BytesR int64 `json:"bytes-r"` + Ccq int64 `json:"ccq"` + Channel int `json:"channel"` + DevCat int `json:"dev_cat"` + DevFamily int `json:"dev_family"` + DevID int `json:"dev_id"` + DpiStats struct { + App int64 + Cat int64 + RxBytes int64 + RxPackets int64 + TxBytes int64 + TxPackets int64 + } `json:"dpi_stats"` + DpiStatsLastUpdated int64 `json:"dpi_stats_last_updated"` + Essid string `json:"essid"` + FirstSeen int64 `json:"first_seen"` + FixedIP string `json:"fixed_ip"` + Hostname string `json:"hostname"` + GwMac string `json:"gw_mac"` + IdleTime int64 `json:"idle_time"` + IP string `json:"ip"` + Is11R bool `json:"is_11r"` + IsGuest bool `json:"is_guest"` + IsWired bool `json:"is_wired"` + LastSeen int64 `json:"last_seen"` + LatestAssocTime int64 `json:"latest_assoc_time"` + Mac string `json:"mac"` + Name string `json:"name"` + Network string `json:"network"` + NetworkID string `json:"network_id"` + Noise int64 `json:"noise"` + Note string `json:"note"` + Noted bool `json:"noted"` + OsClass int `json:"os_class"` + OsName int `json:"os_name"` + Oui string `json:"oui"` + PowersaveEnabled bool `json:"powersave_enabled"` + QosPolicyApplied bool `json:"qos_policy_applied"` + Radio string `json:"radio"` + RadioName string `json:"radio_name"` + RadioProto string `json:"radio_proto"` + RoamCount int64 `json:"roam_count"` + Rssi int64 `json:"rssi"` + RxBytes int64 `json:"rx_bytes"` + RxBytesR int64 `json:"rx_bytes-r"` + RxPackets int64 `json:"rx_packets"` + RxRate int64 `json:"rx_rate"` + Signal int64 `json:"signal"` + SiteID string `json:"site_id"` + SwDepth int `json:"sw_depth"` + SwMac string `json:"sw_mac"` + SwPort int `json:"sw_port"` + TxBytes int64 `json:"tx_bytes"` + TxBytesR int64 `json:"tx_bytes-r"` + TxPackets int64 `json:"tx_packets"` + TxPower int64 `json:"tx_power"` + TxRate int64 `json:"tx_rate"` + Uptime int64 `json:"uptime"` + UserID string `json:"user_id"` + UserGroupID string `json:"usergroup_id"` + UseFixedIP bool `json:"use_fixedip"` + Vlan int `json:"vlan"` + WiredRxBytes int64 `json:"wired-rx_bytes"` + WiredRxBytesR int64 `json:"wired-rx_bytes-r"` + WiredRxPackets int64 `json:"wired-rx_packets"` + WiredTxBytes int64 `json:"wired-tx_bytes"` + WiredTxBytesR int64 `json:"wired-tx_bytes-r"` + WiredTxPackets int64 `json:"wired-tx_packets"` +} diff --git a/core/unifi/uap.go b/core/unifi/uap.go new file mode 100644 index 00000000..d388506c --- /dev/null +++ b/core/unifi/uap.go @@ -0,0 +1,266 @@ +package unidev + +import ( + "strconv" + "time" + + influx "github.com/influxdata/influxdb/client/v2" +) + +// Points generates a device's datapoints for InfluxDB. +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! + */ + var points []*influx.Point + tags := map[string]string{ + "id": u.ID, + "mac": u.Mac, + "device_type": u.Stat.O, + "device_oid": u.Stat.Oid, + "device_ap": u.Stat.Ap, + "site_id": u.SiteID, + "name": u.Name, + "addopted": strconv.FormatBool(u.Adopted), + "bandsteering_mode": u.BandsteeringMode, + "board_rev": strconv.Itoa(u.BoardRev), + "cfgversion": u.Cfgversion, + "config_network_ip": u.ConfigNetwork.IP, + "config_network_type": u.ConfigNetwork.Type, + "connect_request_ip": u.ConnectRequestIP, + "connect_request_port": u.ConnectRequestPort, + "default": strconv.FormatBool(u.Default), + "device_id": u.DeviceID, + "discovered_via": u.DiscoveredVia, + "fw_caps": strconv.Itoa(u.FwCaps), + "guest-num_sta": strconv.Itoa(u.GuestNumSta), + "guest_token": u.GuestToken, + "has_eth1": strconv.FormatBool(u.HasEth1), + "has_speaker": strconv.FormatBool(u.HasSpeaker), + "inform_ip": u.InformIP, + "isolated": strconv.FormatBool(u.Isolated), + "last_uplink_mac": u.LastUplink.UplinkMac, + "last_uplink_remote_port": strconv.Itoa(u.LastUplink.UplinkRemotePort), + "known_cfgversion": u.KnownCfgversion, + "led_override": u.LedOverride, + "locating": strconv.FormatBool(u.Locating), + "model": u.Model, + "outdoor_mode_override": u.OutdoorModeOverride, + "serial": u.Serial, + "type": u.Type, + "version_incompatible": strconv.FormatBool(u.VersionIncompatible), + "vwireEnabled": strconv.FormatBool(u.VwireEnabled), + "wifi_caps": strconv.Itoa(u.WifiCaps), + } + fields := map[string]interface{}{ + "ip": u.IP, + "bytes": u.Bytes, + "bytes_d": u.BytesD, + "bytes_r": u.BytesR, + "last_seen": u.LastSeen, + "rx_bytes": u.RxBytes, + "rx_bytes-d": u.RxBytesD, + "tx_bytes": u.TxBytes, + "tx_bytes-d": u.TxBytesD, + "uptime": u.Uptime.Number, + "considered_lost_at": u.ConsideredLostAt, + "next_heartbeat_at": u.NextHeartbeatAt, + "scanning": u.Scanning, + "spectrum_scanning": u.SpectrumScanning, + "roll_upgrade": u.Rollupgrade, + "state": u.State, + "upgradable": u.Upgradable, + "user-num_sta": u.UserNumSta, + "version": u.Version, + "loadavg_1": u.SysStats.Loadavg1, + "loadavg_5": u.SysStats.Loadavg5, + "loadavg_15": u.SysStats.Loadavg15, + "mem_buffer": u.SysStats.MemBuffer, + "mem_total": u.SysStats.MemTotal, + "mem_used": u.SysStats.MemUsed, + "cpu": u.SystemStats.CPU, + "mem": u.SystemStats.Mem, + "system_uptime": u.SystemStats.Uptime, + "stat_bytes": u.Stat.Bytes, + "stat_duration": u.Stat.Duration, + "stat_guest-rx_bytes": u.Stat.RxBytes, + "stat_guest-rx_crypts": u.Stat.RxCrypts, + "stat_guest-rx_dropped": u.Stat.RxDropped, + "stat_guest-rx_errors": u.Stat.RxErrors, + "stat_guest-rx_frags": u.Stat.RxFrags, + "stat_guest-rx_packets": u.Stat.RxPackets, + "stat_guest-tx_bytes": u.Stat.TxBytes, + "stat_guest-tx_dropped": u.Stat.TxDropped, + "stat_guest-tx_errors": u.Stat.TxErrors, + "stat_guest-tx_packets": u.Stat.TxPackets, + "stat_guest-tx_retries": u.Stat.TxRetries, + "stat_port_1-rx_broadcast": u.Stat.Port1RxBroadcast, + "stat_port_1-rx_bytes": u.Stat.Port1RxBytes, + "stat_port_1-rx_multicast": u.Stat.Port1RxMulticast, + "stat_port_1-rx_packets": u.Stat.Port1RxPackets, + "stat_port_1-tx_broadcast": u.Stat.Port1TxBroadcast, + "stat_port_1-tx_bytes": u.Stat.Port1TxBytes, + "stat_port_1-tx_multicast": u.Stat.Port1TxMulticast, + "stat_port_1-tx_packets": u.Stat.Port1TxPackets, + "stat_rx_bytes": u.Stat.RxBytes, + "stat_rx_crypts": u.Stat.RxCrypts, + "stat_rx_dropped": u.Stat.RxDropped, + "stat_rx_errors": u.Stat.RxErrors, + "stat_rx_frags": u.Stat.RxFrags, + "stat_rx_packets": u.Stat.TxPackets, + "stat_tx_bytes": u.Stat.TxBytes, + "stat_tx_dropped": u.Stat.TxDropped, + "stat_tx_errors": u.Stat.TxErrors, + "stat_tx_packets": u.Stat.TxPackets, + "stat_tx_retries": u.Stat.TxRetries, + "stat_user-rx_bytes": u.Stat.UserRxBytes, + "stat_user-rx_crypts": u.Stat.UserRxCrypts, + "stat_user-rx_dropped": u.Stat.UserRxDropped, + "stat_user-rx_errors": u.Stat.UserRxErrors, + "stat_user-rx_frags": u.Stat.UserRxFrags, + "stat_user-rx_packets": u.Stat.UserRxPackets, + "stat_user-tx_bytes": u.Stat.UserTxBytes, + "stat_user-tx_dropped": u.Stat.UserTxDropped, + "stat_user-tx_errors": u.Stat.UserTxErrors, + "stat_user-tx_packets": u.Stat.UserTxPackets, + "stat_user-tx_retries": u.Stat.UserTxRetries, + "stat_user-wifi0-rx_bytes": u.Stat.UserWifi0RxBytes, + "stat_user-wifi0-rx_crypts": u.Stat.UserWifi0RxCrypts, + "stat_user-wifi0-rx_dropped": u.Stat.UserWifi0RxDropped, + "stat_user-wifi0-rx_errors": u.Stat.UserWifi0RxErrors, + "stat_user-wifi0-rx_frags": u.Stat.UserWifi0RxFrags, + "stat_user-wifi0-rx_packets": u.Stat.UserWifi0RxPackets, + "stat_user-wifi0-tx_bytes": u.Stat.UserWifi0TxBytes, + "stat_user-wifi0-tx_dropped": u.Stat.UserWifi0TxDropped, + "stat_user-wifi0-tx_errors": u.Stat.UserWifi0TxErrors, + "stat_user-wifi0-tx_packets": u.Stat.UserWifi0TxPackets, + "stat_user-wifi0-tx_retries": u.Stat.UserWifi0TxRetries, + "stat_user-wifi1-rx_bytes": u.Stat.UserWifi1RxBytes, + "stat_user-wifi1-rx_crypts": u.Stat.UserWifi1RxCrypts, + "stat_user-wifi1-rx_dropped": u.Stat.UserWifi1RxDropped, + "stat_user-wifi1-rx_errors": u.Stat.UserWifi1RxErrors, + "stat_user-wifi1-rx_frags": u.Stat.UserWifi1RxFrags, + "stat_user-wifi1-rx_packets": u.Stat.UserWifi1RxPackets, + "stat_user-wifi1-tx_bytes": u.Stat.UserWifi1TxBytes, + "stat_user-wifi1-tx_dropped": u.Stat.UserWifi1TxDropped, + "stat_user-wifi1-tx_errors": u.Stat.UserWifi1TxErrors, + "stat_user-wifi1-tx_packets": u.Stat.UserWifi1TxPackets, + "stat_user-wifi1-tx_retries": u.Stat.UserWifi1TxRetries, + "stat_wifi0-rx_bytes": u.Stat.Wifi0RxBytes, + "stat_wifi0-rx_crypts": u.Stat.Wifi0RxCrypts, + "stat_wifi0-rx_dropped": u.Stat.Wifi0RxDropped, + "stat_wifi0-rx_errors": u.Stat.Wifi0RxErrors, + "stat_wifi0-rx_frags": u.Stat.Wifi0RxFrags, + "stat_wifi0-rx_packets": u.Stat.Wifi0RxPackets, + "stat_wifi0-tx_bytes": u.Stat.Wifi0TxBytes, + "stat_wifi0-tx_dropped": u.Stat.Wifi0TxDropped, + "stat_wifi0-tx_errors": u.Stat.Wifi0TxErrors, + "stat_wifi0-tx_packets": u.Stat.Wifi0TxPackets, + "stat_wifi0-tx_retries": u.Stat.Wifi0TxRetries, + "stat_wifi1-rx_bytes": u.Stat.Wifi1RxBytes, + "stat_wifi1-rx_crypts": u.Stat.Wifi1RxCrypts, + "stat_wifi1-rx_dropped": u.Stat.Wifi1RxDropped, + "stat_wifi1-rx_errors": u.Stat.Wifi1RxErrors, + "stat_wifi1-rx_frags": u.Stat.Wifi1RxFrags, + "stat_wifi1-rx_packets": u.Stat.Wifi1RxPackets, + "stat_wifi1-tx_bytes": u.Stat.Wifi1TxBytes, + "stat_wifi1-tx_dropped": u.Stat.Wifi1TxDropped, + "stat_wifi1-tx_errors": u.Stat.Wifi1TxErrors, + "stat_wifi1-tx_packets": u.Stat.Wifi1TxPackets, + "stat_wifi1-tx_retries": u.Stat.Wifi1TxRetries, + } + pt, err := influx.NewPoint("uap", tags, fields, time.Now()) + if err != nil { + return nil, err + } + points = append(points, pt) + for _, p := range u.RadioTable { + tags := map[string]string{ + "device_name": u.Name, + "device_id": u.ID, + "device_mac": u.Mac, + "name": p.Name, + "wlangroup_id": p.WlangroupID, + "channel": p.Channel.String, + "radio": p.Radio, + } + fields := map[string]interface{}{ + "builtin_ant_gain": p.BuiltinAntGain, + "current_antenna_gain": p.CurrentAntennaGain, + "has_dfs": p.HasDfs, + "has_fccdfs": p.HasFccdfs, + "ht": p.Ht, + "is_11ac": p.Is11Ac, + "max_txpower": p.MaxTxpower, + "min_rssi_enabled": p.MinRssiEnabled, + "min_txpower": p.MinTxpower, + "nss": p.Nss, + "radio_caps": p.RadioCaps, + "tx_power": p.TxPower.Number, + "tx_power_mode": p.TxPowerMode, + } + + for _, s := range u.RadioTableStats { + // This may be a tad slower but it allows putting + // all the radio stats into one table. + if p.Name == s.Name { + fields["ast_be_xmit"] = s.AstBeXmit + fields["ast_cst"] = s.AstCst + fields["channel"] = s.Channel + fields["ast_txto"] = s.AstTxto + fields["cu_self_rx"] = s.CuSelfRx + fields["cu_self_tx"] = s.CuSelfTx + fields["cu_total"] = s.CuTotal + fields["extchannel"] = s.Extchannel + fields["gain"] = s.Gain + fields["guest-num_sta"] = s.GuestNumSta + fields["num_sta"] = s.NumSta + fields["radio"] = s.Radio + fields["state"] = s.State + fields["radio_tx_packets"] = s.TxPackets + fields["radio_tx_power"] = s.TxPower + fields["radio_tx_retries"] = s.TxRetries + fields["user-num_sta"] = s.UserNumSta + } + } + for _, s := range u.VapTable { + if p.Name == s.RadioName { + tags["ap_mac"] = s.ApMac + tags["bssid"] = s.Bssid + fields["ccq"] = s.Ccq + fields["essid"] = s.Essid + fields["extchannel"] = s.Extchannel + tags["vap_id"] = s.ID + fields["is_guest"] = s.IsGuest + fields["is_wep"] = s.IsWep + fields["mac_filter_rejections"] = s.MacFilterRejections + fields["map_id"] = s.MapID + tags["vap_name"] = s.Name + fields["rx_bytes"] = s.RxBytes + fields["rx_crypts"] = s.RxCrypts + fields["rx_dropped"] = s.RxDropped + fields["rx_errors"] = s.RxErrors + fields["rx_frags"] = s.RxFrags + fields["rx_nwids"] = s.RxNwids + fields["rx_packets"] = s.RxPackets + fields["tx_bytes"] = s.TxBytes + fields["tx_dropped"] = s.TxDropped + fields["tx_errors"] = s.TxErrors + fields["tx_latency_avg"] = s.TxLatencyAvg + fields["tx_latency_max"] = s.TxLatencyMax + fields["tx_latency_min"] = s.TxLatencyMin + fields["tx_packets"] = s.TxPackets + fields["tx_power"] = s.TxPower + fields["tx_retries"] = s.TxRetries + fields["usage"] = s.Usage + tags["wlanconf_id"] = s.WlanconfID + } + } + pt, err := influx.NewPoint("uap_radios", tags, fields, time.Now()) + if err != nil { + return points, err + } + points = append(points, pt) + } + return points, nil +} diff --git a/core/unifi/uap_type.go b/core/unifi/uap_type.go new file mode 100644 index 00000000..053a83e1 --- /dev/null +++ b/core/unifi/uap_type.go @@ -0,0 +1,361 @@ +package unidev + +// UAP is 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. + No ones feelings will be hurt if you want to break this + up into multiple structs, and/or make it better in general. + */ + ID string `json:"_id"` + UUptime float64 `json:"_uptime"` + AdoptIP string `json:"adopt_ip,omitempty"` + AdoptURL string `json:"adopt_url,omitempty"` + Adopted bool `json:"adopted"` + AntennaTable []struct { + ID float64 `json:"id"` + Name string `json:"name"` + Wifi0Gain float64 `json:"wifi0_gain"` + Wifi1Gain float64 `json:"wifi1_gain"` + } `json:"antenna_table"` + BandsteeringMode string `json:"bandsteering_mode,omitempty"` + BoardRev int `json:"board_rev"` + Bytes float64 `json:"bytes"` + BytesD float64 `json:"bytes-d"` + BytesR float64 `json:"bytes-r"` + Cfgversion string `json:"cfgversion"` + ConfigNetwork struct { + IP string `json:"ip"` + Type string `json:"type"` + } `json:"config_network"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + ConsideredLostAt float64 `json:"considered_lost_at"` + CountrycodeTable []float64 `json:"countrycode_table"` + Default bool `json:"default,omitempty"` + DeviceID string `json:"device_id"` + DiscoveredVia string `json:"discovered_via,omitempty"` + DownlinkTable []interface{} `json:"downlink_table"` + EthernetTable []struct { + Mac string `json:"mac"` + Name string `json:"name"` + NumPort float64 `json:"num_port"` + } `json:"ethernet_table"` + FwCaps int `json:"fw_caps"` + GuestNumSta int `json:"guest-num_sta"` + GuestToken string `json:"guest_token"` + HasEth1 bool `json:"has_eth1"` + HasSpeaker bool `json:"has_speaker"` + InformIP string `json:"inform_ip"` + InformURL string `json:"inform_url"` + IP string `json:"ip"` + Isolated bool `json:"isolated"` + KnownCfgversion string `json:"known_cfgversion"` + LastSeen float64 `json:"last_seen"` + LastUplink struct { + UplinkMac string `json:"uplink_mac"` + UplinkRemotePort int `json:"uplink_remote_port"` + } `json:"last_uplink"` + LedOverride string `json:"led_override"` + Locating bool `json:"locating"` + Mac string `json:"mac"` + Model string `json:"model"` + Name string `json:"name"` + NextHeartbeatAt float64 `json:"next_heartbeat_at"` + NumSta float64 `json:"num_sta"` + OutdoorModeOverride string `json:"outdoor_mode_override"` + PortTable []struct { + AggregatedBy bool `json:"aggregated_by"` + AttrNoEdit bool `json:"attr_no_edit,omitempty"` + Autoneg bool `json:"autoneg"` + BytesR float64 `json:"bytes-r"` + Enable bool `json:"enable"` + FlowctrlRx bool `json:"flowctrl_rx"` + FlowctrlTx bool `json:"flowctrl_tx"` + FullDuplex bool `json:"full_duplex"` + IsUplink bool `json:"is_uplink"` + Jumbo bool `json:"jumbo"` + MacTable []struct { + Age float64 `json:"age"` + Mac string `json:"mac"` + Static bool `json:"static"` + Uptime float64 `json:"uptime"` + Vlan float64 `json:"vlan"` + } `json:"mac_table"` + Masked bool `json:"masked"` + Media string `json:"media"` + Name string `json:"name"` + OpMode string `json:"op_mode"` + PoeCaps float64 `json:"poe_caps"` + PortDelta struct { + RxBytes float64 `json:"rx_bytes"` + RxPackets float64 `json:"rx_packets"` + TimeDelta float64 `json:"time_delta"` + TxBytes float64 `json:"tx_bytes"` + TxPackets float64 `json:"tx_packets"` + } `json:"port_delta"` + PortIdx float64 `json:"port_idx"` + PortPoe bool `json:"port_poe"` + PortconfID string `json:"portconf_id"` + RxBroadcast float64 `json:"rx_broadcast"` + RxBytes float64 `json:"rx_bytes"` + RxBytesR float64 `json:"rx_bytes-r"` + RxDropped float64 `json:"rx_dropped"` + RxErrors float64 `json:"rx_errors"` + RxMulticast float64 `json:"rx_multicast"` + RxPackets float64 `json:"rx_packets"` + Speed float64 `json:"speed"` + StpPathcost float64 `json:"stp_pathcost"` + StpState string `json:"stp_state"` + TxBroadcast float64 `json:"tx_broadcast"` + TxBytes float64 `json:"tx_bytes"` + TxBytesR float64 `json:"tx_bytes-r"` + TxDropped float64 `json:"tx_dropped"` + TxErrors float64 `json:"tx_errors"` + TxMulticast float64 `json:"tx_multicast"` + TxPackets float64 `json:"tx_packets"` + Up bool `json:"up"` + } `json:"port_table"` + RadioTable []struct { + BuiltinAntGain float64 `json:"builtin_ant_gain"` + BuiltinAntenna bool `json:"builtin_antenna"` + Channel FlexInt `json:"channel"` + CurrentAntennaGain float64 `json:"current_antenna_gain"` + Ht string `json:"ht"` + MaxTxpower float64 `json:"max_txpower"` + MinRssiEnabled bool `json:"min_rssi_enabled"` + MinTxpower float64 `json:"min_txpower"` + Name string `json:"name"` + Nss float64 `json:"nss"` + Radio string `json:"radio"` + RadioCaps float64 `json:"radio_caps"` + TxPower FlexInt `json:"tx_power"` + TxPowerMode string `json:"tx_power_mode"` + WlangroupID string `json:"wlangroup_id"` + HasDfs bool `json:"has_dfs,omitempty"` + HasFccdfs bool `json:"has_fccdfs,omitempty"` + Is11Ac bool `json:"is_11ac,omitempty"` + } `json:"radio_table"` + RadioTableStats []struct { + AstBeXmit float64 `json:"ast_be_xmit"` + AstCst float64 `json:"ast_cst"` + AstTxto float64 `json:"ast_txto"` + Channel float64 `json:"channel"` + CuSelfRx float64 `json:"cu_self_rx"` + CuSelfTx float64 `json:"cu_self_tx"` + CuTotal float64 `json:"cu_total"` + Extchannel float64 `json:"extchannel"` + Gain float64 `json:"gain"` + GuestNumSta float64 `json:"guest-num_sta"` + Name string `json:"name"` + NumSta float64 `json:"num_sta"` + Radio string `json:"radio"` + State string `json:"state"` + TxPackets float64 `json:"tx_packets"` + TxPower float64 `json:"tx_power"` + TxRetries float64 `json:"tx_retries"` + UserNumSta float64 `json:"user-num_sta"` + } `json:"radio_table_stats"` + Rollupgrade bool `json:"rollupgrade"` + RxBytes float64 `json:"rx_bytes"` + RxBytesD float64 `json:"rx_bytes-d"` + ScanRadioTable []interface{} `json:"scan_radio_table"` + Scanning bool `json:"scanning"` + Serial string `json:"serial"` + SiteID string `json:"site_id"` + SpectrumScanning bool `json:"spectrum_scanning"` + SSHSessionTable []interface{} `json:"ssh_session_table"` + Stat struct { + Ap string `json:"ap"` + Bytes float64 `json:"bytes"` + Datetime string `json:"datetime"` + Duration float64 `json:"duration"` + GuestRxBytes float64 `json:"guest-rx_bytes"` + GuestRxCrypts float64 `json:"guest-rx_crypts"` + GuestRxDropped float64 `json:"guest-rx_dropped"` + GuestRxErrors float64 `json:"guest-rx_errors"` + GuestRxFrags float64 `json:"guest-rx_frags"` + GuestRxPackets float64 `json:"guest-rx_packets"` + GuestTxBytes float64 `json:"guest-tx_bytes"` + GuestTxDropped float64 `json:"guest-tx_dropped"` + GuestTxErrors float64 `json:"guest-tx_errors"` + GuestTxPackets float64 `json:"guest-tx_packets"` + GuestTxRetries float64 `json:"guest-tx_retries"` + O string `json:"o"` + Oid string `json:"oid"` + Port1RxBroadcast float64 `json:"port_1-rx_broadcast"` + Port1RxBytes float64 `json:"port_1-rx_bytes"` + Port1RxMulticast float64 `json:"port_1-rx_multicast"` + Port1RxPackets float64 `json:"port_1-rx_packets"` + Port1TxBroadcast float64 `json:"port_1-tx_broadcast"` + Port1TxBytes float64 `json:"port_1-tx_bytes"` + Port1TxMulticast float64 `json:"port_1-tx_multicast"` + Port1TxPackets float64 `json:"port_1-tx_packets"` + RxBytes float64 `json:"rx_bytes"` + RxCrypts float64 `json:"rx_crypts"` + RxDropped float64 `json:"rx_dropped"` + RxErrors float64 `json:"rx_errors"` + RxFrags float64 `json:"rx_frags"` + RxPackets float64 `json:"rx_packets"` + SiteID string `json:"site_id"` + Time float64 `json:"time"` + TxBytes float64 `json:"tx_bytes"` + TxDropped float64 `json:"tx_dropped"` + TxErrors float64 `json:"tx_errors"` + TxPackets float64 `json:"tx_packets"` + TxRetries float64 `json:"tx_retries"` + UserRxBytes float64 `json:"user-rx_bytes"` + UserRxCrypts float64 `json:"user-rx_crypts"` + UserRxDropped float64 `json:"user-rx_dropped"` + UserRxErrors float64 `json:"user-rx_errors"` + UserRxFrags float64 `json:"user-rx_frags"` + UserRxPackets float64 `json:"user-rx_packets"` + UserTxBytes float64 `json:"user-tx_bytes"` + UserTxDropped float64 `json:"user-tx_dropped"` + UserTxErrors float64 `json:"user-tx_errors"` + UserTxPackets float64 `json:"user-tx_packets"` + UserTxRetries float64 `json:"user-tx_retries"` + UserWifi0RxBytes float64 `json:"user-wifi0-rx_bytes"` + UserWifi0RxCrypts float64 `json:"user-wifi0-rx_crypts"` + UserWifi0RxDropped float64 `json:"user-wifi0-rx_dropped"` + UserWifi0RxErrors float64 `json:"user-wifi0-rx_errors"` + UserWifi0RxFrags float64 `json:"user-wifi0-rx_frags"` + UserWifi0RxPackets float64 `json:"user-wifi0-rx_packets"` + UserWifi0TxBytes float64 `json:"user-wifi0-tx_bytes"` + UserWifi0TxDropped float64 `json:"user-wifi0-tx_dropped"` + UserWifi0TxErrors float64 `json:"user-wifi0-tx_errors"` + UserWifi0TxPackets float64 `json:"user-wifi0-tx_packets"` + UserWifi0TxRetries float64 `json:"user-wifi0-tx_retries"` + UserWifi1RxBytes float64 `json:"user-wifi1-rx_bytes"` + UserWifi1RxCrypts float64 `json:"user-wifi1-rx_crypts"` + UserWifi1RxDropped float64 `json:"user-wifi1-rx_dropped"` + UserWifi1RxErrors float64 `json:"user-wifi1-rx_errors"` + UserWifi1RxFrags float64 `json:"user-wifi1-rx_frags"` + UserWifi1RxPackets float64 `json:"user-wifi1-rx_packets"` + UserWifi1TxBytes float64 `json:"user-wifi1-tx_bytes"` + UserWifi1TxDropped float64 `json:"user-wifi1-tx_dropped"` + UserWifi1TxErrors float64 `json:"user-wifi1-tx_errors"` + UserWifi1TxPackets float64 `json:"user-wifi1-tx_packets"` + UserWifi1TxRetries float64 `json:"user-wifi1-tx_retries"` + Wifi0RxBytes float64 `json:"wifi0-rx_bytes"` + Wifi0RxCrypts float64 `json:"wifi0-rx_crypts"` + Wifi0RxDropped float64 `json:"wifi0-rx_dropped"` + Wifi0RxErrors float64 `json:"wifi0-rx_errors"` + Wifi0RxFrags float64 `json:"wifi0-rx_frags"` + Wifi0RxPackets float64 `json:"wifi0-rx_packets"` + Wifi0TxBytes float64 `json:"wifi0-tx_bytes"` + Wifi0TxDropped float64 `json:"wifi0-tx_dropped"` + Wifi0TxErrors float64 `json:"wifi0-tx_errors"` + Wifi0TxPackets float64 `json:"wifi0-tx_packets"` + Wifi0TxRetries float64 `json:"wifi0-tx_retries"` + Wifi1RxBytes float64 `json:"wifi1-rx_bytes"` + Wifi1RxCrypts float64 `json:"wifi1-rx_crypts"` + Wifi1RxDropped float64 `json:"wifi1-rx_dropped"` + Wifi1RxErrors float64 `json:"wifi1-rx_errors"` + Wifi1RxFrags float64 `json:"wifi1-rx_frags"` + Wifi1RxPackets float64 `json:"wifi1-rx_packets"` + Wifi1TxBytes float64 `json:"wifi1-tx_bytes"` + Wifi1TxDropped float64 `json:"wifi1-tx_dropped"` + Wifi1TxErrors float64 `json:"wifi1-tx_errors"` + Wifi1TxPackets float64 `json:"wifi1-tx_packets"` + Wifi1TxRetries float64 `json:"wifi1-tx_retries"` + } `json:"stat"` + State int `json:"state"` + SysStats struct { + Loadavg1 float64 `json:"loadavg_1,string"` + Loadavg15 float64 `json:"loadavg_15,string"` + Loadavg5 float64 `json:"loadavg_5,string"` + MemBuffer float64 `json:"mem_buffer"` + MemTotal float64 `json:"mem_total"` + MemUsed float64 `json:"mem_used"` + } `json:"sys_stats"` + SystemStats struct { + CPU float64 `json:"cpu,string"` + Mem float64 `json:"mem,string"` + Uptime float64 `json:"uptime,string"` + } `json:"system-stats"` + TxBytes float64 `json:"tx_bytes"` + TxBytesD float64 `json:"tx_bytes-d"` + Type string `json:"type"` + Upgradable bool `json:"upgradable"` + Uplink struct { + FullDuplex bool `json:"full_duplex"` + IP string `json:"ip"` + Mac string `json:"mac"` + MaxSpeed int `json:"max_speed"` + MaxVlan int `json:"max_vlan"` + Media string `json:"media"` + Name string `json:"name"` + Netmask string `json:"netmask"` + NumPort int `json:"num_port"` + RxBytes float64 `json:"rx_bytes"` + RxBytesR float64 `json:"rx_bytes-r"` + RxDropped float64 `json:"rx_dropped"` + RxErrors float64 `json:"rx_errors"` + RxMulticast float64 `json:"rx_multicast"` + RxPackets float64 `json:"rx_packets"` + Speed float64 `json:"speed"` + TxBytes float64 `json:"tx_bytes"` + TxBytesR float64 `json:"tx_bytes-r"` + TxDropped float64 `json:"tx_dropped"` + TxErrors float64 `json:"tx_errors"` + TxPackets float64 `json:"tx_packets"` + Type string `json:"type"` + Up bool `json:"up"` + UplinkMac string `json:"uplink_mac"` + UplinkRemotePort int `json:"uplink_remote_port"` + } `json:"uplink"` + UplinkTable []interface{} `json:"uplink_table"` + Uptime FlexInt `json:"uptime"` + UserNumSta int `json:"user-num_sta"` + VapTable []struct { + ApMac string `json:"ap_mac"` + Bssid string `json:"bssid"` + Ccq int `json:"ccq"` + Channel int `json:"channel"` + Essid string `json:"essid"` + Extchannel int `json:"extchannel"` + ID string `json:"id"` + IsGuest bool `json:"is_guest"` + IsWep bool `json:"is_wep"` + MacFilterRejections int `json:"mac_filter_rejections"` + MapID string `json:"map_id"` + Name string `json:"name"` + NumSta int `json:"num_sta"` + Radio string `json:"radio"` + RadioName string `json:"radio_name"` + RxBytes float64 `json:"rx_bytes"` + RxCrypts float64 `json:"rx_crypts"` + RxDropped float64 `json:"rx_dropped"` + RxErrors float64 `json:"rx_errors"` + RxFrags float64 `json:"rx_frags"` + RxNwids float64 `json:"rx_nwids"` + RxPackets float64 `json:"rx_packets"` + SiteID string `json:"site_id"` + State string `json:"state"` + T string `json:"t"` + TxBytes float64 `json:"tx_bytes"` + TxDropped float64 `json:"tx_dropped"` + TxErrors float64 `json:"tx_errors"` + TxLatencyAvg float64 `json:"tx_latency_avg"` + TxLatencyMax float64 `json:"tx_latency_max"` + TxLatencyMin float64 `json:"tx_latency_min"` + TxPackets float64 `json:"tx_packets"` + TxPower int `json:"tx_power"` + TxRetries int `json:"tx_retries"` + Up bool `json:"up"` + Usage string `json:"usage"` + WlanconfID string `json:"wlanconf_id"` + } `json:"vap_table"` + Version string `json:"version"` + VersionIncompatible bool `json:"version_incompatible"` + VwireEnabled bool `json:"vwireEnabled"` + VwireTable []interface{} `json:"vwire_table"` + VwireVapTable []struct { + Bssid string `json:"bssid"` + Radio string `json:"radio"` + RadioName string `json:"radio_name"` + State string `json:"state"` + } `json:"vwire_vap_table"` + WifiCaps int `json:"wifi_caps"` +} diff --git a/core/unifi/unidev.go b/core/unifi/unidev.go new file mode 100644 index 00000000..34f08254 --- /dev/null +++ b/core/unifi/unidev.go @@ -0,0 +1,105 @@ +package unidev + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "log" + "net/http" + "net/http/cookiejar" + "strconv" + + influx "github.com/influxdata/influxdb/client/v2" + "github.com/pkg/errors" +) + +// LoginPath is Unifi Controller Login API Path +const LoginPath = "/api/login" + +// Asset provides a common interface to retreive metrics from a device or client. +// It currently only supports InfluxDB, but could be amended to support other +// libraries that have a similar interface. +// This app only uses the .AddPoint/s() methods with the Asset type. +type Asset interface { + // Point() means this is useful to influxdb.. + Points() ([]*influx.Point, error) + // Add more methods to achieve more usefulness from this library. +} + +// AuthedReq is what you get in return for providing a password! +type AuthedReq struct { + *http.Client + baseURL string +} + +// FlexInt provides a container and unmarshalling for fields that may be +// numbers or strings in the Unifi API +type FlexInt struct { + Number float64 + String string +} + +// UnmarshalJSON converts a string or number to an integer. +func (f *FlexInt) UnmarshalJSON(b []byte) error { + var unk interface{} + if err := json.Unmarshal(b, &unk); err != nil { + return err + } + switch i := unk.(type) { + case float64: + f.Number = i + f.String = strconv.FormatFloat(i, 'f', -1, 64) + return nil + case string: + f.String = i + f.Number, _ = strconv.ParseFloat(i, 64) + return nil + default: + return errors.New("Cannot unmarshal to FlexInt") + } +} + +// 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) { + json := `{"username": "` + user + `","password": "` + pass + `"}` + jar, err := cookiejar.New(nil) + if err != nil { + return nil, errors.Wrap(err, "cookiejar.New(nil)") + } + a := &AuthedReq{&http.Client{ + Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !verifySSL}}, + Jar: jar, + }, url} + req, err := a.UniReq(LoginPath, json) + if err != nil { + return a, errors.Wrap(err, "UniReq(LoginPath, json)") + } + resp, err := a.Do(req) + if err != nil { + return a, errors.Wrap(err, "authReq.Do(req)") + } + defer func() { + if err := resp.Body.Close(); err != nil { + log.Println("resp.Body.Close():", err) // Not fatal. Just log it. + } + }() + if resp.StatusCode != http.StatusOK { + return a, errors.Errorf("authentication failed (%v): %v (status: %v/%v)", + user, url+LoginPath, resp.StatusCode, resp.Status) + } + return a, 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) { + if params != "" { + req, err = http.NewRequest("POST", a.baseURL+apiPath, bytes.NewBufferString(params)) + } else { + req, err = http.NewRequest("GET", a.baseURL+apiPath, nil) + } + if err == nil { + req.Header.Add("Accept", "application/json") + } + return +} diff --git a/core/unifi/unidev_test.go b/core/unifi/unidev_test.go new file mode 100644 index 00000000..0557934a --- /dev/null +++ b/core/unifi/unidev_test.go @@ -0,0 +1,82 @@ +package unidev + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFlexInt(t *testing.T) { + t.Parallel() + a := assert.New(t) + type testReply struct { + Five FlexInt `json:"five"` + Seven FlexInt `json:"seven"` + Auto FlexInt `json:"auto"` + Channel FlexInt `json:"channel"` + } + var r testReply + // test unmarshalling the custom type three times with different values. + a.Nil(json.Unmarshal([]byte(`{"five": "5", "seven": 7, "auto": "auto"}`), &r)) + + // test number in string. + a.EqualValues(5, r.Five.Number) + a.EqualValues("5", r.Five.String) + // test number. + a.EqualValues(7, r.Seven.Number) + a.EqualValues("7", r.Seven.String) + // test string. + a.EqualValues(0, r.Auto.Number) + a.EqualValues("auto", r.Auto.String) + // test (error) struct. + a.NotNil(json.Unmarshal([]byte(`{"channel": {}}`), &r), + "a non-string and non-number must produce an error.") + a.EqualValues(0, r.Channel.Number) +} + +func TestUniReq(t *testing.T) { + t.Parallel() + a := assert.New(t) + u := "/test/path" + url := "http://some.url:8443" + // Test empty parameters. + authReq := &AuthedReq{&http.Client{}, url} + r, err := authReq.UniReq(u, "") + a.Nil(err, "newrequest must not produce an error") + a.EqualValues(u, r.URL.Path, + "the provided apiPath was not added to http request") + a.EqualValues(url, r.URL.Scheme+"://"+r.URL.Host, "URL improperly encoded") + a.EqualValues("GET", r.Method, "without parameters the method must be GET") + a.EqualValues("application/json", r.Header.Get("Accept"), "Accept header must be set to application/json") + + // Test with parameters + p := "key1=value9&key2=value7" + authReq = &AuthedReq{&http.Client{}, "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, + "the provided apiPath was not added to http request") + a.EqualValues(url, r.URL.Scheme+"://"+r.URL.Host, "URL improperly encoded") + a.EqualValues("POST", r.Method, "with parameters the method must be POST") + a.EqualValues("application/json", r.Header.Get("Accept"), "Accept header must be set to application/json") + // Check the parameters. + d, err := ioutil.ReadAll(r.Body) + a.Nil(err, "problem reading request body, POST parameters may be malformed") + a.EqualValues(p, string(d), "POST parameters improperly encoded") +} + +func TestAuthController(t *testing.T) { + t.Parallel() + a := assert.New(t) + url := "http://127.0.0.1:64431" + authReq, err := AuthController("user1", "pass2", url, false) + a.NotNil(err) + a.EqualValues(url, authReq.baseURL) + a.Contains(err.Error(), "authReq.Do(req):", "an invalid destination should product a .Do(req) error.") + /* TODO: OPEN web server, check parameters posted, more. This test is incomplete. + a.EqualValues(`{"username": "user1","password": "pass2"}`, string(post_params), "user/pass json parameters improperly encoded") + */ +} diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go new file mode 100644 index 00000000..e1f1e6f2 --- /dev/null +++ b/core/unifi/unifi.go @@ -0,0 +1,154 @@ +package unidev + +import ( + "encoding/json" + "io/ioutil" + "log" + + "github.com/pkg/errors" +) + +// Debug .... +var Debug = false + +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) { + var response struct { + Clients []UCL `json:"data"` + Meta struct { + Rc string `json:"rc"` + } `json:"meta"` + } + req, err := c.UniReq(ClientPath, "") + if err != nil { + return nil, errors.Wrap(err, "c.UniReq(ClientPath)") + } + resp, err := c.Do(req) + if err != nil { + return nil, errors.Wrap(err, "c.Do(req)") + } + defer func() { + if err := resp.Body.Close(); err != nil { + log.Println("resp.Body.Close():", err) // Not fatal? Just log it. + } + }() + if body, err := ioutil.ReadAll(resp.Body); err != nil { + return nil, errors.Wrap(err, "ioutil.ReadAll(resp.Body)") + } else if err = json.Unmarshal(body, &response); err != nil { + return nil, errors.Wrap(err, "json.Unmarshal([]UCL)") + } + return response.Clients, nil +} + +// GetUnifiClientAssets provides an interface to return common asset types. +func (c *AuthedReq) GetUnifiClientAssets() ([]Asset, error) { + clients, err := c.GetUnifiClients() + assets := []Asset{} + if err == nil { + for _, r := range clients { + assets = append(assets, r) + } + } + return assets, err +} + +// GetUnifiDevices returns a response full of devices' data from the Unifi Controller. +func (c *AuthedReq) GetUnifiDevices() ([]USG, []USW, []UAP, error) { + var parsed struct { + Data []json.RawMessage `json:"data"` + Meta struct { + Rc string `json:"rc"` + } `json:"meta"` + } + req, err := c.UniReq(DevicePath, "") + if err != nil { + return nil, nil, nil, errors.Wrap(err, "c.UniReq(DevicePath)") + } + resp, err := c.Do(req) + if err != nil { + return nil, nil, nil, errors.Wrap(err, "c.Do(req)") + } + defer func() { + if err := resp.Body.Close(); err != nil { + log.Println("resp.Body.Close():", err) // Not fatal? Just log it. + } + }() + if body, err := ioutil.ReadAll(resp.Body); err != nil { + return nil, nil, nil, errors.Wrap(err, "ioutil.ReadAll(resp.Body)") + } else if err = json.Unmarshal(body, &parsed); err != nil { + return nil, nil, nil, errors.Wrap(err, "json.Unmarshal([]json.RawMessage)") + } + + var usgs []USG + var usws []USW + var uaps []UAP + // Loop each item in the raw JSON message, detect its type and unmarshal it. + for i, r := range parsed.Data { + var usg USG + var usw USW + var uap UAP + // Unamrshal into a map and check "type" + var obj map[string]interface{} + if err := json.Unmarshal(r, &obj); err != nil { + return nil, nil, nil, errors.Wrapf(err, "[%d] json.Unmarshal(interfce{})", i) + } + assetType := "" + if t, ok := obj["type"].(string); ok { + assetType = t + } + if Debug { + log.Println("Unmarshalling Device Type:", assetType) + } + // Unmarshal again into the correct type.. + switch assetType { + case "uap": + if err := json.Unmarshal(r, &uap); err != nil { + return nil, nil, nil, errors.Wrapf(err, "[%d] json.Unmarshal([]UAP)", i) + } + uaps = append(uaps, uap) + case "ugw", "usg": // in case they ever fix the name in the api. + if err := json.Unmarshal(r, &usg); err != nil { + return nil, nil, nil, errors.Wrapf(err, "[%d] json.Unmarshal([]USG)", i) + } + usgs = append(usgs, usg) + case "usw": + if err := json.Unmarshal(r, &usw); err != nil { + return nil, nil, nil, errors.Wrapf(err, "[%d] json.Unmarshal([]USW)", i) + } + usws = append(usws, usw) + default: + log.Println("unknown asset type -", assetType, "- skipping") + continue + } + } + return usgs, usws, uaps, nil +} + +// GetUnifiDeviceAssets provides an interface to return common asset types. +func (c *AuthedReq) GetUnifiDeviceAssets() ([]Asset, error) { + usgs, usws, uaps, err := c.GetUnifiDevices() + assets := []Asset{} + if err == nil { + for _, r := range usgs { + assets = append(assets, r) + } + for _, r := range usws { + assets = append(assets, r) + } + for _, r := range uaps { + assets = append(assets, r) + } + } + return assets, err +} diff --git a/core/unifi/usg.go b/core/unifi/usg.go new file mode 100644 index 00000000..a8123705 --- /dev/null +++ b/core/unifi/usg.go @@ -0,0 +1,186 @@ +package unidev + +import ( + "strconv" + "time" + + influx "github.com/influxdata/influxdb/client/v2" +) + +// Points generates a device's datapoints for InfluxDB. +func (u USG) Points() ([]*influx.Point, error) { + var points []*influx.Point + tags := map[string]string{ + "id": u.ID, + "mac": u.Mac, + "device_type": u.Stat.O, + "device_oid": u.Stat.Oid, + "site_id": u.SiteID, + "addopted": strconv.FormatBool(u.Adopted), + "name": u.Name, + "adopt_ip": u.AdoptIP, + "adopt_url": u.AdoptURL, + "cfgversion": u.Cfgversion, + "config_network_ip": u.ConfigNetwork.IP, + "config_network_type": u.ConfigNetwork.Type, + "connect_request_ip": u.ConnectRequestIP, + "connect_request_port": u.ConnectRequestPort, + "default": strconv.FormatBool(u.Default), + "device_id": u.DeviceID, + "discovered_via": u.DiscoveredVia, + "guest_token": u.GuestToken, + "inform_ip": u.InformIP, + "known_cfgversion": u.KnownCfgversion, + "led_override": u.LedOverride, + "locating": strconv.FormatBool(u.Locating), + "model": u.Model, + "outdoor_mode_override": u.OutdoorModeOverride, + "serial": u.Serial, + "type": u.Type, + "version_incompatible": strconv.FormatBool(u.VersionIncompatible), + "usg_caps": strconv.FormatFloat(u.UsgCaps, 'f', 6, 64), + "speedtest-status-saved": strconv.FormatBool(u.SpeedtestStatusSaved), + } + fields := map[string]interface{}{ + "ip": u.IP, + "bytes": u.Bytes, + "last_seen": u.LastSeen, + "license_state": u.LicenseState, + "fw_caps": u.FwCaps, + "guest-num_sta": u.GuestNumSta, + "rx_bytes": u.RxBytes, + "tx_bytes": u.TxBytes, + "uptime": u.Uptime, + "considered_lost_at": u.ConsideredLostAt, + "next_heartbeat_at": u.NextHeartbeatAt, + "roll_upgrade": u.Rollupgrade, + "state": u.State, + "upgradable": u.Upgradable, + "user-num_sta": u.UserNumSta, + "version": u.Version, + "num_desktop": u.NumDesktop, + "num_handheld": u.NumHandheld, + "num_mobile": u.NumMobile, + "speedtest-status_latency": u.SpeedtestStatus.Latency, + "speedtest-status_rundate": u.SpeedtestStatus.Rundate, + "speedtest-status_runtime": u.SpeedtestStatus.Runtime, + "speedtest-status_download": u.SpeedtestStatus.StatusDownload, + "speedtest-status_ping": u.SpeedtestStatus.StatusPing, + "speedtest-status_summary": u.SpeedtestStatus.StatusSummary, + "speedtest-status_upload": u.SpeedtestStatus.StatusUpload, + "speedtest-status_xput_download": u.SpeedtestStatus.XputDownload, + "speedtest-status_xput_upload": u.SpeedtestStatus.XputUpload, + // have two WANs? mmmm, go ahead and add it. ;) + "config_network_wan_type": u.ConfigNetworkWan.Type, + "wan1_bytes-r": u.Wan1.BytesR, + "wan1_enable": u.Wan1.Enable, + "wan1_full_duplex": u.Wan1.FullDuplex, + "wan1_purpose": "uplink", // because it should have a purpose. + "wan1_gateway": u.Wan1.Gateway, + "wan1_ifname": u.Wan1.Ifname, + "wan1_ip": u.Wan1.IP, + "wan1_mac": u.Wan1.Mac, + "wan1_max_speed": u.Wan1.MaxSpeed, + "wan1_name": u.Wan1.Name, + "wan1_netmask": u.Wan1.Netmask, + "wan1_rx_bytes": u.Wan1.RxBytes, + "wan1_rx_bytes-r": u.Wan1.RxBytesR, + "wan1_rx_dropped": u.Wan1.RxDropped, + "wan1_rx_errors": u.Wan1.RxErrors, + "wan1_rx_multicast": u.Wan1.RxMulticast, + "wan1_rx_packets": u.Wan1.RxPackets, + "wan1_type": u.Wan1.Type, + "wan1_speed": u.Wan1.Speed, + "wan1_up": u.Wan1.Up, + "wan1_tx_bytes": u.Wan1.TxBytes, + "wan1_tx_bytes-r": u.Wan1.TxBytesR, + "wan1_tx_dropped": u.Wan1.TxDropped, + "wan1_tx_errors": u.Wan1.TxErrors, + "wan1_tx_packets": u.Wan1.TxPackets, + "loadavg_1": u.SysStats.Loadavg1, + "loadavg_5": u.SysStats.Loadavg5, + "loadavg_15": u.SysStats.Loadavg15, + "mem_used": u.SysStats.MemUsed, + "mem_buffer": u.SysStats.MemBuffer, + "mem_total": u.SysStats.MemTotal, + "cpu": u.SystemStats.CPU, + "mem": u.SystemStats.Mem, + "system_uptime": u.SystemStats.Uptime, + "stat_duration": u.Stat.Duration, + "stat_datetime": u.Stat.Datetime, + "gw": u.Stat.Gw, + "false": "false", // to fill holes in graphs. + "lan-rx_bytes": u.Stat.LanRxBytes, + "lan-rx_packets": u.Stat.LanRxPackets, + "lan-tx_bytes": u.Stat.LanTxBytes, + "lan-tx_packets": u.Stat.LanTxPackets, + "wan-rx_bytes": u.Stat.WanRxBytes, + "wan-rx_dropped": u.Stat.WanRxDropped, + "wan-rx_packets": u.Stat.WanRxPackets, + "wan-tx_bytes": u.Stat.WanTxBytes, + "wan-tx_packets": u.Stat.WanTxPackets, + "uplink_name": u.Uplink.Name, + "uplink_latency": u.Uplink.Latency, + "uplink_speed": u.Uplink.Speed, + "uplink_num_ports": u.Uplink.NumPort, + "uplink_max_speed": u.Uplink.MaxSpeed, + } + pt, err := influx.NewPoint("usg", tags, fields, time.Now()) + if err != nil { + return nil, err + } + points = append(points, pt) + for _, p := range u.NetworkTable { + tags := map[string]string{ + "device_name": u.Name, + "device_id": u.ID, + "device_mac": u.Mac, + "name": p.Name, + "dhcpd_dns_enabled": strconv.FormatBool(p.DhcpdDNSEnabled), + "dhcpd_enabled": strconv.FormatBool(p.DhcpdEnabled), + "dhcpd_ntp_enabled": strconv.FormatBool(p.DhcpdNtpEnabled), + "dhcpd_time_offset_enabled": strconv.FormatBool(p.DhcpdTimeOffsetEnabled), + "dhcp_relay_enabledy": strconv.FormatBool(p.DhcpRelayEnabled), + "dhcpd_gateway_enabled": strconv.FormatBool(p.DhcpdGatewayEnabled), + "dhcpd_wins_enabled": strconv.FormatBool(p.DhcpdWinsEnabled), + "dhcpguard_enabled": strconv.FormatBool(p.DhcpguardEnabled), + "enabled": strconv.FormatBool(p.Enabled), + "vlan_enabled": strconv.FormatBool(p.VlanEnabled), + "attr_no_delete": strconv.FormatBool(p.AttrNoDelete), + "upnp_lan_enabled": strconv.FormatBool(p.UpnpLanEnabled), + "igmp_snooping": strconv.FormatBool(p.IgmpSnooping), + "is_guest": strconv.FormatBool(p.IsGuest), + "is_nat": strconv.FormatBool(p.IsNat), + "networkgroup": p.Networkgroup, + "site_id": p.SiteID, + } + fields := map[string]interface{}{ + "dhcpd_ip_1": p.DhcpdIP1, + "domain_name": p.DomainName, + "dhcpd_start": p.DhcpdStart, + "dhcpd_stop": p.DhcpdStop, + "ip": p.IP, + "ip_subnet": p.IPSubnet, + "mac": p.Mac, + "name": p.Name, + "num_sta": p.NumSta, + "purpose": p.Purpose, + "rx_bytes": p.RxBytes, + "rx_packets": p.RxPackets, + "tx_bytes": p.TxBytes, + "tx_packets": p.TxPackets, + "up": p.Up, + "vlan": p.Vlan, + "dhcpd_ntp_1": p.DhcpdNtp1, + "dhcpd_unifi_controller": p.DhcpdUnifiController, + "ipv6_interface_type": p.Ipv6InterfaceType, + "attr_hidden_id": p.AttrHiddenID, + } + pt, err = influx.NewPoint("usg_networks", tags, fields, time.Now()) + if err != nil { + return points, err + } + points = append(points, pt) + } + return points, err +} diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go new file mode 100644 index 00000000..d5a7d15a --- /dev/null +++ b/core/unifi/usg_type.go @@ -0,0 +1,260 @@ +package unidev + +import "encoding/json" + +// USG is a Unifi Security Gateway +type USG struct { + ID string `json:"_id"` + UUptime float64 `json:"_uptime"` + AdoptIP string `json:"adopt_ip"` + AdoptURL string `json:"adopt_url"` + Adopted bool `json:"adopted"` + Bytes float64 `json:"bytes"` + Cfgversion string `json:"cfgversion"` + ConfigNetwork struct { + IP string `json:"ip"` + Type string `json:"type"` + } `json:"config_network"` + ConfigNetworkWan struct { + Type string `json:"type"` + } `json:"config_network_wan"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + ConsideredLostAt float64 `json:"considered_lost_at"` + Default bool `json:"default"` + DeviceID string `json:"device_id"` + DiscoveredVia string `json:"discovered_via"` + EthernetTable []struct { + Mac string `json:"mac"` + Name string `json:"name"` + NumPort float64 `json:"num_port"` + } `json:"ethernet_table"` + FwCaps float64 `json:"fw_caps"` + GuestNumSta float64 `json:"guest-num_sta"` + GuestToken string `json:"guest_token"` + InformIP string `json:"inform_ip"` + InformURL string `json:"inform_url"` + IP string `json:"ip"` + KnownCfgversion string `json:"known_cfgversion"` + LastSeen float64 `json:"last_seen"` + LedOverride string `json:"led_override"` + LicenseState string `json:"license_state"` + Locating bool `json:"locating"` + Mac string `json:"mac"` + Model string `json:"model"` + Name string `json:"name"` + NetworkTable []struct { + ID string `json:"_id"` + DhcpdDNSEnabled bool `json:"dhcpd_dns_enabled"` + DhcpdEnabled bool `json:"dhcpd_enabled"` + DhcpdIP1 string `json:"dhcpd_ip_1,omitempty"` + DhcpdLeasetime json.Number `json:"dhcpd_leasetime,Number"` + DhcpdStart string `json:"dhcpd_start"` + DhcpdStop string `json:"dhcpd_stop"` + DhcpdWinsEnabled bool `json:"dhcpd_wins_enabled,omitempty"` + DhcpguardEnabled bool `json:"dhcpguard_enabled,omitempty"` + DomainName string `json:"domain_name"` + Enabled bool `json:"enabled"` + IgmpSnooping bool `json:"igmp_snooping,omitempty"` + IP string `json:"ip"` + IPSubnet string `json:"ip_subnet"` + IsGuest bool `json:"is_guest"` + IsNat bool `json:"is_nat"` + Mac string `json:"mac"` + Name string `json:"name"` + Networkgroup string `json:"networkgroup"` + NumSta float64 `json:"num_sta"` + Purpose string `json:"purpose"` + RxBytes float64 `json:"rx_bytes"` + RxPackets float64 `json:"rx_packets"` + SiteID string `json:"site_id"` + TxBytes float64 `json:"tx_bytes"` + TxPackets float64 `json:"tx_packets"` + Up string `json:"up"` + Vlan string `json:"vlan,omitempty"` + VlanEnabled bool `json:"vlan_enabled"` + DhcpRelayEnabled bool `json:"dhcp_relay_enabled,omitempty"` + DhcpdGatewayEnabled bool `json:"dhcpd_gateway_enabled,omitempty"` + DhcpdNtp1 string `json:"dhcpd_ntp_1,omitempty"` + DhcpdNtpEnabled bool `json:"dhcpd_ntp_enabled,omitempty"` + DhcpdTimeOffsetEnabled bool `json:"dhcpd_time_offset_enabled,omitempty"` + DhcpdUnifiController string `json:"dhcpd_unifi_controller,omitempty"` + Ipv6InterfaceType string `json:"ipv6_interface_type,omitempty"` + AttrHiddenID string `json:"attr_hidden_id,omitempty"` + AttrNoDelete bool `json:"attr_no_delete,omitempty"` + UpnpLanEnabled bool `json:"upnp_lan_enabled,omitempty"` + } `json:"network_table"` + NextHeartbeatAt float64 `json:"next_heartbeat_at"` + NumDesktop float64 `json:"num_desktop"` + NumHandheld float64 `json:"num_handheld"` + NumMobile float64 `json:"num_mobile"` + NumSta float64 `json:"num_sta"` + OutdoorModeOverride string `json:"outdoor_mode_override"` + PortTable []struct { + DNS []string `json:"dns,omitempty"` + Enable bool `json:"enable"` + FullDuplex bool `json:"full_duplex"` + Gateway string `json:"gateway,omitempty"` + Ifname string `json:"ifname"` + IP string `json:"ip"` + Mac string `json:"mac"` + Name string `json:"name"` + Netmask string `json:"netmask"` + RxBytes float64 `json:"rx_bytes"` + RxDropped float64 `json:"rx_dropped"` + RxErrors float64 `json:"rx_errors"` + RxMulticast float64 `json:"rx_multicast"` + RxPackets float64 `json:"rx_packets"` + Speed float64 `json:"speed"` + TxBytes float64 `json:"tx_bytes"` + TxDropped float64 `json:"tx_dropped"` + TxErrors float64 `json:"tx_errors"` + TxPackets float64 `json:"tx_packets"` + Up bool `json:"up"` + } `json:"port_table"` + Rollupgrade bool `json:"rollupgrade"` + RxBytes float64 `json:"rx_bytes"` + Serial string `json:"serial"` + SiteID string `json:"site_id"` + SpeedtestStatus struct { + Latency float64 `json:"latency"` + Rundate float64 `json:"rundate"` + Runtime float64 `json:"runtime"` + StatusDownload float64 `json:"status_download"` + StatusPing float64 `json:"status_ping"` + StatusSummary float64 `json:"status_summary"` + StatusUpload float64 `json:"status_upload"` + XputDownload float64 `json:"xput_download"` + XputUpload float64 `json:"xput_upload"` + } `json:"speedtest-status"` + SpeedtestStatusSaved bool `json:"speedtest-status-saved"` + Stat struct { + Datetime string `json:"datetime"` + Duration float64 `json:"duration"` + Gw string `json:"gw"` + LanRxBytes float64 `json:"lan-rx_bytes"` + LanRxPackets float64 `json:"lan-rx_packets"` + LanTxBytes float64 `json:"lan-tx_bytes"` + LanTxPackets float64 `json:"lan-tx_packets"` + O string `json:"o"` + Oid string `json:"oid"` + SiteID string `json:"site_id"` + Time float64 `json:"time"` + WanRxBytes float64 `json:"wan-rx_bytes"` + WanRxDropped float64 `json:"wan-rx_dropped"` + WanRxPackets float64 `json:"wan-rx_packets"` + WanTxBytes float64 `json:"wan-tx_bytes"` + WanTxPackets float64 `json:"wan-tx_packets"` + } `json:"stat"` + State float64 `json:"state"` + SysStats struct { + Loadavg1 float64 `json:"loadavg_1,string"` + Loadavg15 float64 `json:"loadavg_15,string"` + Loadavg5 float64 `json:"loadavg_5,string"` + MemBuffer float64 `json:"mem_buffer"` + MemTotal float64 `json:"mem_total"` + MemUsed float64 `json:"mem_used"` + } `json:"sys_stats"` + SystemStats struct { + CPU float64 `json:"cpu,string"` + Mem float64 `json:"mem,string"` + Uptime float64 `json:"uptime,string"` + } `json:"system-stats"` + TxBytes float64 `json:"tx_bytes"` + Type string `json:"type"` + Upgradable bool `json:"upgradable"` + Uplink struct { + BytesR float64 `json:"bytes-r"` + Drops float64 `json:"drops"` + Enable bool `json:"enable"` + FullDuplex bool `json:"full_duplex"` + Gateways []string `json:"gateways"` + IP string `json:"ip"` + Latency float64 `json:"latency"` + Mac string `json:"mac"` + MaxSpeed float64 `json:"max_speed"` + Name string `json:"name"` + Nameservers []string `json:"nameservers"` + Netmask string `json:"netmask"` + NumPort float64 `json:"num_port"` + RxBytes float64 `json:"rx_bytes"` + RxBytesR float64 `json:"rx_bytes-r"` + RxDropped float64 `json:"rx_dropped"` + RxErrors float64 `json:"rx_errors"` + RxMulticast float64 `json:"rx_multicast"` + RxPackets float64 `json:"rx_packets"` + Speed float64 `json:"speed"` + SpeedtestLastrun float64 `json:"speedtest_lastrun"` + SpeedtestPing float64 `json:"speedtest_ping"` + SpeedtestStatus string `json:"speedtest_status"` + TxBytes float64 `json:"tx_bytes"` + TxBytesR float64 `json:"tx_bytes-r"` + TxDropped float64 `json:"tx_dropped"` + TxErrors float64 `json:"tx_errors"` + TxPackets float64 `json:"tx_packets"` + Type string `json:"type"` + Up bool `json:"up"` + Uptime float64 `json:"uptime"` + XputDown float64 `json:"xput_down"` + XputUp float64 `json:"xput_up"` + } `json:"uplink"` + Uptime float64 `json:"uptime"` + UserNumSta float64 `json:"user-num_sta"` + UsgCaps float64 `json:"usg_caps"` + Version string `json:"version"` + VersionIncompatible bool `json:"version_incompatible"` + Wan1 struct { + BytesR float64 `json:"bytes-r"` + DNS []string `json:"dns"` + Enable bool `json:"enable"` + FullDuplex bool `json:"full_duplex"` + Gateway string `json:"gateway"` + Ifname string `json:"ifname"` + IP string `json:"ip"` + Mac string `json:"mac"` + MaxSpeed float64 `json:"max_speed"` + Name string `json:"name"` + Netmask string `json:"netmask"` + RxBytes float64 `json:"rx_bytes"` + RxBytesR float64 `json:"rx_bytes-r"` + RxDropped float64 `json:"rx_dropped"` + RxErrors float64 `json:"rx_errors"` + RxMulticast float64 `json:"rx_multicast"` + RxPackets float64 `json:"rx_packets"` + Speed float64 `json:"speed"` + TxBytes float64 `json:"tx_bytes"` + TxBytesR float64 `json:"tx_bytes-r"` + TxDropped float64 `json:"tx_dropped"` + TxErrors float64 `json:"tx_errors"` + TxPackets float64 `json:"tx_packets"` + Type string `json:"type"` + Up bool `json:"up"` + } `json:"wan1"` + Wan2 struct { + BytesR float64 `json:"bytes-r"` + DNS []string `json:"dns"` + Enable bool `json:"enable"` + FullDuplex bool `json:"full_duplex"` + Gateway string `json:"gateway"` + Ifname string `json:"ifname"` + IP string `json:"ip"` + Mac string `json:"mac"` + MaxSpeed float64 `json:"max_speed"` + Name string `json:"name"` + Netmask string `json:"netmask"` + RxBytes float64 `json:"rx_bytes"` + RxBytesR float64 `json:"rx_bytes-r"` + RxDropped float64 `json:"rx_dropped"` + RxErrors float64 `json:"rx_errors"` + RxMulticast float64 `json:"rx_multicast"` + RxPackets float64 `json:"rx_packets"` + Speed float64 `json:"speed"` + TxBytes float64 `json:"tx_bytes"` + TxBytesR float64 `json:"tx_bytes-r"` + TxDropped float64 `json:"tx_dropped"` + TxErrors float64 `json:"tx_errors"` + TxPackets float64 `json:"tx_packets"` + Type string `json:"type"` + Up bool `json:"up"` + } `json:"wan2"` +} diff --git a/core/unifi/usw.go b/core/unifi/usw.go new file mode 100644 index 00000000..5a2e491e --- /dev/null +++ b/core/unifi/usw.go @@ -0,0 +1,118 @@ +package unidev + +import ( + "strconv" + "time" + + influx "github.com/influxdata/influxdb/client/v2" +) + +// Points generates a device's datapoints for InfluxDB. +func (u USW) Points() ([]*influx.Point, error) { + var points []*influx.Point + tags := map[string]string{ + "id": u.ID, + "mac": u.Mac, + "device_type": u.Stat.O, + "device_oid": u.Stat.Oid, + "site_id": u.SiteID, + "name": u.Name, + "addopted": strconv.FormatBool(u.Adopted), + "adopt_ip": u.AdoptIP, + "adopt_url": u.AdoptURL, + "cfgversion": u.Cfgversion, + "config_network_ip": u.ConfigNetwork.IP, + "config_network_type": u.ConfigNetwork.Type, + "connect_request_ip": u.ConnectRequestIP, + "connect_request_port": u.ConnectRequestPort, + "default": strconv.FormatBool(u.Default), + "device_id": u.DeviceID, + "discovered_via": u.DiscoveredVia, + "inform_ip": u.InformIP, + "last_uplink_mac": u.LastUplink.UplinkMac, + "known_cfgversion": u.KnownCfgversion, + "led_override": u.LedOverride, + "locating": strconv.FormatBool(u.Locating), + "model": u.Model, + "outdoor_mode_override": u.OutdoorModeOverride, + "serial": u.Serial, + "type": u.Type, + "version_incompatible": strconv.FormatBool(u.VersionIncompatible), + "dot1x_portctrl_enabled": strconv.FormatBool(u.Dot1XPortctrlEnabled), + "flowctrl_enabled": strconv.FormatBool(u.FlowctrlEnabled), + "has_fan": strconv.FormatBool(u.HasFan), + "has_temperature": strconv.FormatBool(u.HasTemperature), + "jumboframe_enabled": strconv.FormatBool(u.JumboframeEnabled), + "stp_priority": u.StpPriority, + "stp_version": u.StpVersion, + } + fields := map[string]interface{}{ + "fw_caps": u.FwCaps, + "guest-num_sta": u.GuestNumSta, + "ip": u.IP, + "bytes": u.Bytes, + "fan_level": u.FanLevel, + "general_temperature": u.GeneralTemperature, + "last_seen": u.LastSeen, + "license_state": u.LicenseState, + "overheating": u.Overheating, + "rx_bytes": u.RxBytes, + "tx_bytes": u.TxBytes, + "uptime": u.Uptime, + "considered_lost_at": u.ConsideredLostAt, + "next_heartbeat_at": u.NextHeartbeatAt, + "roll_upgrade": u.Rollupgrade, + "state": u.State, + "upgradable": u.Upgradable, + "user-num_sta": u.UserNumSta, + "version": u.Version, + "loadavg_1": u.SysStats.Loadavg1, + "loadavg_5": u.SysStats.Loadavg5, + "loadavg_15": u.SysStats.Loadavg15, + "mem_buffer": u.SysStats.MemBuffer, + "mem_used": u.SysStats.MemUsed, + "mem_total": u.SysStats.MemTotal, + "cpu": u.SystemStats.CPU, + "mem": u.SystemStats.Mem, + "system_uptime": u.SystemStats.Uptime, + "stat_bytes": u.Stat.Bytes, + "stat_duration": u.Stat.Duration, + "stat_guest-rx_bytes": u.Stat.RxBytes, + "stat_guest-rx_crypts": u.Stat.RxCrypts, + "stat_guest-rx_dropped": u.Stat.RxDropped, + "stat_guest-rx_errors": u.Stat.RxErrors, + "stat_guest-rx_frags": u.Stat.RxFrags, + "stat_guest-rx_packets": u.Stat.RxPackets, + "stat_guest-tx_bytes": u.Stat.TxBytes, + "stat_guest-tx_dropped": u.Stat.TxDropped, + "stat_guest-tx_errors": u.Stat.TxErrors, + "stat_guest-tx_packets": u.Stat.TxPackets, + "stat_guest-tx_retries": u.Stat.TxRetries, + "stat_port_1-rx_broadcast": u.Stat.Port1RxBroadcast, + "stat_port_1-rx_bytes": u.Stat.Port1RxBytes, + "stat_port_1-rx_multicast": u.Stat.Port1RxMulticast, + "stat_port_1-rx_packets": u.Stat.Port1RxPackets, + "stat_port_1-tx_broadcast": u.Stat.Port1TxBroadcast, + "stat_port_1-tx_bytes": u.Stat.Port1TxBytes, + "stat_port_1-tx_multicast": u.Stat.Port1TxMulticast, + "stat_port_1-tx_packets": u.Stat.Port1TxPackets, + "stat_rx_bytes": u.Stat.RxBytes, + "stat_rx_crypts": u.Stat.RxCrypts, + "stat_rx_dropped": u.Stat.RxDropped, + "stat_rx_errors": u.Stat.RxErrors, + "stat_rx_frags": u.Stat.RxFrags, + "stat_rx_packets": u.Stat.TxPackets, + "stat_tx_bytes": u.Stat.TxBytes, + "stat_tx_dropped": u.Stat.TxDropped, + "stat_tx_errors": u.Stat.TxErrors, + "stat_tx_packets": u.Stat.TxPackets, + "stat_tx_retries": u.Stat.TxRetries, + "uplink_depth": strconv.FormatFloat(u.UplinkDepth, 'f', 6, 64), + // Add the port stats too. + } + pt, err := influx.NewPoint("usw", tags, fields, time.Now()) + if err == nil { + points = append(points, pt) + } + return points, err +} diff --git a/core/unifi/usw_type.go b/core/unifi/usw_type.go new file mode 100644 index 00000000..0b61ce17 --- /dev/null +++ b/core/unifi/usw_type.go @@ -0,0 +1,415 @@ +package unidev + +// USW is a Unifi Switch +type USW struct { + ID string `json:"_id"` + UUptime float64 `json:"_uptime"` + AdoptIP string `json:"adopt_ip"` + AdoptURL string `json:"adopt_url"` + Adopted bool `json:"adopted"` + BoardRev float64 `json:"board_rev"` + Bytes float64 `json:"bytes"` + Cfgversion string `json:"cfgversion"` + ConfigNetwork struct { + IP string `json:"ip"` + Type string `json:"type"` + } `json:"config_network"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + ConsideredLostAt float64 `json:"considered_lost_at"` + Default bool `json:"default"` + DeviceID string `json:"device_id"` + DhcpServerTable []interface{} `json:"dhcp_server_table"` + DiscoveredVia string `json:"discovered_via"` + Dot1XPortctrlEnabled bool `json:"dot1x_portctrl_enabled"` + DownlinkTable []struct { + FullDuplex bool `json:"full_duplex"` + Mac string `json:"mac"` + PortIdx float64 `json:"port_idx"` + Speed float64 `json:"speed"` + } `json:"downlink_table"` + EthernetTable []struct { + Mac string `json:"mac"` + Name string `json:"name"` + NumPort float64 `json:"num_port,omitempty"` + } `json:"ethernet_table"` + FanLevel float64 `json:"fan_level"` + FlowctrlEnabled bool `json:"flowctrl_enabled"` + FwCaps float64 `json:"fw_caps"` + GeneralTemperature float64 `json:"general_temperature"` + GuestNumSta float64 `json:"guest-num_sta"` + HasFan bool `json:"has_fan"` + HasTemperature bool `json:"has_temperature"` + InformIP string `json:"inform_ip"` + InformURL string `json:"inform_url"` + IP string `json:"ip"` + JumboframeEnabled bool `json:"jumboframe_enabled"` + KnownCfgversion string `json:"known_cfgversion"` + LastSeen float64 `json:"last_seen"` + LastUplink struct { + UplinkMac string `json:"uplink_mac"` + } `json:"last_uplink"` + LedOverride string `json:"led_override"` + LicenseState string `json:"license_state"` + Locating bool `json:"locating"` + Mac string `json:"mac"` + Model string `json:"model"` + Name string `json:"name"` + NextHeartbeatAt float64 `json:"next_heartbeat_at"` + NumSta float64 `json:"num_sta"` + OutdoorModeOverride string `json:"outdoor_mode_override"` + Overheating bool `json:"overheating"` + PortOverrides []struct { + Name string `json:"name,omitempty"` + PoeMode string `json:"poe_mode,omitempty"` + PortIdx float64 `json:"port_idx"` + PortconfID string `json:"portconf_id"` + } `json:"port_overrides"` + PortTable []struct { + AggregatedBy bool `json:"aggregated_by"` + Autoneg bool `json:"autoneg"` + BytesR float64 `json:"bytes-r"` + Dot1XMode string `json:"dot1x_mode"` + Dot1XStatus string `json:"dot1x_status"` + Enable bool `json:"enable"` + FlowctrlRx bool `json:"flowctrl_rx"` + FlowctrlTx bool `json:"flowctrl_tx"` + FullDuplex bool `json:"full_duplex"` + IsUplink bool `json:"is_uplink"` + Jumbo bool `json:"jumbo"` + LldpTable []interface{} `json:"lldp_table"` + Masked bool `json:"masked"` + Media string `json:"media"` + Name string `json:"name"` + OpMode string `json:"op_mode"` + PoeCaps float64 `json:"poe_caps"` + PoeClass string `json:"poe_class,omitempty"` + PoeCurrent string `json:"poe_current,omitempty"` + PoeEnable bool `json:"poe_enable,omitempty"` + PoeGood bool `json:"poe_good,omitempty"` + PoeMode string `json:"poe_mode,omitempty"` + PoePower string `json:"poe_power,omitempty"` + PoeVoltage string `json:"poe_voltage,omitempty"` + PortIdx float64 `json:"port_idx"` + PortPoe bool `json:"port_poe"` + PortconfID string `json:"portconf_id"` + RxBroadcast float64 `json:"rx_broadcast"` + RxBytes float64 `json:"rx_bytes"` + RxBytesR float64 `json:"rx_bytes-r"` + RxDropped float64 `json:"rx_dropped"` + RxErrors float64 `json:"rx_errors"` + RxMulticast float64 `json:"rx_multicast"` + RxPackets float64 `json:"rx_packets"` + Speed float64 `json:"speed"` + StpPathcost float64 `json:"stp_pathcost"` + StpState string `json:"stp_state"` + TxBroadcast float64 `json:"tx_broadcast"` + TxBytes float64 `json:"tx_bytes"` + TxBytesR float64 `json:"tx_bytes-r"` + TxDropped float64 `json:"tx_dropped"` + TxErrors float64 `json:"tx_errors"` + TxMulticast float64 `json:"tx_multicast"` + TxPackets float64 `json:"tx_packets"` + Up bool `json:"up"` + SfpFound bool `json:"sfp_found,omitempty"` + } `json:"port_table"` + Rollupgrade bool `json:"rollupgrade"` + RxBytes float64 `json:"rx_bytes"` + Serial string `json:"serial"` + SiteID string `json:"site_id"` + SSHSessionTable []interface{} `json:"ssh_session_table"` + + Stat struct { + Bytes float64 `json:"bytes"` + Datetime string `json:"datetime"` + Duration float64 `json:"duration"` + O string `json:"o"` + Oid string `json:"oid"` + Port1RxBroadcast float64 `json:"port_1-rx_broadcast"` + Port1RxBytes float64 `json:"port_1-rx_bytes"` + Port1RxDropped float64 `json:"port_1-rx_dropped"` + Port1RxMulticast float64 `json:"port_1-rx_multicast"` + Port1RxPackets float64 `json:"port_1-rx_packets"` + Port1TxBroadcast float64 `json:"port_1-tx_broadcast"` + Port1TxBytes float64 `json:"port_1-tx_bytes"` + Port1TxMulticast float64 `json:"port_1-tx_multicast"` + Port1TxPackets float64 `json:"port_1-tx_packets"` + Port2RxBroadcast float64 `json:"port_2-rx_broadcast"` + Port2RxBytes float64 `json:"port_2-rx_bytes"` + Port2RxDropped float64 `json:"port_2-rx_dropped"` + Port2RxMulticast float64 `json:"port_2-rx_multicast"` + Port2RxPackets float64 `json:"port_2-rx_packets"` + Port2TxBroadcast float64 `json:"port_2-tx_broadcast"` + Port2TxBytes float64 `json:"port_2-tx_bytes"` + Port2TxMulticast float64 `json:"port_2-tx_multicast"` + Port2TxPackets float64 `json:"port_2-tx_packets"` + Port3RxBroadcast float64 `json:"port_3-rx_broadcast"` + Port3RxBytes float64 `json:"port_3-rx_bytes"` + Port3RxDropped float64 `json:"port_3-rx_dropped"` + Port3RxMulticast float64 `json:"port_3-rx_multicast"` + Port3RxPackets float64 `json:"port_3-rx_packets"` + Port3TxBroadcast float64 `json:"port_3-tx_broadcast"` + Port3TxBytes float64 `json:"port_3-tx_bytes"` + Port3TxMulticast float64 `json:"port_3-tx_multicast"` + Port3TxPackets float64 `json:"port_3-tx_packets"` + Port4RxBroadcast float64 `json:"port_4-rx_broadcast"` + Port4RxBytes float64 `json:"port_4-rx_bytes"` + Port4RxDropped float64 `json:"port_4-rx_dropped"` + Port4RxMulticast float64 `json:"port_4-rx_multicast"` + Port4RxPackets float64 `json:"port_4-rx_packets"` + Port4TxBroadcast float64 `json:"port_4-tx_broadcast"` + Port4TxBytes float64 `json:"port_4-tx_bytes"` + Port4TxMulticast float64 `json:"port_4-tx_multicast"` + Port4TxPackets float64 `json:"port_4-tx_packets"` + Port5RxBroadcast float64 `json:"port_5-rx_broadcast"` + Port5RxBytes float64 `json:"port_5-rx_bytes"` + Port5RxDropped float64 `json:"port_5-rx_dropped"` + Port5RxMulticast float64 `json:"port_5-rx_multicast"` + Port5RxPackets float64 `json:"port_5-rx_packets"` + Port5TxBroadcast float64 `json:"port_5-tx_broadcast"` + Port5TxBytes float64 `json:"port_5-tx_bytes"` + Port5TxMulticast float64 `json:"port_5-tx_multicast"` + Port5TxPackets float64 `json:"port_5-tx_packets"` + Port6RxBroadcast float64 `json:"port_6-rx_broadcast"` + Port6RxBytes float64 `json:"port_6-rx_bytes"` + Port6RxDropped float64 `json:"port_6-rx_dropped"` + Port6RxMulticast float64 `json:"port_6-rx_multicast"` + Port6RxPackets float64 `json:"port_6-rx_packets"` + Port6TxBroadcast float64 `json:"port_6-tx_broadcast"` + Port6TxBytes float64 `json:"port_6-tx_bytes"` + Port6TxMulticast float64 `json:"port_6-tx_multicast"` + Port6TxPackets float64 `json:"port_6-tx_packets"` + Port7RxBroadcast float64 `json:"port_7-rx_broadcast"` + Port7RxBytes float64 `json:"port_7-rx_bytes"` + Port7RxDropped float64 `json:"port_7-rx_dropped"` + Port7RxMulticast float64 `json:"port_7-rx_multicast"` + Port7RxPackets float64 `json:"port_7-rx_packets"` + Port7TxBroadcast float64 `json:"port_7-tx_broadcast"` + Port7TxBytes float64 `json:"port_7-tx_bytes"` + Port7TxMulticast float64 `json:"port_7-tx_multicast"` + Port7TxPackets float64 `json:"port_7-tx_packets"` + Port8RxBroadcast float64 `json:"port_8-rx_broadcast"` + Port8RxBytes float64 `json:"port_8-rx_bytes"` + Port8RxDropped float64 `json:"port_8-rx_dropped"` + Port8RxMulticast float64 `json:"port_8-rx_multicast"` + Port8RxPackets float64 `json:"port_8-rx_packets"` + Port8TxBroadcast float64 `json:"port_8-tx_broadcast"` + Port8TxBytes float64 `json:"port_8-tx_bytes"` + Port8TxMulticast float64 `json:"port_8-tx_multicast"` + Port8TxPackets float64 `json:"port_8-tx_packets"` + Port9RxBroadcast float64 `json:"port_9-rx_broadcast"` + Port9RxBytes float64 `json:"port_9-rx_bytes"` + Port9RxDropped float64 `json:"port_9-rx_dropped"` + Port9RxMulticast float64 `json:"port_9-rx_multicast"` + Port9RxPackets float64 `json:"port_9-rx_packets"` + Port9TxBroadcast float64 `json:"port_9-tx_broadcast"` + Port9TxBytes float64 `json:"port_9-tx_bytes"` + Port9TxMulticast float64 `json:"port_9-tx_multicast"` + Port9TxPackets float64 `json:"port_9-tx_packets"` + Port10RxBroadcast float64 `json:"port_10-rx_broadcast"` + Port10RxBytes float64 `json:"port_10-rx_bytes"` + Port10RxDropped float64 `json:"port_10-rx_dropped"` + Port10RxMulticast float64 `json:"port_10-rx_multicast"` + Port10RxPackets float64 `json:"port_10-rx_packets"` + Port10TxBroadcast float64 `json:"port_10-tx_broadcast"` + Port10TxBytes float64 `json:"port_10-tx_bytes"` + Port10TxMulticast float64 `json:"port_10-tx_multicast"` + Port10TxPackets float64 `json:"port_10-tx_packets"` + Port11RxBroadcast float64 `json:"port_11-rx_broadcast"` + Port11RxBytes float64 `json:"port_11-rx_bytes"` + Port11RxDropped float64 `json:"port_11-rx_dropped"` + Port11RxMulticast float64 `json:"port_11-rx_multicast"` + Port11RxPackets float64 `json:"port_11-rx_packets"` + Port11TxBroadcast float64 `json:"port_11-tx_broadcast"` + Port11TxBytes float64 `json:"port_11-tx_bytes"` + Port11TxMulticast float64 `json:"port_11-tx_multicast"` + Port11TxPackets float64 `json:"port_11-tx_packets"` + Port12RxBroadcast float64 `json:"port_12-rx_broadcast"` + Port12RxBytes float64 `json:"port_12-rx_bytes"` + Port12RxDropped float64 `json:"port_12-rx_dropped"` + Port12RxMulticast float64 `json:"port_12-rx_multicast"` + Port12RxPackets float64 `json:"port_12-rx_packets"` + Port12TxBroadcast float64 `json:"port_12-tx_broadcast"` + Port12TxBytes float64 `json:"port_12-tx_bytes"` + Port12TxMulticast float64 `json:"port_12-tx_multicast"` + Port12TxPackets float64 `json:"port_12-tx_packets"` + Port13RxBroadcast float64 `json:"port_13-rx_broadcast"` + Port13RxBytes float64 `json:"port_13-rx_bytes"` + Port13RxDropped float64 `json:"port_13-rx_dropped"` + Port13RxMulticast float64 `json:"port_13-rx_multicast"` + Port13RxPackets float64 `json:"port_13-rx_packets"` + Port13TxBroadcast float64 `json:"port_13-tx_broadcast"` + Port13TxBytes float64 `json:"port_13-tx_bytes"` + Port13TxMulticast float64 `json:"port_13-tx_multicast"` + Port13TxPackets float64 `json:"port_13-tx_packets"` + Port14RxBroadcast float64 `json:"port_14-rx_broadcast"` + Port14RxBytes float64 `json:"port_14-rx_bytes"` + Port14RxDropped float64 `json:"port_14-rx_dropped"` + Port14RxMulticast float64 `json:"port_14-rx_multicast"` + Port14RxPackets float64 `json:"port_14-rx_packets"` + Port14TxBroadcast float64 `json:"port_14-tx_broadcast"` + Port14TxBytes float64 `json:"port_14-tx_bytes"` + Port14TxMulticast float64 `json:"port_14-tx_multicast"` + Port14TxPackets float64 `json:"port_14-tx_packets"` + Port15RxBroadcast float64 `json:"port_15-rx_broadcast"` + Port15RxBytes float64 `json:"port_15-rx_bytes"` + Port15RxDropped float64 `json:"port_15-rx_dropped"` + Port15RxMulticast float64 `json:"port_15-rx_multicast"` + Port15RxPackets float64 `json:"port_15-rx_packets"` + Port15TxBroadcast float64 `json:"port_15-tx_broadcast"` + Port15TxBytes float64 `json:"port_15-tx_bytes"` + Port15TxMulticast float64 `json:"port_15-tx_multicast"` + Port15TxPackets float64 `json:"port_15-tx_packets"` + Port16RxBroadcast float64 `json:"port_16-rx_broadcast"` + Port16RxBytes float64 `json:"port_16-rx_bytes"` + Port16RxDropped float64 `json:"port_16-rx_dropped"` + Port16RxMulticast float64 `json:"port_16-rx_multicast"` + Port16RxPackets float64 `json:"port_16-rx_packets"` + Port16TxBroadcast float64 `json:"port_16-tx_broadcast"` + Port16TxBytes float64 `json:"port_16-tx_bytes"` + Port16TxMulticast float64 `json:"port_16-tx_multicast"` + Port16TxPackets float64 `json:"port_16-tx_packets"` + Port17RxBroadcast float64 `json:"port_17-rx_broadcast"` + Port17RxBytes float64 `json:"port_17-rx_bytes"` + Port17RxDropped float64 `json:"port_17-rx_dropped"` + Port17RxMulticast float64 `json:"port_17-rx_multicast"` + Port17RxPackets float64 `json:"port_17-rx_packets"` + Port17TxBroadcast float64 `json:"port_17-tx_broadcast"` + Port17TxBytes float64 `json:"port_17-tx_bytes"` + Port17TxMulticast float64 `json:"port_17-tx_multicast"` + Port17TxPackets float64 `json:"port_17-tx_packets"` + Port18RxBroadcast float64 `json:"port_18-rx_broadcast"` + Port18RxBytes float64 `json:"port_18-rx_bytes"` + Port18RxDropped float64 `json:"port_18-rx_dropped"` + Port18RxMulticast float64 `json:"port_18-rx_multicast"` + Port18RxPackets float64 `json:"port_18-rx_packets"` + Port18TxBroadcast float64 `json:"port_18-tx_broadcast"` + Port18TxBytes float64 `json:"port_18-tx_bytes"` + Port18TxMulticast float64 `json:"port_18-tx_multicast"` + Port18TxPackets float64 `json:"port_18-tx_packets"` + Port19RxBroadcast float64 `json:"port_19-rx_broadcast"` + Port19RxBytes float64 `json:"port_19-rx_bytes"` + Port19RxDropped float64 `json:"port_19-rx_dropped"` + Port19RxMulticast float64 `json:"port_19-rx_multicast"` + Port19RxPackets float64 `json:"port_19-rx_packets"` + Port19TxBroadcast float64 `json:"port_19-tx_broadcast"` + Port19TxBytes float64 `json:"port_19-tx_bytes"` + Port19TxMulticast float64 `json:"port_19-tx_multicast"` + Port19TxPackets float64 `json:"port_19-tx_packets"` + Port20RxBroadcast float64 `json:"port_20-rx_broadcast"` + Port20RxBytes float64 `json:"port_20-rx_bytes"` + Port20RxDropped float64 `json:"port_20-rx_dropped"` + Port20RxMulticast float64 `json:"port_20-rx_multicast"` + Port20RxPackets float64 `json:"port_20-rx_packets"` + Port20TxBroadcast float64 `json:"port_20-tx_broadcast"` + Port20TxBytes float64 `json:"port_20-tx_bytes"` + Port20TxMulticast float64 `json:"port_20-tx_multicast"` + Port20TxPackets float64 `json:"port_20-tx_packets"` + Port21RxBroadcast float64 `json:"port_21-rx_broadcast"` + Port21RxBytes float64 `json:"port_21-rx_bytes"` + Port21RxDropped float64 `json:"port_21-rx_dropped"` + Port21RxMulticast float64 `json:"port_21-rx_multicast"` + Port21RxPackets float64 `json:"port_21-rx_packets"` + Port21TxBroadcast float64 `json:"port_21-tx_broadcast"` + Port21TxBytes float64 `json:"port_21-tx_bytes"` + Port21TxMulticast float64 `json:"port_21-tx_multicast"` + Port21TxPackets float64 `json:"port_21-tx_packets"` + Port22RxBroadcast float64 `json:"port_22-rx_broadcast"` + Port22RxBytes float64 `json:"port_22-rx_bytes"` + Port22RxDropped float64 `json:"port_22-rx_dropped"` + Port22RxMulticast float64 `json:"port_22-rx_multicast"` + Port22RxPackets float64 `json:"port_22-rx_packets"` + Port22TxBroadcast float64 `json:"port_22-tx_broadcast"` + Port22TxBytes float64 `json:"port_22-tx_bytes"` + Port22TxMulticast float64 `json:"port_22-tx_multicast"` + Port22TxPackets float64 `json:"port_22-tx_packets"` + Port23RxBroadcast float64 `json:"port_23-rx_broadcast"` + Port23RxBytes float64 `json:"port_23-rx_bytes"` + Port23RxDropped float64 `json:"port_23-rx_dropped"` + Port23RxMulticast float64 `json:"port_23-rx_multicast"` + Port23RxPackets float64 `json:"port_23-rx_packets"` + Port23TxBroadcast float64 `json:"port_23-tx_broadcast"` + Port23TxBytes float64 `json:"port_23-tx_bytes"` + Port23TxMulticast float64 `json:"port_23-tx_multicast"` + Port23TxPackets float64 `json:"port_23-tx_packets"` + Port24RxBroadcast float64 `json:"port_24-rx_broadcast"` + Port24RxBytes float64 `json:"port_24-rx_bytes"` + Port24RxDropped float64 `json:"port_24-rx_dropped"` + Port24RxMulticast float64 `json:"port_24-rx_multicast"` + Port24RxPackets float64 `json:"port_24-rx_packets"` + Port24TxBroadcast float64 `json:"port_24-tx_broadcast"` + Port24TxBytes float64 `json:"port_24-tx_bytes"` + Port24TxMulticast float64 `json:"port_24-tx_multicast"` + Port24TxPackets float64 `json:"port_24-tx_packets"` + // Have a 48 port switch? How 'bout a pull request. :D + RxBroadcast float64 `json:"rx_broadcast"` + RxBytes float64 `json:"rx_bytes"` + RxCrypts float64 `json:"rx_crypts"` + RxDropped float64 `json:"rx_dropped"` + RxErrors float64 `json:"rx_errors"` + RxFrags float64 `json:"rx_frags"` + RxMulticast float64 `json:"rx_multicast"` + RxPackets float64 `json:"rx_packets"` + SiteID string `json:"site_id"` + Sw string `json:"sw"` + Time float64 `json:"time"` + TxBroadcast float64 `json:"tx_broadcast"` + TxBytes float64 `json:"tx_bytes"` + TxDropped float64 `json:"tx_dropped"` + TxErrors float64 `json:"tx_errors"` + TxMulticast float64 `json:"tx_multicast"` + TxPackets float64 `json:"tx_packets"` + TxRetries float64 `json:"tx_retries"` + } `json:"stat"` + + State float64 `json:"state"` + StpPriority string `json:"stp_priority"` + StpVersion string `json:"stp_version"` + SysStats struct { + Loadavg1 float64 `json:"loadavg_1,string"` + Loadavg15 float64 `json:"loadavg_15,string"` + Loadavg5 float64 `json:"loadavg_5,string"` + MemBuffer float64 `json:"mem_buffer"` + MemTotal float64 `json:"mem_total"` + MemUsed float64 `json:"mem_used"` + } `json:"sys_stats"` + SystemStats struct { + CPU float64 `json:"cpu,string"` + Mem float64 `json:"mem,string"` + Uptime float64 `json:"uptime,string"` + } `json:"system-stats"` + TxBytes float64 `json:"tx_bytes"` + Type string `json:"type"` + Upgradable bool `json:"upgradable"` + Uplink struct { + FullDuplex bool `json:"full_duplex"` + IP string `json:"ip"` + Mac string `json:"mac"` + MaxSpeed float64 `json:"max_speed"` + Media string `json:"media"` + Name string `json:"name"` + Netmask string `json:"netmask"` + NumPort float64 `json:"num_port"` + PortIdx float64 `json:"port_idx"` + RxBytes float64 `json:"rx_bytes"` + RxBytesR float64 `json:"rx_bytes-r"` + RxDropped float64 `json:"rx_dropped"` + RxErrors float64 `json:"rx_errors"` + RxMulticast float64 `json:"rx_multicast"` + RxPackets float64 `json:"rx_packets"` + Speed float64 `json:"speed"` + TxBytes float64 `json:"tx_bytes"` + TxBytesR float64 `json:"tx_bytes-r"` + TxDropped float64 `json:"tx_dropped"` + TxErrors float64 `json:"tx_errors"` + TxPackets float64 `json:"tx_packets"` + Type string `json:"type"` + Up bool `json:"up"` + UplinkMac string `json:"uplink_mac"` + } `json:"uplink"` + UplinkDepth float64 `json:"uplink_depth"` + Uptime float64 `json:"uptime"` + UserNumSta float64 `json:"user-num_sta"` + Version string `json:"version"` + VersionIncompatible bool `json:"version_incompatible"` +} From bb40ca6b9a8cc4be512adc10ce7b96ceb795d44b Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 23 Jan 2019 23:50:59 -0800 Subject: [PATCH 003/194] Add dep constraints. --- core/unifi/.gitignore | 1 + core/unifi/Gopkg.lock | 51 +++++++++++++++++++++++++++++++++++++++++++ core/unifi/Gopkg.toml | 42 +++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 core/unifi/.gitignore create mode 100644 core/unifi/Gopkg.lock create mode 100644 core/unifi/Gopkg.toml diff --git a/core/unifi/.gitignore b/core/unifi/.gitignore new file mode 100644 index 00000000..61ead866 --- /dev/null +++ b/core/unifi/.gitignore @@ -0,0 +1 @@ +/vendor diff --git a/core/unifi/Gopkg.lock b/core/unifi/Gopkg.lock new file mode 100644 index 00000000..9bd31137 --- /dev/null +++ b/core/unifi/Gopkg.lock @@ -0,0 +1,51 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/davecgh/go-spew" + packages = ["spew"] + revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" + version = "v1.1.1" + +[[projects]] + name = "github.com/influxdata/influxdb" + packages = [ + "client/v2", + "models", + "pkg/escape" + ] + revision = "698dbc789aff13c2678357a6b93ff73dd7136571" + version = "v1.7.3" + +[[projects]] + name = "github.com/influxdata/platform" + packages = [ + "models", + "pkg/escape" + ] + revision = "0f79e4ea3248354c789cba274542e0a8e55971db" + +[[projects]] + name = "github.com/pkg/errors" + packages = ["."] + revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4" + version = "v0.8.1" + +[[projects]] + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + +[[projects]] + name = "github.com/stretchr/testify" + packages = ["assert"] + revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053" + version = "v1.3.0" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "197affc1e5dd8eaa5e70f3a4f3f5ed63d0079ff7fbb632d9036bf985e3c60338" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/core/unifi/Gopkg.toml b/core/unifi/Gopkg.toml new file mode 100644 index 00000000..94dee33a --- /dev/null +++ b/core/unifi/Gopkg.toml @@ -0,0 +1,42 @@ +# Gopkg.toml example +# +# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + name = "github.com/influxdata/influxdb" + version = "1.7.3" + +[[constraint]] + name = "github.com/pkg/errors" + version = "0.8.1" + +[[constraint]] + name = "github.com/stretchr/testify" + version = "1.3.0" + +[prune] + go-tests = true + unused-packages = true From 127082affa9ec76d53e3deac00f615c46f813599 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Thu, 24 Jan 2019 00:01:13 -0800 Subject: [PATCH 004/194] Fix name. --- core/unifi/clients.go | 2 +- core/unifi/clients_type.go | 2 +- core/unifi/uap.go | 2 +- core/unifi/uap_type.go | 2 +- core/unifi/unidev.go | 2 +- core/unifi/unidev_test.go | 2 +- core/unifi/unifi.go | 2 +- core/unifi/usg.go | 2 +- core/unifi/usg_type.go | 2 +- core/unifi/usw.go | 2 +- core/unifi/usw_type.go | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/core/unifi/clients.go b/core/unifi/clients.go index f4694537..7e94b465 100644 --- a/core/unifi/clients.go +++ b/core/unifi/clients.go @@ -1,4 +1,4 @@ -package unidev +package unifi import ( "strconv" diff --git a/core/unifi/clients_type.go b/core/unifi/clients_type.go index 45ddf1dd..996c2493 100644 --- a/core/unifi/clients_type.go +++ b/core/unifi/clients_type.go @@ -1,4 +1,4 @@ -package unidev +package unifi // UCL defines all the data a connected-network client contains. type UCL struct { diff --git a/core/unifi/uap.go b/core/unifi/uap.go index d388506c..6114c861 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -1,4 +1,4 @@ -package unidev +package unifi import ( "strconv" diff --git a/core/unifi/uap_type.go b/core/unifi/uap_type.go index 053a83e1..78506b74 100644 --- a/core/unifi/uap_type.go +++ b/core/unifi/uap_type.go @@ -1,4 +1,4 @@ -package unidev +package unifi // UAP is a Unifi Access Point. type UAP struct { diff --git a/core/unifi/unidev.go b/core/unifi/unidev.go index 34f08254..5efbb3fa 100644 --- a/core/unifi/unidev.go +++ b/core/unifi/unidev.go @@ -1,4 +1,4 @@ -package unidev +package unifi import ( "bytes" diff --git a/core/unifi/unidev_test.go b/core/unifi/unidev_test.go index 0557934a..92852ab2 100644 --- a/core/unifi/unidev_test.go +++ b/core/unifi/unidev_test.go @@ -1,4 +1,4 @@ -package unidev +package unifi import ( "encoding/json" diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index e1f1e6f2..aae44a32 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -1,4 +1,4 @@ -package unidev +package unifi import ( "encoding/json" diff --git a/core/unifi/usg.go b/core/unifi/usg.go index a8123705..9d3bfa73 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg.go @@ -1,4 +1,4 @@ -package unidev +package unifi import ( "strconv" diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index d5a7d15a..54fe09e4 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -1,4 +1,4 @@ -package unidev +package unifi import "encoding/json" diff --git a/core/unifi/usw.go b/core/unifi/usw.go index 5a2e491e..d19346fa 100644 --- a/core/unifi/usw.go +++ b/core/unifi/usw.go @@ -1,4 +1,4 @@ -package unidev +package unifi import ( "strconv" diff --git a/core/unifi/usw_type.go b/core/unifi/usw_type.go index 0b61ce17..42b36b4c 100644 --- a/core/unifi/usw_type.go +++ b/core/unifi/usw_type.go @@ -1,4 +1,4 @@ -package unidev +package unifi // USW is a Unifi Switch type USW struct { From 9dff9a864516ccaf7bb7ca9790047b9ae1d87cf2 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 26 Jan 2019 03:50:10 -0800 Subject: [PATCH 005/194] Ditch the interface, open up the structs. Fix logging. --- core/unifi/Gopkg.lock | 22 +++++++-- core/unifi/README.md | 46 +++++++++++++++++-- core/unifi/unidev.go | 42 +++++++++++------- core/unifi/unidev_test.go | 4 +- core/unifi/unifi.go | 93 +++++++++++---------------------------- 5 files changed, 115 insertions(+), 92 deletions(-) diff --git a/core/unifi/Gopkg.lock b/core/unifi/Gopkg.lock index 9bd31137..54395b3b 100644 --- a/core/unifi/Gopkg.lock +++ b/core/unifi/Gopkg.lock @@ -2,50 +2,66 @@ [[projects]] + digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" name = "github.com/davecgh/go-spew" packages = ["spew"] + pruneopts = "UT" revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" version = "v1.1.1" [[projects]] + digest = "1:718c57979a9197414a044fff2028e57cb9fe145069e4f507059755bfe87f1bfe" name = "github.com/influxdata/influxdb" packages = [ "client/v2", "models", - "pkg/escape" + "pkg/escape", ] + pruneopts = "UT" revision = "698dbc789aff13c2678357a6b93ff73dd7136571" version = "v1.7.3" [[projects]] + digest = "1:937258f1293bc9295b4789b0abea5b4ec030e3caecb65a4e1dc0b6999957a5ed" name = "github.com/influxdata/platform" packages = [ "models", - "pkg/escape" + "pkg/escape", ] + pruneopts = "UT" revision = "0f79e4ea3248354c789cba274542e0a8e55971db" [[projects]] + digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b" name = "github.com/pkg/errors" packages = ["."] + pruneopts = "UT" revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4" version = "v0.8.1" [[projects]] + digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" name = "github.com/pmezard/go-difflib" packages = ["difflib"] + pruneopts = "UT" revision = "792786c7400a136282c1664665ae0a8db921c6c2" version = "v1.0.0" [[projects]] + digest = "1:972c2427413d41a1e06ca4897e8528e5a1622894050e2f527b38ddf0f343f759" name = "github.com/stretchr/testify" packages = ["assert"] + pruneopts = "UT" revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053" version = "v1.3.0" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "197affc1e5dd8eaa5e70f3a4f3f5ed63d0079ff7fbb632d9036bf985e3c60338" + input-imports = [ + "github.com/influxdata/influxdb/client/v2", + "github.com/pkg/errors", + "github.com/stretchr/testify/assert", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/core/unifi/README.md b/core/unifi/README.md index 20c723db..fe625aec 100644 --- a/core/unifi/README.md +++ b/core/unifi/README.md @@ -3,10 +3,48 @@ It connects to a Unifi Controller, given a url, username and password. Returns an authenticated http Client you may use to query the device for data. Also contains some built-in methods for de-serializing common client and device -data. The included asset interface currently only works for InfluxDB but could -probably be modified to support other output mechanisms; not sure really. +data. The data is provided in a large struct you can consume in your application. + +This library also contains methods to export the Unifi data in InfluxDB format. Pull requests and feedback are welcomed! -This lib is rudimentary and gets a job done for the tool at hand. It could be -used to base your own library. Good luck! + +Here's a working example: +```golang +package main + +import ( + "log" + "github.com/golift/unifi" +) + +func main() { + username := "admin" + password := "superSecret1234" + URL := "https://127.0.0.1:8443/" + uni, err := unifi.AuthController(username, password, URL, false) + if err != nil { + log.Fatalln("error:", err) + } + clients, err := uni.GetUnifiClients() + if err != nil { + log.Fatalln("error:", err) + } + log.Println(len(clients), "clients connected:") + for i, client := range clients { + log.Println(i+1, client.ID, client.Hostname, client.IP, client.Name, client.LastSeen) + } + devices, err := uni.GetUnifiDevices() + if err != nil { + log.Fatalln("error:", err) + } + log.Println(len(devices.USWs), "Unifi Switches Found") + log.Println(len(devices.USGs), "Unifi Gateways Found") + + log.Println(len(devices.UAPs), "Unifi Access Points Found:") + for i, uap := range devices.UAPs { + log.Println(i+1, uap.Name, uap.IP) + } +} +``` diff --git a/core/unifi/unidev.go b/core/unifi/unidev.go index 5efbb3fa..68b4f82a 100644 --- a/core/unifi/unidev.go +++ b/core/unifi/unidev.go @@ -4,32 +4,32 @@ import ( "bytes" "crypto/tls" "encoding/json" - "log" "net/http" "net/http/cookiejar" "strconv" - influx "github.com/influxdata/influxdb/client/v2" "github.com/pkg/errors" ) +// 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" -// Asset provides a common interface to retreive metrics from a device or client. -// It currently only supports InfluxDB, but could be amended to support other -// libraries that have a similar interface. -// This app only uses the .AddPoint/s() methods with the Asset type. -type Asset interface { - // Point() means this is useful to influxdb.. - Points() ([]*influx.Point, error) - // Add more methods to achieve more usefulness from this library. +// Devices contains a list of all the unifi devices from a controller. +type Devices struct { + UAPs []UAP + USGs []USG + USWs []USW } // AuthedReq is what you get in return for providing a password! type AuthedReq struct { *http.Client - baseURL string + baseURL string + ErrorLog Logger + DebugLog Logger } // FlexInt provides a container and unmarshalling for fields that may be @@ -67,10 +67,10 @@ func AuthController(user, pass, url string, verifySSL bool) (*AuthedReq, error) if err != nil { return nil, errors.Wrap(err, "cookiejar.New(nil)") } - a := &AuthedReq{&http.Client{ + a := &AuthedReq{Client: &http.Client{ Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !verifySSL}}, Jar: jar, - }, url} + }, baseURL: url} req, err := a.UniReq(LoginPath, json) if err != nil { return a, errors.Wrap(err, "UniReq(LoginPath, json)") @@ -80,9 +80,7 @@ func AuthController(user, pass, url string, verifySSL bool) (*AuthedReq, error) return a, errors.Wrap(err, "authReq.Do(req)") } defer func() { - if err := resp.Body.Close(); err != nil { - log.Println("resp.Body.Close():", err) // Not fatal. Just log it. - } + _ = resp.Body.Close() }() if resp.StatusCode != http.StatusOK { return a, errors.Errorf("authentication failed (%v): %v (status: %v/%v)", @@ -103,3 +101,15 @@ 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...) + } +} + +func (a AuthedReq) eLogf(msg string, v ...interface{}) { + if a.ErrorLog != nil { + a.ErrorLog("[ERROR] "+msg, v...) + } +} diff --git a/core/unifi/unidev_test.go b/core/unifi/unidev_test.go index 92852ab2..ba654e94 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{&http.Client{}, url} + authReq := &AuthedReq{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{&http.Client{}, "http://some.url:8443"} + authReq = &AuthedReq{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 aae44a32..1f8a3cc8 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -3,14 +3,10 @@ package unifi import ( "encoding/json" "io/ioutil" - "log" "github.com/pkg/errors" ) -// Debug .... -var Debug = false - const ( // ClientPath is Unifi Clients API Path ClientPath = "/api/s/default/stat/sta" @@ -26,9 +22,6 @@ const ( func (c *AuthedReq) GetUnifiClients() ([]UCL, error) { var response struct { Clients []UCL `json:"data"` - Meta struct { - Rc string `json:"rc"` - } `json:"meta"` } req, err := c.UniReq(ClientPath, "") if err != nil { @@ -39,9 +32,7 @@ func (c *AuthedReq) GetUnifiClients() ([]UCL, error) { return nil, errors.Wrap(err, "c.Do(req)") } defer func() { - if err := resp.Body.Close(); err != nil { - log.Println("resp.Body.Close():", err) // Not fatal? Just log it. - } + _ = resp.Body.Close() }() if body, err := ioutil.ReadAll(resp.Body); err != nil { return nil, errors.Wrap(err, "ioutil.ReadAll(resp.Body)") @@ -51,104 +42,72 @@ func (c *AuthedReq) GetUnifiClients() ([]UCL, error) { return response.Clients, nil } -// GetUnifiClientAssets provides an interface to return common asset types. -func (c *AuthedReq) GetUnifiClientAssets() ([]Asset, error) { - clients, err := c.GetUnifiClients() - assets := []Asset{} - if err == nil { - for _, r := range clients { - assets = append(assets, r) - } - } - return assets, err -} - // GetUnifiDevices returns a response full of devices' data from the Unifi Controller. -func (c *AuthedReq) GetUnifiDevices() ([]USG, []USW, []UAP, error) { +func (c *AuthedReq) GetUnifiDevices() (*Devices, error) { var parsed struct { Data []json.RawMessage `json:"data"` - Meta struct { - Rc string `json:"rc"` - } `json:"meta"` } req, err := c.UniReq(DevicePath, "") if err != nil { - return nil, nil, nil, errors.Wrap(err, "c.UniReq(DevicePath)") + return nil, errors.Wrap(err, "c.UniReq(DevicePath)") } resp, err := c.Do(req) if err != nil { - return nil, nil, nil, errors.Wrap(err, "c.Do(req)") + return nil, errors.Wrap(err, "c.Do(req)") } defer func() { - if err := resp.Body.Close(); err != nil { - log.Println("resp.Body.Close():", err) // Not fatal? Just log it. - } + _ = resp.Body.Close() }() if body, err := ioutil.ReadAll(resp.Body); err != nil { - return nil, nil, nil, errors.Wrap(err, "ioutil.ReadAll(resp.Body)") + return nil, errors.Wrap(err, "ioutil.ReadAll(resp.Body)") } else if err = json.Unmarshal(body, &parsed); err != nil { - return nil, nil, nil, errors.Wrap(err, "json.Unmarshal([]json.RawMessage)") + return nil, errors.Wrap(err, "json.Unmarshal([]json.RawMessage)") } + return c.parseUnifiDevices(parsed.Data), nil +} - var usgs []USG - var usws []USW - var uaps []UAP +func (c *AuthedReq) 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 parsed.Data { + for i, r := range data { var usg USG var usw USW var uap UAP // Unamrshal into a map and check "type" var obj map[string]interface{} if err := json.Unmarshal(r, &obj); err != nil { - return nil, nil, nil, errors.Wrapf(err, "[%d] json.Unmarshal(interfce{})", i) + c.eLogf("[%d] json.Unmarshal(interfce{}): %v", i, err) + continue } assetType := "" if t, ok := obj["type"].(string); ok { assetType = t } - if Debug { - log.Println("Unmarshalling Device Type:", assetType) - } + c.dLogf("Unmarshalling Device Type:", assetType) // Unmarshal again into the correct type.. switch assetType { case "uap": if err := json.Unmarshal(r, &uap); err != nil { - return nil, nil, nil, errors.Wrapf(err, "[%d] json.Unmarshal([]UAP)", i) + c.eLogf("[%d] json.Unmarshal([]UAP): %v", i, err) + continue } - uaps = append(uaps, uap) + 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 { - return nil, nil, nil, errors.Wrapf(err, "[%d] json.Unmarshal([]USG)", i) + c.eLogf("[%d] json.Unmarshal([]USG): %v", i, err) + continue } - usgs = append(usgs, usg) + devices.USGs = append(devices.USGs, usg) case "usw": if err := json.Unmarshal(r, &usw); err != nil { - return nil, nil, nil, errors.Wrapf(err, "[%d] json.Unmarshal([]USW)", i) + c.eLogf("[%d] json.Unmarshal([]USW): %v", i, err) + continue } - usws = append(usws, usw) + devices.USWs = append(devices.USWs, usw) default: - log.Println("unknown asset type -", assetType, "- skipping") + c.dLogf("unknown asset type -", assetType, "- skipping") continue } } - return usgs, usws, uaps, nil -} - -// GetUnifiDeviceAssets provides an interface to return common asset types. -func (c *AuthedReq) GetUnifiDeviceAssets() ([]Asset, error) { - usgs, usws, uaps, err := c.GetUnifiDevices() - assets := []Asset{} - if err == nil { - for _, r := range usgs { - assets = append(assets, r) - } - for _, r := range usws { - assets = append(assets, r) - } - for _, r := range uaps { - assets = append(assets, r) - } - } - return assets, err + return devices } From f3a87e2e37e841e270a051549fd311e0bbba82fd Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 26 Jan 2019 03:53:26 -0800 Subject: [PATCH 006/194] Add logger example. --- core/unifi/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/unifi/README.md b/core/unifi/README.md index fe625aec..ccb1614e 100644 --- a/core/unifi/README.md +++ b/core/unifi/README.md @@ -27,6 +27,9 @@ func main() { if err != nil { log.Fatalln("error:", err) } + // Log with log.Printf or make your own interface. + uni.ErrorLog = log.Printf + uni.DebugLog = log.Printf clients, err := uni.GetUnifiClients() if err != nil { log.Fatalln("error:", err) From 7256b15467314f93daa330cf16044166b3897239 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 26 Jan 2019 04:04:36 -0800 Subject: [PATCH 007/194] minor tweaks --- core/unifi/README.md | 14 ++++++-------- core/unifi/clients.go | 1 + core/unifi/uap.go | 2 ++ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/core/unifi/README.md b/core/unifi/README.md index ccb1614e..1c430930 100644 --- a/core/unifi/README.md +++ b/core/unifi/README.md @@ -5,19 +5,17 @@ an authenticated http Client you may use to query the device for data. Also contains some built-in methods for de-serializing common client and device data. The data is provided in a large struct you can consume in your application. -This library also contains methods to export the Unifi data in InfluxDB format. +This library also contains methods to export the Unifi data in InfluxDB format, +and this can be used as an example to base your own metrics collection methods. Pull requests and feedback are welcomed! - Here's a working example: ```golang package main -import ( - "log" - "github.com/golift/unifi" -) +import "log" +import "github.com/golift/unifi" func main() { username := "admin" @@ -27,7 +25,7 @@ func main() { if err != nil { log.Fatalln("error:", err) } - // Log with log.Printf or make your own interface. + // Log with log.Printf or make your own interface that accepts (msg, fmt) uni.ErrorLog = log.Printf uni.DebugLog = log.Printf clients, err := uni.GetUnifiClients() @@ -45,7 +43,7 @@ func main() { log.Println(len(devices.USWs), "Unifi Switches Found") log.Println(len(devices.USGs), "Unifi Gateways Found") - log.Println(len(devices.UAPs), "Unifi Access Points Found:") + log.Println(len(devices.UAPs), "Unifi Wireless APs Found:") for i, uap := range devices.UAPs { log.Println(i+1, uap.Name, uap.IP) } diff --git a/core/unifi/clients.go b/core/unifi/clients.go index 7e94b465..2b98ece8 100644 --- a/core/unifi/clients.go +++ b/core/unifi/clients.go @@ -10,6 +10,7 @@ import ( // Points generates a client's datapoints for InfluxDB. func (u 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 != "" { diff --git a/core/unifi/uap.go b/core/unifi/uap.go index 6114c861..a35db906 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -221,6 +221,7 @@ func (u UAP) Points() ([]*influx.Point, error) { fields["radio_tx_power"] = s.TxPower fields["radio_tx_retries"] = s.TxRetries fields["user-num_sta"] = s.UserNumSta + continue } } for _, s := range u.VapTable { @@ -254,6 +255,7 @@ func (u UAP) Points() ([]*influx.Point, error) { fields["tx_retries"] = s.TxRetries fields["usage"] = s.Usage tags["wlanconf_id"] = s.WlanconfID + continue } } pt, err := influx.NewPoint("uap_radios", tags, fields, time.Now()) From d2862befc037b1de70cb490ce623fbb2daf8f32a Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 26 Jan 2019 04:15:41 -0800 Subject: [PATCH 008/194] 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"` From 4ef35f25f2b572ab453e39217b6895b4c6efe2dd Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 26 Jan 2019 04:18:21 -0800 Subject: [PATCH 009/194] minor fixes. --- core/unifi/README.md | 8 ++++---- core/unifi/unidev.go | 11 +++++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/core/unifi/README.md b/core/unifi/README.md index 1c430930..58daebf3 100644 --- a/core/unifi/README.md +++ b/core/unifi/README.md @@ -23,22 +23,22 @@ func main() { URL := "https://127.0.0.1:8443/" uni, err := unifi.AuthController(username, password, URL, false) if err != nil { - log.Fatalln("error:", err) + log.Fatalln("Error:", err) } // Log with log.Printf or make your own interface that accepts (msg, fmt) uni.ErrorLog = log.Printf uni.DebugLog = log.Printf clients, err := uni.GetUnifiClients() if err != nil { - log.Fatalln("error:", err) + log.Fatalln("Error:", err) } - log.Println(len(clients), "clients connected:") + log.Println(len(clients), "Clients connected:") for i, client := range clients { log.Println(i+1, client.ID, client.Hostname, client.IP, client.Name, client.LastSeen) } devices, err := uni.GetUnifiDevices() if err != nil { - log.Fatalln("error:", err) + log.Fatalln("Error:", err) } log.Println(len(devices.USWs), "Unifi Switches Found") log.Println(len(devices.USGs), "Unifi Gateways Found") diff --git a/core/unifi/unidev.go b/core/unifi/unidev.go index af2bf02c..520be0a5 100644 --- a/core/unifi/unidev.go +++ b/core/unifi/unidev.go @@ -77,10 +77,13 @@ func AuthController(user, pass, url string, verifySSL bool) (*Unifi, error) { if err != nil { return nil, errors.Wrap(err, "cookiejar.New(nil)") } - u := &Unifi{Client: &http.Client{ - Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !verifySSL}}, - Jar: jar, - }, baseURL: url} + u := &Unifi{ + Client: &http.Client{ + Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !verifySSL}}, + Jar: jar, + }, + baseURL: url, + } req, err := u.UniReq(LoginPath, json) if err != nil { return u, errors.Wrap(err, "UniReq(LoginPath, json)") From 94bc27fd285c8e18a6e1a01f413e600f5ec0cd1c Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 26 Jan 2019 04:25:23 -0800 Subject: [PATCH 010/194] more minor fixes. --- core/unifi/README.md | 4 ++-- core/unifi/unidev.go | 8 +++++--- core/unifi/unifi.go | 18 +++++++++--------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/core/unifi/README.md b/core/unifi/README.md index 58daebf3..8b8c4a30 100644 --- a/core/unifi/README.md +++ b/core/unifi/README.md @@ -28,7 +28,7 @@ func main() { // Log with log.Printf or make your own interface that accepts (msg, fmt) uni.ErrorLog = log.Printf uni.DebugLog = log.Printf - clients, err := uni.GetUnifiClients() + clients, err := uni.GetClients() if err != nil { log.Fatalln("Error:", err) } @@ -36,7 +36,7 @@ func main() { for i, client := range clients { log.Println(i+1, client.ID, client.Hostname, client.IP, client.Name, client.LastSeen) } - devices, err := uni.GetUnifiDevices() + devices, err := uni.GetDevices() if err != nil { log.Fatalln("Error:", err) } diff --git a/core/unifi/unidev.go b/core/unifi/unidev.go index 520be0a5..ba28b895 100644 --- a/core/unifi/unidev.go +++ b/core/unifi/unidev.go @@ -24,7 +24,7 @@ const ( LoginPath = "/api/login" ) -// Logger is a base type to deal with changing log outs. +// Logger is a base type to deal with changing log outputs. type Logger func(msg string, fmt ...interface{}) // Devices contains a list of all the unifi devices from a controller. @@ -69,9 +69,9 @@ func (f *FlexInt) UnmarshalJSON(b []byte) error { } } -// AuthController creates a http.Client with authenticated cookies. +// GetController creates a http.Client with authenticated cookies. // Used to make additional, authenticated requests to the APIs. -func AuthController(user, pass, url string, verifySSL bool) (*Unifi, error) { +func GetController(user, pass, url string, verifySSL bool) (*Unifi, error) { json := `{"username": "` + user + `","password": "` + pass + `"}` jar, err := cookiejar.New(nil) if err != nil { @@ -103,6 +103,8 @@ func AuthController(user, pass, url string, verifySSL bool) (*Unifi, error) { } // UniReq is a small helper function that adds an Accept header. +// Use this if you're unmarshalling Unifi data into custom types. +// And you're doing that... sumbut a pull request with your new struct. :) func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err error) { if params != "" { req, err = http.NewRequest("POST", u.baseURL+apiPath, bytes.NewBufferString(params)) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 92893292..5c2645af 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -7,8 +7,8 @@ import ( "github.com/pkg/errors" ) -// GetUnifiClients returns a response full of clients' data from the Unifi Controller. -func (u *Unifi) GetUnifiClients() ([]UCL, error) { +// GetClients returns a response full of clients' data from the Unifi Controller. +func (u *Unifi) GetClients() ([]UCL, error) { var response struct { Clients []UCL `json:"data"` } @@ -31,8 +31,8 @@ func (u *Unifi) GetUnifiClients() ([]UCL, error) { return response.Clients, nil } -// GetUnifiDevices returns a response full of devices' data from the Unifi Controller. -func (u *Unifi) GetUnifiDevices() (*Devices, error) { +// GetDevices returns a response full of devices' data from the Unifi Controller. +func (u *Unifi) GetDevices() (*Devices, error) { var parsed struct { Data []json.RawMessage `json:"data"` } @@ -52,11 +52,11 @@ func (u *Unifi) GetUnifiDevices() (*Devices, error) { } else if err = json.Unmarshal(body, &parsed); err != nil { return nil, errors.Wrap(err, "json.Unmarshal([]json.RawMessage)") } - return u.parseUnifiDevices(parsed.Data), nil + return u.parseDevices(parsed.Data), nil } -// parseUnifiDevices parses the raw JSON from the Unifi Controller into device structures. -func (u *Unifi) parseUnifiDevices(data []json.RawMessage) *Devices { +// parseDevices parses the raw JSON from the Unifi Controller into device structures. +func (u *Unifi) parseDevices(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 { @@ -73,7 +73,7 @@ func (u *Unifi) parseUnifiDevices(data []json.RawMessage) *Devices { if t, ok := obj["type"].(string); ok { assetType = t } - u.dLogf("Unmarshalling Device Type:", assetType) + u.dLogf("Unmarshalling Device Type: %v", assetType) // Unmarshal again into the correct type.. switch assetType { case "uap": @@ -95,7 +95,7 @@ func (u *Unifi) parseUnifiDevices(data []json.RawMessage) *Devices { } devices.USWs = append(devices.USWs, usw) default: - u.dLogf("unknown asset type -", assetType, "- skipping") + u.dLogf("unknown asset type - " + assetType + " - skipping") continue } } From a6afe62ff2b276b355bbf44ab8e9a25c5807a97d Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 26 Jan 2019 04:29:16 -0800 Subject: [PATCH 011/194] type strings and fix readme. --- core/unifi/README.md | 2 +- core/unifi/unidev.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/unifi/README.md b/core/unifi/README.md index 8b8c4a30..f4dd4fab 100644 --- a/core/unifi/README.md +++ b/core/unifi/README.md @@ -21,7 +21,7 @@ func main() { username := "admin" password := "superSecret1234" URL := "https://127.0.0.1:8443/" - uni, err := unifi.AuthController(username, password, URL, false) + uni, err := unifi.GetController(username, password, URL, false) if err != nil { log.Fatalln("Error:", err) } diff --git a/core/unifi/unidev.go b/core/unifi/unidev.go index ba28b895..7f2d7f54 100644 --- a/core/unifi/unidev.go +++ b/core/unifi/unidev.go @@ -13,15 +13,15 @@ import ( const ( // ClientPath is Unifi Clients API Path - ClientPath = "/api/s/default/stat/sta" + ClientPath string = "/api/s/default/stat/sta" // DevicePath is where we get data about Unifi devices. - DevicePath = "/api/s/default/stat/device" + DevicePath string = "/api/s/default/stat/device" // NetworkPath contains network-configuration data. Not really graphable. - NetworkPath = "/api/s/default/rest/networkconf" + NetworkPath string = "/api/s/default/rest/networkconf" // UserGroupPath contains usergroup configurations. - UserGroupPath = "/api/s/default/rest/usergroup" + UserGroupPath string = "/api/s/default/rest/usergroup" // LoginPath is Unifi Controller Login API Path - LoginPath = "/api/login" + LoginPath string = "/api/login" ) // Logger is a base type to deal with changing log outputs. From 483480a4eb49d01c79b6f230015125ff54310e0e Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 26 Jan 2019 12:33:18 -0800 Subject: [PATCH 012/194] Use new influx db lib path. Make Points() work with an interface. --- core/unifi/Gopkg.lock | 22 ++++++---------------- core/unifi/Gopkg.toml | 4 ++-- core/unifi/clients.go | 4 ++-- core/unifi/uap.go | 4 ++-- core/unifi/unidev_test.go | 2 +- core/unifi/usg.go | 4 ++-- core/unifi/usw.go | 4 ++-- 7 files changed, 17 insertions(+), 27 deletions(-) diff --git a/core/unifi/Gopkg.lock b/core/unifi/Gopkg.lock index 54395b3b..92114921 100644 --- a/core/unifi/Gopkg.lock +++ b/core/unifi/Gopkg.lock @@ -10,26 +10,16 @@ version = "v1.1.1" [[projects]] - digest = "1:718c57979a9197414a044fff2028e57cb9fe145069e4f507059755bfe87f1bfe" - name = "github.com/influxdata/influxdb" - packages = [ - "client/v2", - "models", - "pkg/escape", - ] - pruneopts = "UT" - revision = "698dbc789aff13c2678357a6b93ff73dd7136571" - version = "v1.7.3" - -[[projects]] - digest = "1:937258f1293bc9295b4789b0abea5b4ec030e3caecb65a4e1dc0b6999957a5ed" - name = "github.com/influxdata/platform" + branch = "master" + digest = "1:50708c8fc92aec981df5c446581cf9f90ba9e2a5692118e0ce75d4534aaa14a2" + name = "github.com/influxdata/influxdb1-client" packages = [ "models", "pkg/escape", + "v2", ] pruneopts = "UT" - revision = "0f79e4ea3248354c789cba274542e0a8e55971db" + revision = "16c852ea613fa2d42fcdccc9a8b0802a8bdc6140" [[projects]] digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b" @@ -59,7 +49,7 @@ analyzer-name = "dep" analyzer-version = 1 input-imports = [ - "github.com/influxdata/influxdb/client/v2", + "github.com/influxdata/influxdb1-client/v2", "github.com/pkg/errors", "github.com/stretchr/testify/assert", ] diff --git a/core/unifi/Gopkg.toml b/core/unifi/Gopkg.toml index 94dee33a..b38356cd 100644 --- a/core/unifi/Gopkg.toml +++ b/core/unifi/Gopkg.toml @@ -26,8 +26,8 @@ [[constraint]] - name = "github.com/influxdata/influxdb" - version = "1.7.3" + branch = "master" + name = "github.com/influxdata/influxdb1-client" [[constraint]] name = "github.com/pkg/errors" diff --git a/core/unifi/clients.go b/core/unifi/clients.go index 1a87c9cd..51e0c8e2 100644 --- a/core/unifi/clients.go +++ b/core/unifi/clients.go @@ -4,12 +4,12 @@ import ( "strconv" "time" - influx "github.com/influxdata/influxdb/client/v2" + influx "github.com/influxdata/influxdb1-client/v2" ) // Points generates Unifi Client datapoints for InfluxDB. // These points can be passed directly to influx. -func (c *UCL) Points() ([]*influx.Point, error) { +func (c UCL) Points() ([]*influx.Point, error) { var points []*influx.Point // Fix name and hostname fields. Sometimes one or the other is blank. if c.Name == "" && c.Hostname != "" { diff --git a/core/unifi/uap.go b/core/unifi/uap.go index 6f62a107..81039f6e 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -4,12 +4,12 @@ import ( "strconv" "time" - influx "github.com/influxdata/influxdb/client/v2" + influx "github.com/influxdata/influxdb1-client/v2" ) // 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) { /* 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/unidev_test.go b/core/unifi/unidev_test.go index 32f3d266..35b31704 100644 --- a/core/unifi/unidev_test.go +++ b/core/unifi/unidev_test.go @@ -72,7 +72,7 @@ func TestAuthController(t *testing.T) { t.Parallel() a := assert.New(t) url := "http://127.0.0.1:64431" - authReq, err := AuthController("user1", "pass2", url, false) + authReq, err := GetController("user1", "pass2", url, false) a.NotNil(err) a.EqualValues(url, authReq.baseURL) a.Contains(err.Error(), "authReq.Do(req):", "an invalid destination should product a .Do(req) error.") diff --git a/core/unifi/usg.go b/core/unifi/usg.go index 1794d6c2..9f41646a 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg.go @@ -4,12 +4,12 @@ import ( "strconv" "time" - influx "github.com/influxdata/influxdb/client/v2" + influx "github.com/influxdata/influxdb1-client/v2" ) // 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) { var points []*influx.Point tags := map[string]string{ "id": u.ID, diff --git a/core/unifi/usw.go b/core/unifi/usw.go index b6b4bc25..760ba833 100644 --- a/core/unifi/usw.go +++ b/core/unifi/usw.go @@ -4,12 +4,12 @@ import ( "strconv" "time" - influx "github.com/influxdata/influxdb/client/v2" + influx "github.com/influxdata/influxdb1-client/v2" ) // 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) { var points []*influx.Point tags := map[string]string{ "id": u.ID, From c5c1907be7e88a230e09b3ede68bc58f33711e52 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 26 Jan 2019 12:51:08 -0800 Subject: [PATCH 013/194] Wrap clients in a struct too. --- core/unifi/unidev.go | 5 +++++ core/unifi/unifi.go | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/core/unifi/unidev.go b/core/unifi/unidev.go index 7f2d7f54..0738e0fa 100644 --- a/core/unifi/unidev.go +++ b/core/unifi/unidev.go @@ -34,6 +34,11 @@ type Devices struct { USWs []USW } +// Clients conptains a list of all the unifi clients from a controller. +type Clients struct { + UCLs []UCL +} + // Unifi is what you get in return for providing a password! type Unifi struct { *http.Client diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 5c2645af..2c62af33 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -8,7 +8,7 @@ import ( ) // GetClients returns a response full of clients' data from the Unifi Controller. -func (u *Unifi) GetClients() ([]UCL, error) { +func (u *Unifi) GetClients() (*Clients, error) { var response struct { Clients []UCL `json:"data"` } @@ -28,7 +28,7 @@ func (u *Unifi) GetClients() ([]UCL, error) { } else if err = json.Unmarshal(body, &response); err != nil { return nil, errors.Wrap(err, "json.Unmarshal([]UCL)") } - return response.Clients, nil + return &Clients{UCLs: response.Clients}, nil } // GetDevices returns a response full of devices' data from the Unifi Controller. From 8659adfcb24b7cd00f58ba71c25aa19c82b069cc Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 26 Jan 2019 12:58:38 -0800 Subject: [PATCH 014/194] Make these easier to find. --- core/unifi/unifi.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 2c62af33..c53c0eeb 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -60,9 +60,6 @@ func (u *Unifi) parseDevices(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 { - var usg USG - var usw USW - var uap UAP // Unamrshal into a map and check "type" var obj map[string]interface{} if err := json.Unmarshal(r, &obj); err != nil { @@ -77,18 +74,21 @@ func (u *Unifi) parseDevices(data []json.RawMessage) *Devices { // Unmarshal again into the correct type.. switch assetType { case "uap": + var uap UAP if err := json.Unmarshal(r, &uap); err != nil { 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. + var usg USG if err := json.Unmarshal(r, &usg); err != nil { u.eLogf("%d: json.Unmarshal([]USG): %v", i, err) continue } devices.USGs = append(devices.USGs, usg) case "usw": + var usw USW if err := json.Unmarshal(r, &usw); err != nil { u.eLogf("%d: json.Unmarshal([]USW): %v", i, err) continue From 7ac3b0e1f3c2e6da7f097595b0add537ba3826c1 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 26 Jan 2019 13:00:15 -0800 Subject: [PATCH 015/194] Cleanup --- core/unifi/unifi.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index c53c0eeb..5d9e2999 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -33,7 +33,7 @@ func (u *Unifi) GetClients() (*Clients, error) { // GetDevices returns a response full of devices' data from the Unifi Controller. func (u *Unifi) GetDevices() (*Devices, error) { - var parsed struct { + var response struct { Data []json.RawMessage `json:"data"` } req, err := u.UniReq(DevicePath, "") @@ -49,18 +49,17 @@ func (u *Unifi) GetDevices() (*Devices, error) { }() if body, err := ioutil.ReadAll(resp.Body); err != nil { return nil, errors.Wrap(err, "ioutil.ReadAll(resp.Body)") - } else if err = json.Unmarshal(body, &parsed); err != nil { + } else if err = json.Unmarshal(body, &response); err != nil { return nil, errors.Wrap(err, "json.Unmarshal([]json.RawMessage)") } - return u.parseDevices(parsed.Data), nil + return u.parseDevices(response.Data), nil } // parseDevices parses the raw JSON from the Unifi Controller into device structures. func (u *Unifi) parseDevices(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 { - // Unamrshal into a map and check "type" + // Loop each item in the raw JSON message, detect its type and unmarshal it. var obj map[string]interface{} if err := json.Unmarshal(r, &obj); err != nil { u.eLogf("%d: json.Unmarshal(interfce{}): %v", i, err) From 15558b09a591ccb1fbcb34a226032199f009a9a7 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 26 Jan 2019 13:14:27 -0800 Subject: [PATCH 016/194] still polishing. --- core/unifi/unidev.go | 5 ++++- core/unifi/unifi.go | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/unifi/unidev.go b/core/unifi/unidev.go index 0738e0fa..6bac2970 100644 --- a/core/unifi/unidev.go +++ b/core/unifi/unidev.go @@ -7,6 +7,7 @@ import ( "net/http" "net/http/cookiejar" "strconv" + "strings" "github.com/pkg/errors" ) @@ -87,7 +88,9 @@ func GetController(user, pass, url string, verifySSL bool) (*Unifi, error) { Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !verifySSL}}, Jar: jar, }, - baseURL: url, + } + if u.baseURL = url; strings.HasSuffix(url, "/") { + u.baseURL = url[:len(url)-1] } req, err := u.UniReq(LoginPath, json) if err != nil { diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 5d9e2999..b9a337d2 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -94,7 +94,7 @@ func (u *Unifi) parseDevices(data []json.RawMessage) *Devices { } devices.USWs = append(devices.USWs, usw) default: - u.dLogf("unknown asset type - " + assetType + " - skipping") + u.eLogf("unknown asset type - %v - skipping", assetType) continue } } From 43877afa4dbb20d2d05c71398ee46ba8b09cd82b Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 26 Jan 2019 13:15:55 -0800 Subject: [PATCH 017/194] readme fix --- core/unifi/README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/core/unifi/README.md b/core/unifi/README.md index f4dd4fab..3325c94a 100644 --- a/core/unifi/README.md +++ b/core/unifi/README.md @@ -25,15 +25,15 @@ func main() { if err != nil { log.Fatalln("Error:", err) } - // Log with log.Printf or make your own interface that accepts (msg, fmt) - uni.ErrorLog = log.Printf - uni.DebugLog = log.Printf + // Log with log.Printf or make your own interface that accepts (msg, fmt) + uni.ErrorLog = log.Printf + uni.DebugLog = log.Printf clients, err := uni.GetClients() if err != nil { log.Fatalln("Error:", err) } - log.Println(len(clients), "Clients connected:") - for i, client := range clients { + log.Println(len(clients.UCLs), "Clients connected:") + for i, client := range clients.UCLs { log.Println(i+1, client.ID, client.Hostname, client.IP, client.Name, client.LastSeen) } devices, err := uni.GetDevices() @@ -48,4 +48,5 @@ func main() { log.Println(i+1, uap.Name, uap.IP) } } + ``` From c84b1d50fc5ec26759f8441006603cccdaf83ace Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 26 Jan 2019 13:18:12 -0800 Subject: [PATCH 018/194] fix license since this code was copied from an old project --- core/unifi/LICENSE | 1 + 1 file changed, 1 insertion(+) diff --git a/core/unifi/LICENSE b/core/unifi/LICENSE index 4257b091..5666337f 100644 --- a/core/unifi/LICENSE +++ b/core/unifi/LICENSE @@ -1,6 +1,7 @@ MIT License Copyright (c) 2019 Go Lift - Building Strong Go Tools +Copyright (c) 2018 David Newhall II Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 24d4b4f0a7ef6f1173ca3787a3a8cdd72482acf7 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 26 Jan 2019 15:52:41 -0800 Subject: [PATCH 019/194] fix license again. --- core/unifi/LICENSE | 1 + 1 file changed, 1 insertion(+) diff --git a/core/unifi/LICENSE b/core/unifi/LICENSE index 5666337f..9187a167 100644 --- a/core/unifi/LICENSE +++ b/core/unifi/LICENSE @@ -2,6 +2,7 @@ MIT License Copyright (c) 2019 Go Lift - Building Strong Go Tools Copyright (c) 2018 David Newhall II +Copyright (c) 2016 Garrett Bjerkhoel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From bd77a2f80855ccb07b09be7fe865f3179c21a3cc Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 30 Mar 2019 15:55:50 -0700 Subject: [PATCH 020/194] Add FlexBool type and output failed payloads in debug mode. --- core/unifi/unidev.go | 17 +++++++++++++++ core/unifi/unifi.go | 47 ++++++++++++++++++++++++------------------ core/unifi/usg.go | 4 ++-- core/unifi/usg_type.go | 10 ++++----- 4 files changed, 51 insertions(+), 27 deletions(-) diff --git a/core/unifi/unidev.go b/core/unifi/unidev.go index 6bac2970..cd5d6db4 100644 --- a/core/unifi/unidev.go +++ b/core/unifi/unidev.go @@ -75,6 +75,23 @@ func (f *FlexInt) UnmarshalJSON(b []byte) error { } } +// FlexBool provides a container and unmarshalling for fields that may be +// boolean or strings in the Unifi API +type FlexBool struct { + Bool bool + String string +} + +// UnmarshalJSO method converts armed/disarmed, yes/no, active/inactive or 0/1 to true/false. +// Really it converts ready, up, t, armed, yes, active, enabled, 1, true to true. Anything else is false. +func (f *FlexBool) UnmarshalJSON(b []byte) error { + f.String = strings.Trim(string(b), `"`) + f.Bool = f.String == "1" || strings.EqualFold(f.String, "true") || strings.EqualFold(f.String, "yes") || + strings.EqualFold(f.String, "t") || strings.EqualFold(f.String, "armed") || strings.EqualFold(f.String, "active") || + strings.EqualFold(f.String, "enabled") || strings.EqualFold(f.String, "ready") || strings.EqualFold(f.String, "up") + return nil +} + // GetController creates a http.Client with authenticated cookies. // Used to make additional, authenticated requests to the APIs. func GetController(user, pass, url string, verifySSL bool) (*Unifi, error) { diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index b9a337d2..b8b9c0e8 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -58,11 +58,14 @@ func (u *Unifi) GetDevices() (*Devices, error) { // parseDevices parses the raw JSON from the Unifi Controller into device structures. func (u *Unifi) parseDevices(data []json.RawMessage) *Devices { devices := new(Devices) - for i, r := range data { + for _, r := range data { // Loop each item in the raw JSON message, detect its type and unmarshal it. var obj map[string]interface{} - if err := json.Unmarshal(r, &obj); err != nil { - u.eLogf("%d: json.Unmarshal(interfce{}): %v", i, err) + var uap UAP + var usg USG + var usw USW + + if u.unmarshalDevice("interface{}", &obj, r) != nil { continue } assetType := "" @@ -70,29 +73,19 @@ func (u *Unifi) parseDevices(data []json.RawMessage) *Devices { assetType = t } u.dLogf("Unmarshalling Device Type: %v", assetType) - // Unmarshal again into the correct type.. - switch assetType { + switch assetType { // Unmarshal again into the correct type.. case "uap": - var uap UAP - if err := json.Unmarshal(r, &uap); err != nil { - u.eLogf("%d: json.Unmarshal([]UAP): %v", i, err) - continue + if u.unmarshalDevice(assetType, &uap, r) == nil { + devices.UAPs = append(devices.UAPs, uap) } - devices.UAPs = append(devices.UAPs, uap) case "ugw", "usg": // in case they ever fix the name in the api. - var usg USG - if err := json.Unmarshal(r, &usg); err != nil { - u.eLogf("%d: json.Unmarshal([]USG): %v", i, err) - continue + if u.unmarshalDevice(assetType, &usg, r) == nil { + devices.USGs = append(devices.USGs, usg) } - devices.USGs = append(devices.USGs, usg) case "usw": - var usw USW - if err := json.Unmarshal(r, &usw); err != nil { - u.eLogf("%d: json.Unmarshal([]USW): %v", i, err) - continue + if u.unmarshalDevice(assetType, &usw, r) == nil { + devices.USWs = append(devices.USWs, usw) } - devices.USWs = append(devices.USWs, usw) default: u.eLogf("unknown asset type - %v - skipping", assetType) continue @@ -100,3 +93,17 @@ func (u *Unifi) parseDevices(data []json.RawMessage) *Devices { } return devices } + +// unmarshalDevice handles logging for the unmarshal operations in parseDevices(). +func (u *Unifi) unmarshalDevice(device string, ptr interface{}, payload json.RawMessage) error { + err := json.Unmarshal(payload, ptr) + if err != nil { + u.eLogf("json.Unmarshal(%v): %v", device, err) + u.eLogf("Enable Debug Logging to output the failed payload.") + json, err := payload.MarshalJSON() + u.dLogf("Failed Payload: %s (marshal err: %v)", json, err) + u.dLogf("The above payload can prove useful during torubleshooting when you open an Issue:") + u.dLogf("==- https://github.com/golift/unifi/issues/new -==") + } + return err +} diff --git a/core/unifi/usg.go b/core/unifi/usg.go index 9f41646a..894f33b4 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg.go @@ -92,7 +92,7 @@ func (u USG) Points() ([]*influx.Point, error) { "wan1_rx_packets": u.Wan1.RxPackets, "wan1_type": u.Wan1.Type, "wan1_speed": u.Wan1.Speed, - "wan1_up": u.Wan1.Up, + "wan1_up": u.Wan1.Up.Bool, "wan1_tx_bytes": u.Wan1.TxBytes, "wan1_tx_bytes-r": u.Wan1.TxBytesR, "wan1_tx_dropped": u.Wan1.TxDropped, @@ -170,7 +170,7 @@ func (u USG) Points() ([]*influx.Point, error) { "rx_packets": p.RxPackets, "tx_bytes": p.TxBytes, "tx_packets": p.TxPackets, - "up": p.Up, + "up": p.Up.String, "vlan": p.Vlan, "dhcpd_ntp_1": p.DhcpdNtp1, "dhcpd_unifi_controller": p.DhcpdUnifiController, diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index ebbe1b8d..3b29103a 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -70,7 +70,7 @@ type USG struct { SiteID string `json:"site_id"` TxBytes float64 `json:"tx_bytes"` TxPackets float64 `json:"tx_packets"` - Up string `json:"up"` + Up FlexBool `json:"up"` Vlan string `json:"vlan,omitempty"` VlanEnabled bool `json:"vlan_enabled"` DhcpRelayEnabled bool `json:"dhcp_relay_enabled,omitempty"` @@ -110,7 +110,7 @@ type USG struct { TxDropped float64 `json:"tx_dropped"` TxErrors float64 `json:"tx_errors"` TxPackets float64 `json:"tx_packets"` - Up bool `json:"up"` + Up FlexBool `json:"up"` } `json:"port_table"` Rollupgrade bool `json:"rollupgrade"` RxBytes float64 `json:"rx_bytes"` @@ -193,7 +193,7 @@ type USG struct { TxErrors float64 `json:"tx_errors"` TxPackets float64 `json:"tx_packets"` Type string `json:"type"` - Up bool `json:"up"` + Up FlexBool `json:"up"` Uptime float64 `json:"uptime"` XputDown float64 `json:"xput_down"` XputUp float64 `json:"xput_up"` @@ -228,7 +228,7 @@ type USG struct { TxErrors float64 `json:"tx_errors"` TxPackets float64 `json:"tx_packets"` Type string `json:"type"` - Up bool `json:"up"` + Up FlexBool `json:"up"` } `json:"wan1"` Wan2 struct { BytesR float64 `json:"bytes-r"` @@ -255,6 +255,6 @@ type USG struct { TxErrors float64 `json:"tx_errors"` TxPackets float64 `json:"tx_packets"` Type string `json:"type"` - Up bool `json:"up"` + Up FlexBool `json:"up"` } `json:"wan2"` } From cf879d8377d0d62f02cceffef33b099ba24e768c Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Apr 2019 20:34:21 -0700 Subject: [PATCH 021/194] Fix bugs in uap collection. --- core/unifi/uap.go | 42 +++++++++++++++++++++--------------------- core/unifi/unidev.go | 2 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/core/unifi/uap.go b/core/unifi/uap.go index 81039f6e..dec42a5f 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -222,41 +222,41 @@ func (u UAP) Points() ([]*influx.Point, error) { fields["radio_tx_power"] = s.TxPower fields["radio_tx_retries"] = s.TxRetries fields["user-num_sta"] = s.UserNumSta - continue + break } } for _, s := range u.VapTable { if p.Name == s.RadioName { tags["ap_mac"] = s.ApMac tags["bssid"] = s.Bssid + tags["vap_id"] = s.ID + tags["vap_name"] = s.Name + tags["wlanconf_id"] = s.WlanconfID fields["ccq"] = s.Ccq fields["essid"] = s.Essid fields["extchannel"] = s.Extchannel - tags["vap_id"] = s.ID fields["is_guest"] = s.IsGuest fields["is_wep"] = s.IsWep fields["mac_filter_rejections"] = s.MacFilterRejections fields["map_id"] = s.MapID - tags["vap_name"] = s.Name - fields["rx_bytes"] = s.RxBytes - fields["rx_crypts"] = s.RxCrypts - fields["rx_dropped"] = s.RxDropped - fields["rx_errors"] = s.RxErrors - fields["rx_frags"] = s.RxFrags - fields["rx_nwids"] = s.RxNwids - fields["rx_packets"] = s.RxPackets - fields["tx_bytes"] = s.TxBytes - fields["tx_dropped"] = s.TxDropped - fields["tx_errors"] = s.TxErrors - fields["tx_latency_avg"] = s.TxLatencyAvg - fields["tx_latency_max"] = s.TxLatencyMax - fields["tx_latency_min"] = s.TxLatencyMin - fields["tx_packets"] = s.TxPackets - fields["tx_power"] = s.TxPower - fields["tx_retries"] = s.TxRetries + fields["vap_rx_bytes"] = s.RxBytes + fields["vap_rx_crypts"] = s.RxCrypts + fields["vap_rx_dropped"] = s.RxDropped + fields["vap_rx_errors"] = s.RxErrors + fields["vap_rx_frags"] = s.RxFrags + fields["vap_rx_nwids"] = s.RxNwids + fields["vap_rx_packets"] = s.RxPackets + fields["vap_tx_bytes"] = s.TxBytes + fields["vap_tx_dropped"] = s.TxDropped + fields["vap_tx_errors"] = s.TxErrors + fields["vap_tx_latency_avg"] = s.TxLatencyAvg + fields["vap_tx_latency_max"] = s.TxLatencyMax + fields["vap_tx_latency_min"] = s.TxLatencyMin + fields["vap_tx_packets"] = s.TxPackets + fields["vap_tx_power"] = s.TxPower + fields["vap_tx_retries"] = s.TxRetries fields["usage"] = s.Usage - tags["wlanconf_id"] = s.WlanconfID - continue + break } } pt, err := influx.NewPoint("uap_radios", tags, fields, time.Now()) diff --git a/core/unifi/unidev.go b/core/unifi/unidev.go index cd5d6db4..48d37271 100644 --- a/core/unifi/unidev.go +++ b/core/unifi/unidev.go @@ -82,7 +82,7 @@ type FlexBool struct { String string } -// UnmarshalJSO method converts armed/disarmed, yes/no, active/inactive or 0/1 to true/false. +// UnmarshalJSON method converts armed/disarmed, yes/no, active/inactive or 0/1 to true/false. // Really it converts ready, up, t, armed, yes, active, enabled, 1, true to true. Anything else is false. func (f *FlexBool) UnmarshalJSON(b []byte) error { f.String = strings.Trim(string(b), `"`) From 3a91d5ab65dba8dd5d9c31eaefbb8f96966960fa Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Apr 2019 20:39:44 -0700 Subject: [PATCH 022/194] Convert all tx_powers to floats. --- core/unifi/uap.go | 4 ++-- core/unifi/uap_type.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/unifi/uap.go b/core/unifi/uap.go index dec42a5f..edd1fc54 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -219,7 +219,7 @@ func (u UAP) Points() ([]*influx.Point, error) { fields["radio"] = s.Radio fields["state"] = s.State fields["radio_tx_packets"] = s.TxPackets - fields["radio_tx_power"] = s.TxPower + fields["radio_tx_power"] = s.TxPower.Number fields["radio_tx_retries"] = s.TxRetries fields["user-num_sta"] = s.UserNumSta break @@ -253,7 +253,7 @@ func (u UAP) Points() ([]*influx.Point, error) { fields["vap_tx_latency_max"] = s.TxLatencyMax fields["vap_tx_latency_min"] = s.TxLatencyMin fields["vap_tx_packets"] = s.TxPackets - fields["vap_tx_power"] = s.TxPower + fields["vap_tx_power"] = s.TxPower.Number fields["vap_tx_retries"] = s.TxRetries fields["usage"] = s.Usage break diff --git a/core/unifi/uap_type.go b/core/unifi/uap_type.go index 2d61b324..cf930920 100644 --- a/core/unifi/uap_type.go +++ b/core/unifi/uap_type.go @@ -152,7 +152,7 @@ type UAP struct { Radio string `json:"radio"` State string `json:"state"` TxPackets float64 `json:"tx_packets"` - TxPower float64 `json:"tx_power"` + TxPower FlexInt `json:"tx_power"` TxRetries float64 `json:"tx_retries"` UserNumSta float64 `json:"user-num_sta"` } `json:"radio_table_stats"` @@ -341,7 +341,7 @@ type UAP struct { TxLatencyMax float64 `json:"tx_latency_max"` TxLatencyMin float64 `json:"tx_latency_min"` TxPackets float64 `json:"tx_packets"` - TxPower int `json:"tx_power"` + TxPower FlexInt `json:"tx_power"` TxRetries int `json:"tx_retries"` Up bool `json:"up"` Usage string `json:"usage"` From e15602ccfab29e05ae23cb15a710229ebfad73a7 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Mon, 15 Apr 2019 01:21:24 -0700 Subject: [PATCH 023/194] Add sites support. This changes the interface. --- core/unifi/unidev.go | 10 +++--- core/unifi/unifi.go | 86 ++++++++++++++++++++++++++++---------------- 2 files changed, 62 insertions(+), 34 deletions(-) diff --git a/core/unifi/unidev.go b/core/unifi/unidev.go index cd5d6db4..85f7f86e 100644 --- a/core/unifi/unidev.go +++ b/core/unifi/unidev.go @@ -13,14 +13,16 @@ import ( ) const ( + // SiteList is the path to the api site list. + SiteList string = "/api/self/sites" // ClientPath is Unifi Clients API Path - ClientPath string = "/api/s/default/stat/sta" + ClientPath string = "/api/s/%s/stat/sta" // DevicePath is where we get data about Unifi devices. - DevicePath string = "/api/s/default/stat/device" + DevicePath string = "/api/s/%s/stat/device" // NetworkPath contains network-configuration data. Not really graphable. - NetworkPath string = "/api/s/default/rest/networkconf" + NetworkPath string = "/api/s/%s/rest/networkconf" // UserGroupPath contains usergroup configurations. - UserGroupPath string = "/api/s/default/rest/usergroup" + UserGroupPath string = "/api/s/%s/rest/usergroup" // LoginPath is Unifi Controller Login API Path LoginPath string = "/api/login" ) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index b8b9c0e8..8ab4e910 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -2,57 +2,83 @@ package unifi import ( "encoding/json" + "fmt" "io/ioutil" + "strings" "github.com/pkg/errors" ) // GetClients returns a response full of clients' data from the Unifi Controller. -func (u *Unifi) GetClients() (*Clients, error) { - var response struct { - Clients []UCL `json:"data"` +func (u *Unifi) GetClients(sites []string) (*Clients, error) { + var data []UCL + for _, site := range sites { + var response struct { + Data []UCL `json:"data"` + } + clientPath := fmt.Sprintf(ClientPath, site) + if err := u.GetData(clientPath, &response); err != nil { + return nil, err + } + data = append(data, response.Data...) } - req, err := u.UniReq(ClientPath, "") - if err != nil { - return nil, errors.Wrap(err, "c.UniReq(ClientPath)") - } - resp, err := u.Do(req) - if err != nil { - return nil, errors.Wrap(err, "c.Do(req)") - } - defer func() { - _ = resp.Body.Close() - }() - if body, err := ioutil.ReadAll(resp.Body); err != nil { - return nil, errors.Wrap(err, "ioutil.ReadAll(resp.Body)") - } else if err = json.Unmarshal(body, &response); err != nil { - return nil, errors.Wrap(err, "json.Unmarshal([]UCL)") - } - return &Clients{UCLs: response.Clients}, nil + return &Clients{UCLs: data}, nil } // GetDevices returns a response full of devices' data from the Unifi Controller. -func (u *Unifi) GetDevices() (*Devices, error) { - var response struct { - Data []json.RawMessage `json:"data"` +func (u *Unifi) GetDevices(sites []string) (*Devices, error) { + var data []json.RawMessage + for _, site := range sites { + var response struct { + Data []json.RawMessage `json:"data"` + } + devicePath := fmt.Sprintf(DevicePath, site) + if err := u.GetData(devicePath, &response); err != nil { + return nil, err + } + data = append(data, response.Data...) } - req, err := u.UniReq(DevicePath, "") + return u.parseDevices(data), nil +} + +// GetSites returns a list of configured sites on the Unifi controller. +func (u *Unifi) GetSites() ([]string, error) { + var response struct { + Data []struct { + // This is the only field we need. There are others. + Name string `json:"name"` + } `json:"data"` + } + if err := u.GetData(SiteList, &response); err != nil { + return nil, err + } + var output []string + for i := range response.Data { + output = append(output, response.Data[i].Name) + } + u.dLogf("Found %d sites: %v", len(output), strings.Join(output, ",")) + return output, nil +} + +// GetData makes a unifi request and unmarshal the response into a provided pointer. +func (u *Unifi) GetData(methodPath string, v interface{}) error { + req, err := u.UniReq(methodPath, "") if err != nil { - return nil, errors.Wrap(err, "c.UniReq(DevicePath)") + return errors.Wrapf(err, "c.UniReq(%v)", methodPath) } resp, err := u.Do(req) if err != nil { - return nil, errors.Wrap(err, "c.Do(req)") + return errors.Wrapf(err, "c.Do(%v)", methodPath) } defer func() { _ = resp.Body.Close() }() if body, err := ioutil.ReadAll(resp.Body); err != nil { - return nil, errors.Wrap(err, "ioutil.ReadAll(resp.Body)") - } else if err = json.Unmarshal(body, &response); err != nil { - return nil, errors.Wrap(err, "json.Unmarshal([]json.RawMessage)") + return errors.Wrapf(err, "ioutil.ReadAll(%v)", methodPath) + } else if err = json.Unmarshal(body, v); err != nil { + return errors.Wrapf(err, "json.Unmarshal(%v)", methodPath) } - return u.parseDevices(response.Data), nil + return nil } // parseDevices parses the raw JSON from the Unifi Controller into device structures. From f5f4cb0720ed5d9dcf7326e7af12afd66490b4d2 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Mon, 15 Apr 2019 02:08:58 -0700 Subject: [PATCH 024/194] Add better logs. --- core/unifi/unifi.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 8ab4e910..8e42e301 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -16,6 +16,8 @@ func (u *Unifi) GetClients(sites []string) (*Clients, error) { var response struct { Data []UCL `json:"data"` } + u.dLogf("Polling Site '%s' Clients", site) + u.dLogf("Unmarshalling Device Type: ucl") clientPath := fmt.Sprintf(ClientPath, site) if err := u.GetData(clientPath, &response); err != nil { return nil, err @@ -29,6 +31,7 @@ func (u *Unifi) GetClients(sites []string) (*Clients, error) { func (u *Unifi) GetDevices(sites []string) (*Devices, error) { var data []json.RawMessage for _, site := range sites { + u.dLogf("Polling Site '%s' Devices", site) var response struct { Data []json.RawMessage `json:"data"` } @@ -56,7 +59,7 @@ func (u *Unifi) GetSites() ([]string, error) { for i := range response.Data { output = append(output, response.Data[i].Name) } - u.dLogf("Found %d sites: %v", len(output), strings.Join(output, ",")) + u.dLogf("Found %d sites: %s", len(output), strings.Join(output, ",")) return output, nil } @@ -64,19 +67,19 @@ func (u *Unifi) GetSites() ([]string, error) { func (u *Unifi) GetData(methodPath string, v interface{}) error { req, err := u.UniReq(methodPath, "") if err != nil { - return errors.Wrapf(err, "c.UniReq(%v)", methodPath) + return errors.Wrapf(err, "c.UniReq(%s)", methodPath) } resp, err := u.Do(req) if err != nil { - return errors.Wrapf(err, "c.Do(%v)", methodPath) + return errors.Wrapf(err, "c.Do(%s)", methodPath) } defer func() { _ = resp.Body.Close() }() if body, err := ioutil.ReadAll(resp.Body); err != nil { - return errors.Wrapf(err, "ioutil.ReadAll(%v)", methodPath) + return errors.Wrapf(err, "ioutil.ReadAll(%s)", methodPath) } else if err = json.Unmarshal(body, v); err != nil { - return errors.Wrapf(err, "json.Unmarshal(%v)", methodPath) + return errors.Wrapf(err, "json.Unmarshal(%s)", methodPath) } return nil } From 8948b01d418159b6560973bd4c093f92b5f3ee0f Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Mon, 15 Apr 2019 02:26:43 -0700 Subject: [PATCH 025/194] Use new Site type. --- core/unifi/unifi.go | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 8e42e301..1cc11bb6 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -10,15 +10,15 @@ import ( ) // GetClients returns a response full of clients' data from the Unifi Controller. -func (u *Unifi) GetClients(sites []string) (*Clients, error) { +func (u *Unifi) GetClients(sites []Site) (*Clients, error) { var data []UCL for _, site := range sites { var response struct { Data []UCL `json:"data"` } - u.dLogf("Polling Site '%s' Clients", site) + u.dLogf("Polling Site '%s' (%s) Clients", site.Name, site.Desc) u.dLogf("Unmarshalling Device Type: ucl") - clientPath := fmt.Sprintf(ClientPath, site) + clientPath := fmt.Sprintf(ClientPath, site.Name) if err := u.GetData(clientPath, &response); err != nil { return nil, err } @@ -28,14 +28,14 @@ func (u *Unifi) GetClients(sites []string) (*Clients, error) { } // GetDevices returns a response full of devices' data from the Unifi Controller. -func (u *Unifi) GetDevices(sites []string) (*Devices, error) { +func (u *Unifi) GetDevices(sites []Site) (*Devices, error) { var data []json.RawMessage for _, site := range sites { - u.dLogf("Polling Site '%s' Devices", site) + u.dLogf("Polling Site '%s' (%s) Devices", site.Name, site.Desc) var response struct { Data []json.RawMessage `json:"data"` } - devicePath := fmt.Sprintf(DevicePath, site) + devicePath := fmt.Sprintf(DevicePath, site.Name) if err := u.GetData(devicePath, &response); err != nil { return nil, err } @@ -44,23 +44,26 @@ func (u *Unifi) GetDevices(sites []string) (*Devices, error) { return u.parseDevices(data), nil } +// Site represents a site's data. There are more pieces to this. +type Site struct { + Name string `json:"name"` + Desc string `json:"desc"` +} + // GetSites returns a list of configured sites on the Unifi controller. -func (u *Unifi) GetSites() ([]string, error) { +func (u *Unifi) GetSites() ([]Site, error) { var response struct { - Data []struct { - // This is the only field we need. There are others. - Name string `json:"name"` - } `json:"data"` + Data []Site `json:"data"` } if err := u.GetData(SiteList, &response); err != nil { return nil, err } - var output []string + var sites []string for i := range response.Data { - output = append(output, response.Data[i].Name) + sites = append(sites, response.Data[i].Name) } - u.dLogf("Found %d sites: %s", len(output), strings.Join(output, ",")) - return output, nil + u.dLogf("Found %d sites: %s", len(sites), strings.Join(sites, ",")) + return response.Data, nil } // GetData makes a unifi request and unmarshal the response into a provided pointer. From e2d886da72251613b5758218dbecdf8bd37df757 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 17 Apr 2019 00:16:22 -0700 Subject: [PATCH 026/194] Re-arrange --- core/unifi/README.md | 20 ++- core/unifi/{clients.go => clients_influx.go} | 0 core/unifi/parsers.go | 56 +++++++ core/unifi/types.go | 120 ++++++++++++++ core/unifi/types_test.go | 36 +++++ core/unifi/{uap.go => uap_influx.go} | 8 +- core/unifi/uap_type.go | 2 +- core/unifi/unidev.go | 157 ------------------- core/unifi/unifi.go | 107 +++++++------ core/unifi/{unidev_test.go => unifi_test.go} | 47 ++---- core/unifi/{usg.go => usg_influx.go} | 6 +- core/unifi/usg_type.go | 2 +- core/unifi/{usw.go => usw_influx.go} | 2 +- core/unifi/usw_type.go | 2 +- 14 files changed, 304 insertions(+), 261 deletions(-) rename core/unifi/{clients.go => clients_influx.go} (100%) create mode 100644 core/unifi/parsers.go create mode 100644 core/unifi/types.go create mode 100644 core/unifi/types_test.go rename core/unifi/{uap.go => uap_influx.go} (98%) delete mode 100644 core/unifi/unidev.go rename core/unifi/{unidev_test.go => unifi_test.go} (70%) rename core/unifi/{usg.go => usg_influx.go} (98%) rename core/unifi/{usw.go => usw_influx.go} (98%) diff --git a/core/unifi/README.md b/core/unifi/README.md index 3325c94a..cbe77503 100644 --- a/core/unifi/README.md +++ b/core/unifi/README.md @@ -8,6 +8,8 @@ data. The data is provided in a large struct you can consume in your application This library also contains methods to export the Unifi data in InfluxDB format, and this can be used as an example to base your own metrics collection methods. +If more features are requested, I'll certainly consider them. Do you need to do +more than just collect data? [Let me know](https://github.com/golift/unifi/issues/new)! Pull requests and feedback are welcomed! Here's a working example: @@ -28,18 +30,25 @@ func main() { // Log with log.Printf or make your own interface that accepts (msg, fmt) uni.ErrorLog = log.Printf uni.DebugLog = log.Printf - clients, err := uni.GetClients() + + sites, err := uni.GetSites() if err != nil { log.Fatalln("Error:", err) } + clients, err := uni.GetClients(sites) + if err != nil { + log.Fatalln("Error:", err) + } + devices, err := uni.GetDevices(sites) + if err != nil { + log.Fatalln("Error:", err) + } + log.Println(len(clients.UCLs), "Clients connected:") for i, client := range clients.UCLs { log.Println(i+1, client.ID, client.Hostname, client.IP, client.Name, client.LastSeen) } - devices, err := uni.GetDevices() - if err != nil { - log.Fatalln("Error:", err) - } + log.Println(len(devices.USWs), "Unifi Switches Found") log.Println(len(devices.USGs), "Unifi Gateways Found") @@ -48,5 +57,4 @@ func main() { log.Println(i+1, uap.Name, uap.IP) } } - ``` diff --git a/core/unifi/clients.go b/core/unifi/clients_influx.go similarity index 100% rename from core/unifi/clients.go rename to core/unifi/clients_influx.go diff --git a/core/unifi/parsers.go b/core/unifi/parsers.go new file mode 100644 index 00000000..5b324282 --- /dev/null +++ b/core/unifi/parsers.go @@ -0,0 +1,56 @@ +package unifi + +import "encoding/json" + +// parseDevices parses the raw JSON from the Unifi Controller into device structures. +func (u *Unifi) parseDevices(data []json.RawMessage) *Devices { + devices := new(Devices) + for _, r := range data { + // Loop each item in the raw JSON message, detect its type and unmarshal it. + var obj map[string]interface{} + var uap UAP + var usg USG + var usw USW + + if u.unmarshalDevice("interface{}", &obj, r) != nil { + continue + } + assetType := "" + if t, ok := obj["type"].(string); ok { + assetType = t + } + u.dLogf("Unmarshalling Device Type: %v", assetType) + switch assetType { // Unmarshal again into the correct type.. + case "uap": + if u.unmarshalDevice(assetType, &uap, r) == nil { + devices.UAPs = append(devices.UAPs, uap) + } + case "ugw", "usg": // in case they ever fix the name in the api. + if u.unmarshalDevice(assetType, &usg, r) == nil { + devices.USGs = append(devices.USGs, usg) + } + case "usw": + if u.unmarshalDevice(assetType, &usw, r) == nil { + devices.USWs = append(devices.USWs, usw) + } + default: + u.eLogf("unknown asset type - %v - skipping", assetType) + continue + } + } + return devices +} + +// unmarshalDevice handles logging for the unmarshal operations in parseDevices(). +func (u *Unifi) unmarshalDevice(device string, ptr interface{}, payload json.RawMessage) error { + err := json.Unmarshal(payload, ptr) + if err != nil { + u.eLogf("json.Unmarshal(%v): %v", device, err) + u.eLogf("Enable Debug Logging to output the failed payload.") + json, err := payload.MarshalJSON() + u.dLogf("Failed Payload: %s (marshal err: %v)", json, err) + u.dLogf("The above payload can prove useful during torubleshooting when you open an Issue:") + u.dLogf("==- https://github.com/golift/unifi/issues/new -==") + } + return err +} diff --git a/core/unifi/types.go b/core/unifi/types.go new file mode 100644 index 00000000..61266609 --- /dev/null +++ b/core/unifi/types.go @@ -0,0 +1,120 @@ +package unifi + +import ( + "encoding/json" + "net/http" + "strconv" + "strings" + + "github.com/pkg/errors" +) + +// This is a list of unifi API paths. +// The %s in each string must be replaced with a Site.Name. +const ( + // SiteList is the path to the api site list. + SiteList string = "/api/self/sites" + // ClientPath is Unifi Clients API Path + ClientPath string = "/api/s/%s/stat/sta" + // DevicePath is where we get data about Unifi devices. + DevicePath string = "/api/s/%s/stat/device" + // NetworkPath contains network-configuration data. Not really graphable. + NetworkPath string = "/api/s/%s/rest/networkconf" + // UserGroupPath contains usergroup configurations. + UserGroupPath string = "/api/s/%s/rest/usergroup" + // LoginPath is Unifi Controller Login API Path + LoginPath string = "/api/login" +) + +// Logger is a base type to deal with changing log outputs. Create a logger +// that matches this interface to capture debug and error logs. +type Logger func(msg string, fmt ...interface{}) + +// dLogf logs a debug message. +func (u *Unifi) dLogf(msg string, v ...interface{}) { + if u.DebugLog != nil { + u.DebugLog("[DEBUG] "+msg, v...) + } +} + +// dLogf logs an error message. +func (u *Unifi) eLogf(msg string, v ...interface{}) { + if u.ErrorLog != nil { + u.ErrorLog("[ERROR] "+msg, v...) + } +} + +// 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 +} + +// Clients contains a list that contains all of the unifi clients from a controller. +type Clients struct { + UCLs []UCL +} + +// Unifi is what you get in return for providing a password! Unifi represents +// a controller that you can make authenticated requests to. Use this to make +// additional requests for devices, clients or other custom data. +type Unifi struct { + *http.Client + baseURL string + ErrorLog Logger + DebugLog Logger +} + +// Site represents a site's data. There are more pieces to this, but this is +// all we expose. +type Site struct { + Name string `json:"name"` + Desc string `json:"desc"` +} + +// FlexInt provides a container and unmarshalling for fields that may be +// numbers or strings in the Unifi API. +type FlexInt struct { + Val float64 + Txt string +} + +// UnmarshalJSON converts a string or number to an integer. +// Generally, do call this directly, it's used in the json interface. +func (f *FlexInt) UnmarshalJSON(b []byte) error { + var unk interface{} + if err := json.Unmarshal(b, &unk); err != nil { + return err + } + switch i := unk.(type) { + case float64: + f.Val = i + f.Txt = strconv.FormatFloat(i, 'f', -1, 64) + return nil + case string: + f.Txt = i + f.Val, _ = strconv.ParseFloat(i, 64) + return nil + default: + return errors.New("Cannot unmarshal to FlexInt") + } +} + +// FlexBool provides a container and unmarshalling for fields that may be +// boolean or strings in the Unifi API. +type FlexBool struct { + Val bool + Txt string +} + +// UnmarshalJSO method converts armed/disarmed, yes/no, active/inactive or 0/1 to true/false. +// Really it converts ready, up, t, armed, yes, active, enabled, 1, true to true. Anything else is false. +func (f *FlexBool) UnmarshalJSON(b []byte) error { + f.Txt = strings.Trim(string(b), `"`) + f.Val = f.Txt == "1" || strings.EqualFold(f.Txt, "true") || strings.EqualFold(f.Txt, "yes") || + strings.EqualFold(f.Txt, "t") || strings.EqualFold(f.Txt, "armed") || strings.EqualFold(f.Txt, "active") || + strings.EqualFold(f.Txt, "enabled") || strings.EqualFold(f.Txt, "ready") || strings.EqualFold(f.Txt, "up") + return nil +} diff --git a/core/unifi/types_test.go b/core/unifi/types_test.go new file mode 100644 index 00000000..2b62cfcc --- /dev/null +++ b/core/unifi/types_test.go @@ -0,0 +1,36 @@ +package unifi + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFlexInt(t *testing.T) { + t.Parallel() + a := assert.New(t) + type testReply struct { + Five FlexInt `json:"five"` + Seven FlexInt `json:"seven"` + Auto FlexInt `json:"auto"` + Channel FlexInt `json:"channel"` + } + var r testReply + // test unmarshalling the custom type three times with different values. + a.Nil(json.Unmarshal([]byte(`{"five": "5", "seven": 7, "auto": "auto"}`), &r)) + + // test number in string. + a.EqualValues(5, r.Five.Val) + a.EqualValues("5", r.Five.Txt) + // test number. + a.EqualValues(7, r.Seven.Val) + a.EqualValues("7", r.Seven.Txt) + // test string. + a.EqualValues(0, r.Auto.Val) + a.EqualValues("auto", r.Auto.Txt) + // test (error) struct. + a.NotNil(json.Unmarshal([]byte(`{"channel": {}}`), &r), + "a non-string and non-number must produce an error.") + a.EqualValues(0, r.Channel.Val) +} diff --git a/core/unifi/uap.go b/core/unifi/uap_influx.go similarity index 98% rename from core/unifi/uap.go rename to core/unifi/uap_influx.go index 81039f6e..36789de8 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap_influx.go @@ -22,7 +22,7 @@ func (u UAP) Points() ([]*influx.Point, error) { "device_ap": u.Stat.Ap, "site_id": u.SiteID, "name": u.Name, - "addopted": strconv.FormatBool(u.Adopted), + "adopted": strconv.FormatBool(u.Adopted), "bandsteering_mode": u.BandsteeringMode, "board_rev": strconv.Itoa(u.BoardRev), "cfgversion": u.Cfgversion, @@ -63,7 +63,7 @@ func (u UAP) Points() ([]*influx.Point, error) { "rx_bytes-d": u.RxBytesD, "tx_bytes": u.TxBytes, "tx_bytes-d": u.TxBytesD, - "uptime": u.Uptime.Number, + "uptime": u.Uptime.Val, "considered_lost_at": u.ConsideredLostAt, "next_heartbeat_at": u.NextHeartbeatAt, "scanning": u.Scanning, @@ -182,7 +182,7 @@ func (u UAP) Points() ([]*influx.Point, error) { "device_mac": u.Mac, "name": p.Name, "wlangroup_id": p.WlangroupID, - "channel": p.Channel.String, + "channel": p.Channel.Txt, "radio": p.Radio, } fields := map[string]interface{}{ @@ -197,7 +197,7 @@ func (u UAP) Points() ([]*influx.Point, error) { "min_txpower": p.MinTxpower, "nss": p.Nss, "radio_caps": p.RadioCaps, - "tx_power": p.TxPower.Number, + "tx_power": p.TxPower.Val, "tx_power_mode": p.TxPowerMode, } diff --git a/core/unifi/uap_type.go b/core/unifi/uap_type.go index 2d61b324..b612f1dd 100644 --- a/core/unifi/uap_type.go +++ b/core/unifi/uap_type.go @@ -1,6 +1,6 @@ package unifi -// UAP represents all the data from the Ubiquit Controller for a Unifi Access Point. +// UAP represents all the data from the Ubiquiti 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 deleted file mode 100644 index cd5d6db4..00000000 --- a/core/unifi/unidev.go +++ /dev/null @@ -1,157 +0,0 @@ -package unifi - -import ( - "bytes" - "crypto/tls" - "encoding/json" - "net/http" - "net/http/cookiejar" - "strconv" - "strings" - - "github.com/pkg/errors" -) - -const ( - // ClientPath is Unifi Clients API Path - ClientPath string = "/api/s/default/stat/sta" - // DevicePath is where we get data about Unifi devices. - DevicePath string = "/api/s/default/stat/device" - // NetworkPath contains network-configuration data. Not really graphable. - NetworkPath string = "/api/s/default/rest/networkconf" - // UserGroupPath contains usergroup configurations. - UserGroupPath string = "/api/s/default/rest/usergroup" - // LoginPath is Unifi Controller Login API Path - LoginPath string = "/api/login" -) - -// Logger is a base type to deal with changing log outputs. -type Logger func(msg string, fmt ...interface{}) - -// Devices contains a list of all the unifi devices from a controller. -type Devices struct { - UAPs []UAP - USGs []USG - USWs []USW -} - -// Clients conptains a list of all the unifi clients from a controller. -type Clients struct { - UCLs []UCL -} - -// Unifi is what you get in return for providing a password! -type Unifi struct { - *http.Client - baseURL string - ErrorLog Logger - DebugLog Logger -} - -// FlexInt provides a container and unmarshalling for fields that may be -// numbers or strings in the Unifi API -type FlexInt struct { - Number float64 - String string -} - -// UnmarshalJSON converts a string or number to an integer. -func (f *FlexInt) UnmarshalJSON(b []byte) error { - var unk interface{} - if err := json.Unmarshal(b, &unk); err != nil { - return err - } - switch i := unk.(type) { - case float64: - f.Number = i - f.String = strconv.FormatFloat(i, 'f', -1, 64) - return nil - case string: - f.String = i - f.Number, _ = strconv.ParseFloat(i, 64) - return nil - default: - return errors.New("Cannot unmarshal to FlexInt") - } -} - -// FlexBool provides a container and unmarshalling for fields that may be -// boolean or strings in the Unifi API -type FlexBool struct { - Bool bool - String string -} - -// UnmarshalJSO method converts armed/disarmed, yes/no, active/inactive or 0/1 to true/false. -// Really it converts ready, up, t, armed, yes, active, enabled, 1, true to true. Anything else is false. -func (f *FlexBool) UnmarshalJSON(b []byte) error { - f.String = strings.Trim(string(b), `"`) - f.Bool = f.String == "1" || strings.EqualFold(f.String, "true") || strings.EqualFold(f.String, "yes") || - strings.EqualFold(f.String, "t") || strings.EqualFold(f.String, "armed") || strings.EqualFold(f.String, "active") || - strings.EqualFold(f.String, "enabled") || strings.EqualFold(f.String, "ready") || strings.EqualFold(f.String, "up") - return nil -} - -// GetController creates a http.Client with authenticated cookies. -// Used to make additional, authenticated requests to the APIs. -func GetController(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)") - } - u := &Unifi{ - Client: &http.Client{ - Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !verifySSL}}, - Jar: jar, - }, - } - if u.baseURL = url; strings.HasSuffix(url, "/") { - u.baseURL = url[:len(url)-1] - } - req, err := u.UniReq(LoginPath, json) - if err != nil { - return u, errors.Wrap(err, "UniReq(LoginPath, json)") - } - resp, err := u.Do(req) - if err != nil { - return u, errors.Wrap(err, "authReq.Do(req)") - } - defer func() { - _ = resp.Body.Close() - }() - if resp.StatusCode != http.StatusOK { - return u, errors.Errorf("authentication failed (%v): %v (status: %v/%v)", - user, url+LoginPath, resp.StatusCode, resp.Status) - } - return u, nil -} - -// UniReq is a small helper function that adds an Accept header. -// Use this if you're unmarshalling Unifi data into custom types. -// And you're doing that... sumbut a pull request with your new struct. :) -func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err error) { - if params != "" { - req, err = http.NewRequest("POST", u.baseURL+apiPath, bytes.NewBufferString(params)) - } else { - req, err = http.NewRequest("GET", u.baseURL+apiPath, nil) - } - if err == nil { - req.Header.Add("Accept", "application/json") - } - return -} - -// dLogf logs a debug message. -func (u *Unifi) dLogf(msg string, v ...interface{}) { - if u.DebugLog != nil { - u.DebugLog("[DEBUG] "+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/unifi.go b/core/unifi/unifi.go index b8b9c0e8..2ba47653 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -1,12 +1,58 @@ +// Package unifi provides a set of types to unload (unmarshal) Unifi Ubiquiti +// controller data. Also provided are methods to easily get data for devices - +// things like access points and switches, and for clients - the things +// connected to those access points and switches. As a bonus, each device and +// client type provided has an attached method to create InfluxDB datapoints. package unifi import ( + "bytes" + "crypto/tls" "encoding/json" "io/ioutil" + "net/http" + "net/http/cookiejar" + "strings" "github.com/pkg/errors" ) +// GetController creates a http.Client with authenticated cookies. +// Used to make additional, authenticated requests to the APIs. +// Start here. +func GetController(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)") + } + u := &Unifi{ + Client: &http.Client{ + Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !verifySSL}}, + Jar: jar, + }, + } + if u.baseURL = url; strings.HasSuffix(url, "/") { + u.baseURL = url[:len(url)-1] + } + req, err := u.UniReq(LoginPath, json) + if err != nil { + return u, errors.Wrap(err, "UniReq(LoginPath, json)") + } + resp, err := u.Do(req) + if err != nil { + return u, errors.Wrap(err, "authReq.Do(req)") + } + defer func() { + _ = resp.Body.Close() + }() + if resp.StatusCode != http.StatusOK { + return u, errors.Errorf("authentication failed (%v): %v (status: %v/%v)", + user, url+LoginPath, resp.StatusCode, resp.Status) + } + return u, nil +} + // GetClients returns a response full of clients' data from the Unifi Controller. func (u *Unifi) GetClients() (*Clients, error) { var response struct { @@ -55,55 +101,18 @@ func (u *Unifi) GetDevices() (*Devices, error) { return u.parseDevices(response.Data), nil } -// parseDevices parses the raw JSON from the Unifi Controller into device structures. -func (u *Unifi) parseDevices(data []json.RawMessage) *Devices { - devices := new(Devices) - for _, r := range data { - // Loop each item in the raw JSON message, detect its type and unmarshal it. - var obj map[string]interface{} - var uap UAP - var usg USG - var usw USW - - if u.unmarshalDevice("interface{}", &obj, r) != nil { - continue - } - assetType := "" - if t, ok := obj["type"].(string); ok { - assetType = t - } - u.dLogf("Unmarshalling Device Type: %v", assetType) - switch assetType { // Unmarshal again into the correct type.. - case "uap": - if u.unmarshalDevice(assetType, &uap, r) == nil { - devices.UAPs = append(devices.UAPs, uap) - } - case "ugw", "usg": // in case they ever fix the name in the api. - if u.unmarshalDevice(assetType, &usg, r) == nil { - devices.USGs = append(devices.USGs, usg) - } - case "usw": - if u.unmarshalDevice(assetType, &usw, r) == nil { - devices.USWs = append(devices.USWs, usw) - } - default: - u.eLogf("unknown asset type - %v - skipping", assetType) - continue - } +// UniReq is a small helper function that adds an Accept header. +// Use this if you're unmarshalling Unifi data into custom types. +// And if you're doing that... sumbut a pull request with your new struct. :) +// This is a helper method that is exposed for convenience. +func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err error) { + if params != "" { + req, err = http.NewRequest("POST", u.baseURL+apiPath, bytes.NewBufferString(params)) + } else { + req, err = http.NewRequest("GET", u.baseURL+apiPath, nil) } - return devices -} - -// unmarshalDevice handles logging for the unmarshal operations in parseDevices(). -func (u *Unifi) unmarshalDevice(device string, ptr interface{}, payload json.RawMessage) error { - err := json.Unmarshal(payload, ptr) - if err != nil { - u.eLogf("json.Unmarshal(%v): %v", device, err) - u.eLogf("Enable Debug Logging to output the failed payload.") - json, err := payload.MarshalJSON() - u.dLogf("Failed Payload: %s (marshal err: %v)", json, err) - u.dLogf("The above payload can prove useful during torubleshooting when you open an Issue:") - u.dLogf("==- https://github.com/golift/unifi/issues/new -==") + if err == nil { + req.Header.Add("Accept", "application/json") } - return err + return } diff --git a/core/unifi/unidev_test.go b/core/unifi/unifi_test.go similarity index 70% rename from core/unifi/unidev_test.go rename to core/unifi/unifi_test.go index 35b31704..35c533c6 100644 --- a/core/unifi/unidev_test.go +++ b/core/unifi/unifi_test.go @@ -1,7 +1,6 @@ package unifi import ( - "encoding/json" "io/ioutil" "net/http" "testing" @@ -9,32 +8,17 @@ import ( "github.com/stretchr/testify/assert" ) -func TestFlexInt(t *testing.T) { +func TestAuthController(t *testing.T) { t.Parallel() a := assert.New(t) - type testReply struct { - Five FlexInt `json:"five"` - Seven FlexInt `json:"seven"` - Auto FlexInt `json:"auto"` - Channel FlexInt `json:"channel"` - } - var r testReply - // test unmarshalling the custom type three times with different values. - a.Nil(json.Unmarshal([]byte(`{"five": "5", "seven": 7, "auto": "auto"}`), &r)) - - // test number in string. - a.EqualValues(5, r.Five.Number) - a.EqualValues("5", r.Five.String) - // test number. - a.EqualValues(7, r.Seven.Number) - a.EqualValues("7", r.Seven.String) - // test string. - a.EqualValues(0, r.Auto.Number) - a.EqualValues("auto", r.Auto.String) - // test (error) struct. - a.NotNil(json.Unmarshal([]byte(`{"channel": {}}`), &r), - "a non-string and non-number must produce an error.") - a.EqualValues(0, r.Channel.Number) + url := "http://127.0.0.1:64431" + authReq, err := GetController("user1", "pass2", url, false) + a.NotNil(err) + a.EqualValues(url, authReq.baseURL) + a.Contains(err.Error(), "authReq.Do(req):", "an invalid destination should product a .Do(req) error.") + /* TODO: OPEN web server, check parameters posted, more. This test is incomplete. + a.EqualValues(`{"username": "user1","password": "pass2"}`, string(post_params), "user/pass json parameters improperly encoded") + */ } func TestUniReq(t *testing.T) { @@ -67,16 +51,3 @@ func TestUniReq(t *testing.T) { a.Nil(err, "problem reading request body, POST parameters may be malformed") a.EqualValues(p, string(d), "POST parameters improperly encoded") } - -func TestAuthController(t *testing.T) { - t.Parallel() - a := assert.New(t) - url := "http://127.0.0.1:64431" - authReq, err := GetController("user1", "pass2", url, false) - a.NotNil(err) - a.EqualValues(url, authReq.baseURL) - a.Contains(err.Error(), "authReq.Do(req):", "an invalid destination should product a .Do(req) error.") - /* TODO: OPEN web server, check parameters posted, more. This test is incomplete. - a.EqualValues(`{"username": "user1","password": "pass2"}`, string(post_params), "user/pass json parameters improperly encoded") - */ -} diff --git a/core/unifi/usg.go b/core/unifi/usg_influx.go similarity index 98% rename from core/unifi/usg.go rename to core/unifi/usg_influx.go index 894f33b4..9b169e54 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg_influx.go @@ -17,7 +17,7 @@ func (u USG) Points() ([]*influx.Point, error) { "device_type": u.Stat.O, "device_oid": u.Stat.Oid, "site_id": u.SiteID, - "addopted": strconv.FormatBool(u.Adopted), + "adopted": strconv.FormatBool(u.Adopted), "name": u.Name, "adopt_ip": u.AdoptIP, "adopt_url": u.AdoptURL, @@ -92,7 +92,7 @@ func (u USG) Points() ([]*influx.Point, error) { "wan1_rx_packets": u.Wan1.RxPackets, "wan1_type": u.Wan1.Type, "wan1_speed": u.Wan1.Speed, - "wan1_up": u.Wan1.Up.Bool, + "wan1_up": u.Wan1.Up.Val, "wan1_tx_bytes": u.Wan1.TxBytes, "wan1_tx_bytes-r": u.Wan1.TxBytesR, "wan1_tx_dropped": u.Wan1.TxDropped, @@ -170,7 +170,7 @@ func (u USG) Points() ([]*influx.Point, error) { "rx_packets": p.RxPackets, "tx_bytes": p.TxBytes, "tx_packets": p.TxPackets, - "up": p.Up.String, + "up": p.Up.Txt, "vlan": p.Vlan, "dhcpd_ntp_1": p.DhcpdNtp1, "dhcpd_unifi_controller": p.DhcpdUnifiController, diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index 3b29103a..e8bc453f 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -2,7 +2,7 @@ package unifi import "encoding/json" -// USG represents all the data from the Ubiquit Controller for a Unifi Security Gateway. +// USG represents all the data from the Ubiquiti 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_influx.go similarity index 98% rename from core/unifi/usw.go rename to core/unifi/usw_influx.go index 760ba833..94a7f9df 100644 --- a/core/unifi/usw.go +++ b/core/unifi/usw_influx.go @@ -18,7 +18,7 @@ func (u USW) Points() ([]*influx.Point, error) { "device_oid": u.Stat.Oid, "site_id": u.SiteID, "name": u.Name, - "addopted": strconv.FormatBool(u.Adopted), + "adopted": strconv.FormatBool(u.Adopted), "adopt_ip": u.AdoptIP, "adopt_url": u.AdoptURL, "cfgversion": u.Cfgversion, diff --git a/core/unifi/usw_type.go b/core/unifi/usw_type.go index 7fa68de4..a0d6485c 100644 --- a/core/unifi/usw_type.go +++ b/core/unifi/usw_type.go @@ -1,6 +1,6 @@ package unifi -// USW represents all the data from the Ubiquit Controller for a Unifi Switch. +// USW represents all the data from the Ubiquiti Controller for a Unifi Switch. type USW struct { ID string `json:"_id"` UUptime float64 `json:"_uptime"` From 1fe1295a0e86cbdc7184c9b4b31d4cbc54a83887 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 17 Apr 2019 00:54:54 -0700 Subject: [PATCH 027/194] Split getController --- core/unifi/unifi.go | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 2ba47653..90601923 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -9,6 +9,7 @@ import ( "bytes" "crypto/tls" "encoding/json" + "io" "io/ioutil" "net/http" "net/http/cookiejar" @@ -21,36 +22,38 @@ import ( // Used to make additional, authenticated requests to the APIs. // Start here. func GetController(user, pass, url string, verifySSL bool) (*Unifi, error) { + u := &Unifi{baseURL: strings.TrimRight(url, "/")} json := `{"username": "` + user + `","password": "` + pass + `"}` - jar, err := cookiejar.New(nil) - if err != nil { - return nil, errors.Wrap(err, "cookiejar.New(nil)") - } - u := &Unifi{ - Client: &http.Client{ - Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !verifySSL}}, - Jar: jar, - }, - } - if u.baseURL = url; strings.HasSuffix(url, "/") { - u.baseURL = url[:len(url)-1] - } req, err := u.UniReq(LoginPath, json) if err != nil { return u, errors.Wrap(err, "UniReq(LoginPath, json)") } + jar, err := cookiejar.New(nil) + if err != nil { + return nil, errors.Wrap(err, "cookiejar.New(nil)") + } + u.Client = &http.Client{ + Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !verifySSL}}, + Jar: jar, + } + return u, u.getController(req) +} + +// getController is a helper method to make testsing a bit easier. +func (u *Unifi) getController(req *http.Request) error { resp, err := u.Do(req) if err != nil { - return u, errors.Wrap(err, "authReq.Do(req)") + return errors.Wrap(err, "authReq.Do(req)") } defer func() { + _, _ = io.Copy(ioutil.Discard, resp.Body) // avoid leaking. _ = resp.Body.Close() }() if resp.StatusCode != http.StatusOK { - return u, errors.Errorf("authentication failed (%v): %v (status: %v/%v)", - user, url+LoginPath, resp.StatusCode, resp.Status) + return errors.Errorf("authentication failed: %v (status: %v/%v)", + u.baseURL+LoginPath, resp.StatusCode, resp.Status) } - return u, nil + return nil } // GetClients returns a response full of clients' data from the Unifi Controller. From d0a146022651eeca544a43d0240d640fe3b408d4 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 17 Apr 2019 01:15:22 -0700 Subject: [PATCH 028/194] Rename the init func. --- core/unifi/README.md | 2 +- core/unifi/unifi.go | 4 ++-- core/unifi/unifi_test.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/unifi/README.md b/core/unifi/README.md index cbe77503..5ea77454 100644 --- a/core/unifi/README.md +++ b/core/unifi/README.md @@ -23,7 +23,7 @@ func main() { username := "admin" password := "superSecret1234" URL := "https://127.0.0.1:8443/" - uni, err := unifi.GetController(username, password, URL, false) + uni, err := unifi.NewUnifi(username, password, URL, false) if err != nil { log.Fatalln("Error:", err) } diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 2267f4e6..0422a529 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -19,10 +19,10 @@ import ( "github.com/pkg/errors" ) -// GetController creates a http.Client with authenticated cookies. +// NewUnifi creates a http.Client with authenticated cookies. // Used to make additional, authenticated requests to the APIs. // Start here. -func GetController(user, pass, url string, verifySSL bool) (*Unifi, error) { +func NewUnifi(user, pass, url string, verifySSL bool) (*Unifi, error) { jar, err := cookiejar.New(nil) if err != nil { return nil, errors.Wrap(err, "cookiejar.New(nil)") diff --git a/core/unifi/unifi_test.go b/core/unifi/unifi_test.go index 35c533c6..dff7687d 100644 --- a/core/unifi/unifi_test.go +++ b/core/unifi/unifi_test.go @@ -8,11 +8,11 @@ import ( "github.com/stretchr/testify/assert" ) -func TestAuthController(t *testing.T) { +func TestNewUnifi(t *testing.T) { t.Parallel() a := assert.New(t) url := "http://127.0.0.1:64431" - authReq, err := GetController("user1", "pass2", url, false) + authReq, err := NewUnifi("user1", "pass2", url, false) a.NotNil(err) a.EqualValues(url, authReq.baseURL) a.Contains(err.Error(), "authReq.Do(req):", "an invalid destination should product a .Do(req) error.") From ac156bcd1231153f53d320340ad307620c581b1f Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 17 Apr 2019 02:06:06 -0700 Subject: [PATCH 029/194] a little more cleanup --- core/unifi/clients_influx.go | 16 ++++++++-------- core/unifi/parsers.go | 29 +++++++++++------------------ core/unifi/uap_influx.go | 3 +-- core/unifi/usg_influx.go | 5 ++--- core/unifi/usw_influx.go | 7 +++---- 5 files changed, 25 insertions(+), 35 deletions(-) diff --git a/core/unifi/clients_influx.go b/core/unifi/clients_influx.go index 51e0c8e2..70adf58f 100644 --- a/core/unifi/clients_influx.go +++ b/core/unifi/clients_influx.go @@ -10,15 +10,15 @@ import ( // 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 c.Name == "" && c.Hostname != "" { - c.Name = c.Hostname - } else if c.Hostname == "" && c.Name != "" { - c.Hostname = c.Name - } else if c.Hostname == "" && c.Name == "" { + switch { + case c.Hostname == "" && c.Name == "": c.Hostname = "-no-name-" c.Name = "-no-name-" + case c.Hostname == "" && c.Name != "": + c.Hostname = c.Name + case c.Name == "" && c.Hostname != "": + c.Name = c.Hostname } tags := map[string]string{ "id": c.ID, @@ -100,7 +100,7 @@ func (c UCL) Points() ([]*influx.Point, error) { } pt, err := influx.NewPoint("clients", tags, fields, time.Now()) if err == nil { - points = append(points, pt) + return nil, err } - return points, err + return []*influx.Point{pt}, nil } diff --git a/core/unifi/parsers.go b/core/unifi/parsers.go index 5b324282..70c2d193 100644 --- a/core/unifi/parsers.go +++ b/core/unifi/parsers.go @@ -7,47 +7,40 @@ func (u *Unifi) parseDevices(data []json.RawMessage) *Devices { devices := new(Devices) for _, r := range data { // Loop each item in the raw JSON message, detect its type and unmarshal it. - var obj map[string]interface{} - var uap UAP - var usg USG - var usw USW - - if u.unmarshalDevice("interface{}", &obj, r) != nil { + assetType := "" + if o := make(map[string]interface{}); u.unmarshalDevice("map", r, &o) != nil { continue - } - assetType := "" - if t, ok := obj["type"].(string); ok { + } else if t, ok := o["type"].(string); ok { assetType = t } u.dLogf("Unmarshalling Device Type: %v", assetType) + // Choose which type to unmarshal into based on the "type" json key. switch assetType { // Unmarshal again into the correct type.. case "uap": - if u.unmarshalDevice(assetType, &uap, r) == nil { + if uap := (UAP{}); u.unmarshalDevice(assetType, r, &uap) == nil { devices.UAPs = append(devices.UAPs, uap) } case "ugw", "usg": // in case they ever fix the name in the api. - if u.unmarshalDevice(assetType, &usg, r) == nil { + if usg := (USG{}); u.unmarshalDevice(assetType, r, &usg) == nil { devices.USGs = append(devices.USGs, usg) } case "usw": - if u.unmarshalDevice(assetType, &usw, r) == nil { + if usw := (USW{}); u.unmarshalDevice(assetType, r, &usw) == nil { devices.USWs = append(devices.USWs, usw) } default: u.eLogf("unknown asset type - %v - skipping", assetType) - continue } } return devices } // unmarshalDevice handles logging for the unmarshal operations in parseDevices(). -func (u *Unifi) unmarshalDevice(device string, ptr interface{}, payload json.RawMessage) error { - err := json.Unmarshal(payload, ptr) - if err != nil { - u.eLogf("json.Unmarshal(%v): %v", device, err) +func (u *Unifi) unmarshalDevice(dev string, data json.RawMessage, v interface{}) (err error) { + if err = json.Unmarshal(data, v); err != nil { + u.eLogf("json.Unmarshal(%v): %v", dev, err) u.eLogf("Enable Debug Logging to output the failed payload.") - json, err := payload.MarshalJSON() + json, err := data.MarshalJSON() u.dLogf("Failed Payload: %s (marshal err: %v)", json, err) u.dLogf("The above payload can prove useful during torubleshooting when you open an Issue:") u.dLogf("==- https://github.com/golift/unifi/issues/new -==") diff --git a/core/unifi/uap_influx.go b/core/unifi/uap_influx.go index 36789de8..7ae5affa 100644 --- a/core/unifi/uap_influx.go +++ b/core/unifi/uap_influx.go @@ -13,7 +13,6 @@ 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! */ - var points []*influx.Point tags := map[string]string{ "id": u.ID, "mac": u.Mac, @@ -174,7 +173,7 @@ func (u UAP) Points() ([]*influx.Point, error) { if err != nil { return nil, err } - points = append(points, pt) + points := []*influx.Point{pt} for _, p := range u.RadioTable { tags := map[string]string{ "device_name": u.Name, diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index 9b169e54..a2a52779 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -10,7 +10,6 @@ import ( // 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, "mac": u.Mac, @@ -130,7 +129,7 @@ func (u USG) Points() ([]*influx.Point, error) { if err != nil { return nil, err } - points = append(points, pt) + points := []*influx.Point{pt} for _, p := range u.NetworkTable { tags := map[string]string{ "device_name": u.Name, @@ -183,5 +182,5 @@ func (u USG) Points() ([]*influx.Point, error) { } points = append(points, pt) } - return points, err + return points, nil } diff --git a/core/unifi/usw_influx.go b/core/unifi/usw_influx.go index 94a7f9df..810148de 100644 --- a/core/unifi/usw_influx.go +++ b/core/unifi/usw_influx.go @@ -10,7 +10,6 @@ import ( // 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, "mac": u.Mac, @@ -112,8 +111,8 @@ func (u USW) Points() ([]*influx.Point, error) { // Add the port stats too. } pt, err := influx.NewPoint("usw", tags, fields, time.Now()) - if err == nil { - points = append(points, pt) + if err != nil { + return nil, err } - return points, err + return []*influx.Point{pt}, nil } From 92361fbe344f2e8685bbe32b57dbaf1e6f91dea6 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 17 Apr 2019 02:38:57 -0700 Subject: [PATCH 030/194] FlexBool it up --- core/unifi/README.md | 1 + core/unifi/clients_influx.go | 22 +-- core/unifi/clients_type.go | 150 ++++++++--------- core/unifi/uap_influx.go | 34 ++-- core/unifi/uap_type.go | 310 +++++++++++++++++------------------ core/unifi/usg_influx.go | 46 +++--- core/unifi/usg_type.go | 126 +++++++------- core/unifi/usw_influx.go | 27 ++- core/unifi/usw_type.go | 168 +++++++++---------- 9 files changed, 442 insertions(+), 442 deletions(-) diff --git a/core/unifi/README.md b/core/unifi/README.md index 5ea77454..177519ef 100644 --- a/core/unifi/README.md +++ b/core/unifi/README.md @@ -44,6 +44,7 @@ func main() { log.Fatalln("Error:", err) } + log.Println(len(sites), "Unifi Sites Found: ", sites) log.Println(len(clients.UCLs), "Clients connected:") for i, client := range clients.UCLs { log.Println(i+1, client.ID, client.Hostname, client.IP, client.Name, client.LastSeen) diff --git a/core/unifi/clients_influx.go b/core/unifi/clients_influx.go index 70adf58f..f1dc92d7 100644 --- a/core/unifi/clients_influx.go +++ b/core/unifi/clients_influx.go @@ -42,17 +42,17 @@ func (c UCL) Points() ([]*influx.Point, error) { "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), + "authorized": c.Authorized.Txt, + "is_11r": c.Is11R.Txt, + "is_wired": c.IsWired.Txt, + "is_guest": c.IsGuest.Txt, + "is_guest_by_uap": c.IsGuestByUAP.Txt, + "is_guest_by_ugw": c.IsGuestByUGW.Txt, + "is_guest_by_usw": c.IsGuestByUSW.Txt, + "noted": c.Noted.Txt, + "powersave_enabled": c.PowersaveEnabled.Txt, + "qos_policy_applied": c.QosPolicyApplied.Txt, + "use_fixedip": c.UseFixedIP.Txt, "channel": strconv.Itoa(c.Channel), "vlan": strconv.Itoa(c.Vlan), } diff --git a/core/unifi/clients_type.go b/core/unifi/clients_type.go index 996c2493..2ad29ccf 100644 --- a/core/unifi/clients_type.go +++ b/core/unifi/clients_type.go @@ -2,26 +2,26 @@ package unifi // UCL defines all the data a connected-network client contains. type UCL struct { - ID string `json:"_id"` - IsGuestByUAP bool `json:"_is_guest_by_uap"` - IsGuestByUGW bool `json:"_is_guest_by_ugw"` - IsGuestByUSW bool `json:"_is_guest_by_usw"` - LastSeenByUAP int64 `json:"_last_seen_by_uap"` - LastSeenByUGW int64 `json:"_last_seen_by_ugw"` - LastSeenByUSW int64 `json:"_last_seen_by_usw"` - UptimeByUAP int64 `json:"_uptime_by_uap"` - UptimeByUGW int64 `json:"_uptime_by_ugw"` - UptimeByUSW int64 `json:"_uptime_by_usw"` - ApMac string `json:"ap_mac"` - AssocTime int64 `json:"assoc_time"` - Authorized bool `json:"authorized"` - Bssid string `json:"bssid"` - BytesR int64 `json:"bytes-r"` - Ccq int64 `json:"ccq"` - Channel int `json:"channel"` - DevCat int `json:"dev_cat"` - DevFamily int `json:"dev_family"` - DevID int `json:"dev_id"` + ID string `json:"_id"` + IsGuestByUAP FlexBool `json:"_is_guest_by_uap"` + IsGuestByUGW FlexBool `json:"_is_guest_by_ugw"` + IsGuestByUSW FlexBool `json:"_is_guest_by_usw"` + LastSeenByUAP int64 `json:"_last_seen_by_uap"` + LastSeenByUGW int64 `json:"_last_seen_by_ugw"` + LastSeenByUSW int64 `json:"_last_seen_by_usw"` + UptimeByUAP int64 `json:"_uptime_by_uap"` + UptimeByUGW int64 `json:"_uptime_by_ugw"` + UptimeByUSW int64 `json:"_uptime_by_usw"` + ApMac string `json:"ap_mac"` + AssocTime int64 `json:"assoc_time"` + Authorized FlexBool `json:"authorized"` + Bssid string `json:"bssid"` + BytesR int64 `json:"bytes-r"` + Ccq int64 `json:"ccq"` + Channel int `json:"channel"` + DevCat int `json:"dev_cat"` + DevFamily int `json:"dev_family"` + DevID int `json:"dev_id"` DpiStats struct { App int64 Cat int64 @@ -30,59 +30,59 @@ type UCL struct { TxBytes int64 TxPackets int64 } `json:"dpi_stats"` - DpiStatsLastUpdated int64 `json:"dpi_stats_last_updated"` - Essid string `json:"essid"` - FirstSeen int64 `json:"first_seen"` - FixedIP string `json:"fixed_ip"` - Hostname string `json:"hostname"` - GwMac string `json:"gw_mac"` - IdleTime int64 `json:"idle_time"` - IP string `json:"ip"` - Is11R bool `json:"is_11r"` - IsGuest bool `json:"is_guest"` - IsWired bool `json:"is_wired"` - LastSeen int64 `json:"last_seen"` - LatestAssocTime int64 `json:"latest_assoc_time"` - Mac string `json:"mac"` - Name string `json:"name"` - Network string `json:"network"` - NetworkID string `json:"network_id"` - Noise int64 `json:"noise"` - Note string `json:"note"` - Noted bool `json:"noted"` - OsClass int `json:"os_class"` - OsName int `json:"os_name"` - Oui string `json:"oui"` - PowersaveEnabled bool `json:"powersave_enabled"` - QosPolicyApplied bool `json:"qos_policy_applied"` - Radio string `json:"radio"` - RadioName string `json:"radio_name"` - RadioProto string `json:"radio_proto"` - RoamCount int64 `json:"roam_count"` - Rssi int64 `json:"rssi"` - RxBytes int64 `json:"rx_bytes"` - RxBytesR int64 `json:"rx_bytes-r"` - RxPackets int64 `json:"rx_packets"` - RxRate int64 `json:"rx_rate"` - Signal int64 `json:"signal"` - SiteID string `json:"site_id"` - SwDepth int `json:"sw_depth"` - SwMac string `json:"sw_mac"` - SwPort int `json:"sw_port"` - TxBytes int64 `json:"tx_bytes"` - TxBytesR int64 `json:"tx_bytes-r"` - TxPackets int64 `json:"tx_packets"` - TxPower int64 `json:"tx_power"` - TxRate int64 `json:"tx_rate"` - Uptime int64 `json:"uptime"` - UserID string `json:"user_id"` - UserGroupID string `json:"usergroup_id"` - UseFixedIP bool `json:"use_fixedip"` - Vlan int `json:"vlan"` - WiredRxBytes int64 `json:"wired-rx_bytes"` - WiredRxBytesR int64 `json:"wired-rx_bytes-r"` - WiredRxPackets int64 `json:"wired-rx_packets"` - WiredTxBytes int64 `json:"wired-tx_bytes"` - WiredTxBytesR int64 `json:"wired-tx_bytes-r"` - WiredTxPackets int64 `json:"wired-tx_packets"` + DpiStatsLastUpdated int64 `json:"dpi_stats_last_updated"` + Essid string `json:"essid"` + FirstSeen int64 `json:"first_seen"` + FixedIP string `json:"fixed_ip"` + Hostname string `json:"hostname"` + GwMac string `json:"gw_mac"` + IdleTime int64 `json:"idle_time"` + IP string `json:"ip"` + Is11R FlexBool `json:"is_11r"` + IsGuest FlexBool `json:"is_guest"` + IsWired FlexBool `json:"is_wired"` + LastSeen int64 `json:"last_seen"` + LatestAssocTime int64 `json:"latest_assoc_time"` + Mac string `json:"mac"` + Name string `json:"name"` + Network string `json:"network"` + NetworkID string `json:"network_id"` + Noise int64 `json:"noise"` + Note string `json:"note"` + Noted FlexBool `json:"noted"` + OsClass int `json:"os_class"` + OsName int `json:"os_name"` + Oui string `json:"oui"` + PowersaveEnabled FlexBool `json:"powersave_enabled"` + QosPolicyApplied FlexBool `json:"qos_policy_applied"` + Radio string `json:"radio"` + RadioName string `json:"radio_name"` + RadioProto string `json:"radio_proto"` + RoamCount int64 `json:"roam_count"` + Rssi int64 `json:"rssi"` + RxBytes int64 `json:"rx_bytes"` + RxBytesR int64 `json:"rx_bytes-r"` + RxPackets int64 `json:"rx_packets"` + RxRate int64 `json:"rx_rate"` + Signal int64 `json:"signal"` + SiteID string `json:"site_id"` + SwDepth int `json:"sw_depth"` + SwMac string `json:"sw_mac"` + SwPort int `json:"sw_port"` + TxBytes int64 `json:"tx_bytes"` + TxBytesR int64 `json:"tx_bytes-r"` + TxPackets int64 `json:"tx_packets"` + TxPower int64 `json:"tx_power"` + TxRate int64 `json:"tx_rate"` + Uptime int64 `json:"uptime"` + UserID string `json:"user_id"` + UserGroupID string `json:"usergroup_id"` + UseFixedIP FlexBool `json:"use_fixedip"` + Vlan int `json:"vlan"` + WiredRxBytes int64 `json:"wired-rx_bytes"` + WiredRxBytesR int64 `json:"wired-rx_bytes-r"` + WiredRxPackets int64 `json:"wired-rx_packets"` + WiredTxBytes int64 `json:"wired-tx_bytes"` + WiredTxBytesR int64 `json:"wired-tx_bytes-r"` + WiredTxPackets int64 `json:"wired-tx_packets"` } diff --git a/core/unifi/uap_influx.go b/core/unifi/uap_influx.go index 31b3f128..04811da4 100644 --- a/core/unifi/uap_influx.go +++ b/core/unifi/uap_influx.go @@ -21,7 +21,7 @@ func (u UAP) Points() ([]*influx.Point, error) { "device_ap": u.Stat.Ap, "site_id": u.SiteID, "name": u.Name, - "adopted": strconv.FormatBool(u.Adopted), + "adopted": u.Adopted.Txt, "bandsteering_mode": u.BandsteeringMode, "board_rev": strconv.Itoa(u.BoardRev), "cfgversion": u.Cfgversion, @@ -29,27 +29,27 @@ func (u UAP) Points() ([]*influx.Point, error) { "config_network_type": u.ConfigNetwork.Type, "connect_request_ip": u.ConnectRequestIP, "connect_request_port": u.ConnectRequestPort, - "default": strconv.FormatBool(u.Default), + "default": u.Default.Txt, "device_id": u.DeviceID, "discovered_via": u.DiscoveredVia, "fw_caps": strconv.Itoa(u.FwCaps), "guest-num_sta": strconv.Itoa(u.GuestNumSta), "guest_token": u.GuestToken, - "has_eth1": strconv.FormatBool(u.HasEth1), - "has_speaker": strconv.FormatBool(u.HasSpeaker), + "has_eth1": u.HasEth1.Txt, + "has_speaker": u.HasSpeaker.Txt, "inform_ip": u.InformIP, - "isolated": strconv.FormatBool(u.Isolated), + "isolated": u.Isolated.Txt, "last_uplink_mac": u.LastUplink.UplinkMac, "last_uplink_remote_port": strconv.Itoa(u.LastUplink.UplinkRemotePort), "known_cfgversion": u.KnownCfgversion, "led_override": u.LedOverride, - "locating": strconv.FormatBool(u.Locating), + "locating": u.Locating.Txt, "model": u.Model, "outdoor_mode_override": u.OutdoorModeOverride, "serial": u.Serial, "type": u.Type, - "version_incompatible": strconv.FormatBool(u.VersionIncompatible), - "vwireEnabled": strconv.FormatBool(u.VwireEnabled), + "version_incompatible": u.VersionIncompatible.Txt, + "vwireEnabled": u.VwireEnabled.Txt, "wifi_caps": strconv.Itoa(u.WifiCaps), } fields := map[string]interface{}{ @@ -65,11 +65,11 @@ func (u UAP) Points() ([]*influx.Point, error) { "uptime": u.Uptime.Val, "considered_lost_at": u.ConsideredLostAt, "next_heartbeat_at": u.NextHeartbeatAt, - "scanning": u.Scanning, + "scanning": u.Scanning.Txt, "spectrum_scanning": u.SpectrumScanning, - "roll_upgrade": u.Rollupgrade, + "roll_upgrade": u.Rollupgrade.Txt, "state": u.State, - "upgradable": u.Upgradable, + "upgradable": u.Upgradable.Txt, "user-num_sta": u.UserNumSta, "version": u.Version, "loadavg_1": u.SysStats.Loadavg1, @@ -187,12 +187,12 @@ func (u UAP) Points() ([]*influx.Point, error) { fields := map[string]interface{}{ "builtin_ant_gain": p.BuiltinAntGain, "current_antenna_gain": p.CurrentAntennaGain, - "has_dfs": p.HasDfs, - "has_fccdfs": p.HasFccdfs, + "has_dfs": p.HasDfs.Txt, + "has_fccdfs": p.HasFccdfs.Txt, "ht": p.Ht, - "is_11ac": p.Is11Ac, + "is_11ac": p.Is11Ac.Txt, "max_txpower": p.MaxTxpower, - "min_rssi_enabled": p.MinRssiEnabled, + "min_rssi_enabled": p.MinRssiEnabled.Txt, "min_txpower": p.MinTxpower, "nss": p.Nss, "radio_caps": p.RadioCaps, @@ -234,8 +234,8 @@ func (u UAP) Points() ([]*influx.Point, error) { fields["ccq"] = s.Ccq fields["essid"] = s.Essid fields["extchannel"] = s.Extchannel - fields["is_guest"] = s.IsGuest - fields["is_wep"] = s.IsWep + fields["is_guest"] = s.IsGuest.Txt + fields["is_wep"] = s.IsWep.Txt fields["mac_filter_rejections"] = s.MacFilterRejections fields["map_id"] = s.MapID fields["vap_rx_bytes"] = s.RxBytes diff --git a/core/unifi/uap_type.go b/core/unifi/uap_type.go index a6116eb6..5ceae3f4 100644 --- a/core/unifi/uap_type.go +++ b/core/unifi/uap_type.go @@ -7,11 +7,11 @@ type UAP struct { No ones feelings will be hurt if you want to break this up into multiple structs, and/or make it better in general. */ - ID string `json:"_id"` - UUptime float64 `json:"_uptime"` - AdoptIP string `json:"adopt_ip,omitempty"` - AdoptURL string `json:"adopt_url,omitempty"` - Adopted bool `json:"adopted"` + ID string `json:"_id"` + UUptime float64 `json:"_uptime"` + AdoptIP string `json:"adopt_ip,omitempty"` + AdoptURL string `json:"adopt_url,omitempty"` + Adopted FlexBool `json:"adopted"` AntennaTable []struct { ID float64 `json:"id"` Name string `json:"name"` @@ -32,7 +32,7 @@ type UAP struct { ConnectRequestPort string `json:"connect_request_port"` ConsideredLostAt float64 `json:"considered_lost_at"` CountrycodeTable []float64 `json:"countrycode_table"` - Default bool `json:"default,omitempty"` + Default FlexBool `json:"default,omitempty"` DeviceID string `json:"device_id"` DiscoveredVia string `json:"discovered_via,omitempty"` DownlinkTable []interface{} `json:"downlink_table"` @@ -41,52 +41,52 @@ type UAP struct { Name string `json:"name"` NumPort float64 `json:"num_port"` } `json:"ethernet_table"` - FwCaps int `json:"fw_caps"` - GuestNumSta int `json:"guest-num_sta"` - GuestToken string `json:"guest_token"` - HasEth1 bool `json:"has_eth1"` - HasSpeaker bool `json:"has_speaker"` - InformIP string `json:"inform_ip"` - InformURL string `json:"inform_url"` - IP string `json:"ip"` - Isolated bool `json:"isolated"` - KnownCfgversion string `json:"known_cfgversion"` - LastSeen float64 `json:"last_seen"` + FwCaps int `json:"fw_caps"` + GuestNumSta int `json:"guest-num_sta"` + GuestToken string `json:"guest_token"` + HasEth1 FlexBool `json:"has_eth1"` + HasSpeaker FlexBool `json:"has_speaker"` + InformIP string `json:"inform_ip"` + InformURL string `json:"inform_url"` + IP string `json:"ip"` + Isolated FlexBool `json:"isolated"` + KnownCfgversion string `json:"known_cfgversion"` + LastSeen float64 `json:"last_seen"` LastUplink struct { UplinkMac string `json:"uplink_mac"` UplinkRemotePort int `json:"uplink_remote_port"` } `json:"last_uplink"` - LedOverride string `json:"led_override"` - Locating bool `json:"locating"` - Mac string `json:"mac"` - Model string `json:"model"` - Name string `json:"name"` - NextHeartbeatAt float64 `json:"next_heartbeat_at"` - NumSta float64 `json:"num_sta"` - OutdoorModeOverride string `json:"outdoor_mode_override"` + LedOverride string `json:"led_override"` + Locating FlexBool `json:"locating"` + Mac string `json:"mac"` + Model string `json:"model"` + Name string `json:"name"` + NextHeartbeatAt float64 `json:"next_heartbeat_at"` + NumSta float64 `json:"num_sta"` + OutdoorModeOverride string `json:"outdoor_mode_override"` PortTable []struct { - AggregatedBy bool `json:"aggregated_by"` - AttrNoEdit bool `json:"attr_no_edit,omitempty"` - Autoneg bool `json:"autoneg"` - BytesR float64 `json:"bytes-r"` - Enable bool `json:"enable"` - FlowctrlRx bool `json:"flowctrl_rx"` - FlowctrlTx bool `json:"flowctrl_tx"` - FullDuplex bool `json:"full_duplex"` - IsUplink bool `json:"is_uplink"` - Jumbo bool `json:"jumbo"` + AggregatedBy FlexBool `json:"aggregated_by"` + AttrNoEdit FlexBool `json:"attr_no_edit,omitempty"` + Autoneg FlexBool `json:"autoneg"` + BytesR float64 `json:"bytes-r"` + Enable FlexBool `json:"enable"` + FlowctrlRx FlexBool `json:"flowctrl_rx"` + FlowctrlTx FlexBool `json:"flowctrl_tx"` + FullDuplex FlexBool `json:"full_duplex"` + IsUplink FlexBool `json:"is_uplink"` + Jumbo FlexBool `json:"jumbo"` MacTable []struct { - Age float64 `json:"age"` - Mac string `json:"mac"` - Static bool `json:"static"` - Uptime float64 `json:"uptime"` - Vlan float64 `json:"vlan"` + Age float64 `json:"age"` + Mac string `json:"mac"` + Static FlexBool `json:"static"` + Uptime float64 `json:"uptime"` + Vlan float64 `json:"vlan"` } `json:"mac_table"` - Masked bool `json:"masked"` - Media string `json:"media"` - Name string `json:"name"` - OpMode string `json:"op_mode"` - PoeCaps float64 `json:"poe_caps"` + Masked FlexBool `json:"masked"` + Media string `json:"media"` + Name string `json:"name"` + OpMode string `json:"op_mode"` + PoeCaps float64 `json:"poe_caps"` PortDelta struct { RxBytes float64 `json:"rx_bytes"` RxPackets float64 `json:"rx_packets"` @@ -94,47 +94,47 @@ type UAP struct { TxBytes float64 `json:"tx_bytes"` TxPackets float64 `json:"tx_packets"` } `json:"port_delta"` - PortIdx float64 `json:"port_idx"` - PortPoe bool `json:"port_poe"` - PortconfID string `json:"portconf_id"` - RxBroadcast float64 `json:"rx_broadcast"` - RxBytes float64 `json:"rx_bytes"` - RxBytesR float64 `json:"rx_bytes-r"` - RxDropped float64 `json:"rx_dropped"` - RxErrors float64 `json:"rx_errors"` - RxMulticast float64 `json:"rx_multicast"` - RxPackets float64 `json:"rx_packets"` - Speed float64 `json:"speed"` - StpPathcost float64 `json:"stp_pathcost"` - StpState string `json:"stp_state"` - TxBroadcast float64 `json:"tx_broadcast"` - TxBytes float64 `json:"tx_bytes"` - TxBytesR float64 `json:"tx_bytes-r"` - TxDropped float64 `json:"tx_dropped"` - TxErrors float64 `json:"tx_errors"` - TxMulticast float64 `json:"tx_multicast"` - TxPackets float64 `json:"tx_packets"` - Up bool `json:"up"` + PortIdx float64 `json:"port_idx"` + PortPoe FlexBool `json:"port_poe"` + PortconfID string `json:"portconf_id"` + RxBroadcast float64 `json:"rx_broadcast"` + RxBytes float64 `json:"rx_bytes"` + RxBytesR float64 `json:"rx_bytes-r"` + RxDropped float64 `json:"rx_dropped"` + RxErrors float64 `json:"rx_errors"` + RxMulticast float64 `json:"rx_multicast"` + RxPackets float64 `json:"rx_packets"` + Speed float64 `json:"speed"` + StpPathcost float64 `json:"stp_pathcost"` + StpState string `json:"stp_state"` + TxBroadcast float64 `json:"tx_broadcast"` + TxBytes float64 `json:"tx_bytes"` + TxBytesR float64 `json:"tx_bytes-r"` + TxDropped float64 `json:"tx_dropped"` + TxErrors float64 `json:"tx_errors"` + TxMulticast float64 `json:"tx_multicast"` + TxPackets float64 `json:"tx_packets"` + Up FlexBool `json:"up"` } `json:"port_table"` RadioTable []struct { - BuiltinAntGain float64 `json:"builtin_ant_gain"` - BuiltinAntenna bool `json:"builtin_antenna"` - Channel FlexInt `json:"channel"` - CurrentAntennaGain float64 `json:"current_antenna_gain"` - Ht string `json:"ht"` - MaxTxpower float64 `json:"max_txpower"` - MinRssiEnabled bool `json:"min_rssi_enabled"` - MinTxpower float64 `json:"min_txpower"` - Name string `json:"name"` - Nss float64 `json:"nss"` - Radio string `json:"radio"` - RadioCaps float64 `json:"radio_caps"` - TxPower FlexInt `json:"tx_power"` - TxPowerMode string `json:"tx_power_mode"` - WlangroupID string `json:"wlangroup_id"` - HasDfs bool `json:"has_dfs,omitempty"` - HasFccdfs bool `json:"has_fccdfs,omitempty"` - Is11Ac bool `json:"is_11ac,omitempty"` + BuiltinAntGain float64 `json:"builtin_ant_gain"` + BuiltinAntenna FlexBool `json:"builtin_antenna"` + Channel FlexInt `json:"channel"` + CurrentAntennaGain float64 `json:"current_antenna_gain"` + Ht string `json:"ht"` + MaxTxpower float64 `json:"max_txpower"` + MinRssiEnabled FlexBool `json:"min_rssi_enabled"` + MinTxpower float64 `json:"min_txpower"` + Name string `json:"name"` + Nss float64 `json:"nss"` + Radio string `json:"radio"` + RadioCaps float64 `json:"radio_caps"` + TxPower FlexInt `json:"tx_power"` + TxPowerMode string `json:"tx_power_mode"` + WlangroupID string `json:"wlangroup_id"` + HasDfs FlexBool `json:"has_dfs,omitempty"` + HasFccdfs FlexBool `json:"has_fccdfs,omitempty"` + Is11Ac FlexBool `json:"is_11ac,omitempty"` } `json:"radio_table"` RadioTableStats []struct { AstBeXmit float64 `json:"ast_be_xmit"` @@ -156,14 +156,14 @@ type UAP struct { TxRetries float64 `json:"tx_retries"` UserNumSta float64 `json:"user-num_sta"` } `json:"radio_table_stats"` - Rollupgrade bool `json:"rollupgrade"` + Rollupgrade FlexBool `json:"rollupgrade"` RxBytes float64 `json:"rx_bytes"` RxBytesD float64 `json:"rx_bytes-d"` ScanRadioTable []interface{} `json:"scan_radio_table"` - Scanning bool `json:"scanning"` + Scanning FlexBool `json:"scanning"` Serial string `json:"serial"` SiteID string `json:"site_id"` - SpectrumScanning bool `json:"spectrum_scanning"` + SpectrumScanning FlexBool `json:"spectrum_scanning"` SSHSessionTable []interface{} `json:"ssh_session_table"` Stat struct { Ap string `json:"ap"` @@ -274,82 +274,82 @@ type UAP struct { Mem float64 `json:"mem,string"` Uptime float64 `json:"uptime,string"` } `json:"system-stats"` - TxBytes float64 `json:"tx_bytes"` - TxBytesD float64 `json:"tx_bytes-d"` - Type string `json:"type"` - Upgradable bool `json:"upgradable"` + TxBytes float64 `json:"tx_bytes"` + TxBytesD float64 `json:"tx_bytes-d"` + Type string `json:"type"` + Upgradable FlexBool `json:"upgradable"` Uplink struct { - FullDuplex bool `json:"full_duplex"` - IP string `json:"ip"` - Mac string `json:"mac"` - MaxSpeed int `json:"max_speed"` - MaxVlan int `json:"max_vlan"` - Media string `json:"media"` - Name string `json:"name"` - Netmask string `json:"netmask"` - NumPort int `json:"num_port"` - RxBytes float64 `json:"rx_bytes"` - RxBytesR float64 `json:"rx_bytes-r"` - RxDropped float64 `json:"rx_dropped"` - RxErrors float64 `json:"rx_errors"` - RxMulticast float64 `json:"rx_multicast"` - RxPackets float64 `json:"rx_packets"` - Speed float64 `json:"speed"` - TxBytes float64 `json:"tx_bytes"` - TxBytesR float64 `json:"tx_bytes-r"` - TxDropped float64 `json:"tx_dropped"` - TxErrors float64 `json:"tx_errors"` - TxPackets float64 `json:"tx_packets"` - Type string `json:"type"` - Up bool `json:"up"` - UplinkMac string `json:"uplink_mac"` - UplinkRemotePort int `json:"uplink_remote_port"` + FullDuplex FlexBool `json:"full_duplex"` + IP string `json:"ip"` + Mac string `json:"mac"` + MaxSpeed int `json:"max_speed"` + MaxVlan int `json:"max_vlan"` + Media string `json:"media"` + Name string `json:"name"` + Netmask string `json:"netmask"` + NumPort int `json:"num_port"` + RxBytes float64 `json:"rx_bytes"` + RxBytesR float64 `json:"rx_bytes-r"` + RxDropped float64 `json:"rx_dropped"` + RxErrors float64 `json:"rx_errors"` + RxMulticast float64 `json:"rx_multicast"` + RxPackets float64 `json:"rx_packets"` + Speed float64 `json:"speed"` + TxBytes float64 `json:"tx_bytes"` + TxBytesR float64 `json:"tx_bytes-r"` + TxDropped float64 `json:"tx_dropped"` + TxErrors float64 `json:"tx_errors"` + TxPackets float64 `json:"tx_packets"` + Type string `json:"type"` + Up FlexBool `json:"up"` + UplinkMac string `json:"uplink_mac"` + UplinkRemotePort int `json:"uplink_remote_port"` } `json:"uplink"` UplinkTable []interface{} `json:"uplink_table"` Uptime FlexInt `json:"uptime"` UserNumSta int `json:"user-num_sta"` VapTable []struct { - ApMac string `json:"ap_mac"` - Bssid string `json:"bssid"` - Ccq int `json:"ccq"` - Channel int `json:"channel"` - Essid string `json:"essid"` - Extchannel int `json:"extchannel"` - ID string `json:"id"` - IsGuest bool `json:"is_guest"` - IsWep bool `json:"is_wep"` - MacFilterRejections int `json:"mac_filter_rejections"` - MapID string `json:"map_id"` - Name string `json:"name"` - NumSta int `json:"num_sta"` - Radio string `json:"radio"` - RadioName string `json:"radio_name"` - RxBytes float64 `json:"rx_bytes"` - RxCrypts float64 `json:"rx_crypts"` - RxDropped float64 `json:"rx_dropped"` - RxErrors float64 `json:"rx_errors"` - RxFrags float64 `json:"rx_frags"` - RxNwids float64 `json:"rx_nwids"` - RxPackets float64 `json:"rx_packets"` - SiteID string `json:"site_id"` - State string `json:"state"` - T string `json:"t"` - TxBytes float64 `json:"tx_bytes"` - TxDropped float64 `json:"tx_dropped"` - TxErrors float64 `json:"tx_errors"` - TxLatencyAvg float64 `json:"tx_latency_avg"` - TxLatencyMax float64 `json:"tx_latency_max"` - TxLatencyMin float64 `json:"tx_latency_min"` - TxPackets float64 `json:"tx_packets"` - TxPower FlexInt `json:"tx_power"` - TxRetries int `json:"tx_retries"` - Up bool `json:"up"` - Usage string `json:"usage"` - WlanconfID string `json:"wlanconf_id"` + ApMac string `json:"ap_mac"` + Bssid string `json:"bssid"` + Ccq int `json:"ccq"` + Channel int `json:"channel"` + Essid string `json:"essid"` + Extchannel int `json:"extchannel"` + ID string `json:"id"` + IsGuest FlexBool `json:"is_guest"` + IsWep FlexBool `json:"is_wep"` + MacFilterRejections int `json:"mac_filter_rejections"` + MapID string `json:"map_id"` + Name string `json:"name"` + NumSta int `json:"num_sta"` + Radio string `json:"radio"` + RadioName string `json:"radio_name"` + RxBytes float64 `json:"rx_bytes"` + RxCrypts float64 `json:"rx_crypts"` + RxDropped float64 `json:"rx_dropped"` + RxErrors float64 `json:"rx_errors"` + RxFrags float64 `json:"rx_frags"` + RxNwids float64 `json:"rx_nwids"` + RxPackets float64 `json:"rx_packets"` + SiteID string `json:"site_id"` + State string `json:"state"` + T string `json:"t"` + TxBytes float64 `json:"tx_bytes"` + TxDropped float64 `json:"tx_dropped"` + TxErrors float64 `json:"tx_errors"` + TxLatencyAvg float64 `json:"tx_latency_avg"` + TxLatencyMax float64 `json:"tx_latency_max"` + TxLatencyMin float64 `json:"tx_latency_min"` + TxPackets float64 `json:"tx_packets"` + TxPower FlexInt `json:"tx_power"` + TxRetries int `json:"tx_retries"` + Up FlexBool `json:"up"` + Usage string `json:"usage"` + WlanconfID string `json:"wlanconf_id"` } `json:"vap_table"` Version string `json:"version"` - VersionIncompatible bool `json:"version_incompatible"` - VwireEnabled bool `json:"vwireEnabled"` + VersionIncompatible FlexBool `json:"version_incompatible"` + VwireEnabled FlexBool `json:"vwireEnabled"` VwireTable []interface{} `json:"vwire_table"` VwireVapTable []struct { Bssid string `json:"bssid"` diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index a2a52779..a3f0c520 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -16,7 +16,7 @@ func (u USG) Points() ([]*influx.Point, error) { "device_type": u.Stat.O, "device_oid": u.Stat.Oid, "site_id": u.SiteID, - "adopted": strconv.FormatBool(u.Adopted), + "adopted": u.Adopted.Txt, "name": u.Name, "adopt_ip": u.AdoptIP, "adopt_url": u.AdoptURL, @@ -25,21 +25,21 @@ func (u USG) Points() ([]*influx.Point, error) { "config_network_type": u.ConfigNetwork.Type, "connect_request_ip": u.ConnectRequestIP, "connect_request_port": u.ConnectRequestPort, - "default": strconv.FormatBool(u.Default), + "default": u.Default.Txt, "device_id": u.DeviceID, "discovered_via": u.DiscoveredVia, "guest_token": u.GuestToken, "inform_ip": u.InformIP, "known_cfgversion": u.KnownCfgversion, "led_override": u.LedOverride, - "locating": strconv.FormatBool(u.Locating), + "locating": u.Locating.Txt, "model": u.Model, "outdoor_mode_override": u.OutdoorModeOverride, "serial": u.Serial, "type": u.Type, - "version_incompatible": strconv.FormatBool(u.VersionIncompatible), + "version_incompatible": u.VersionIncompatible.Txt, "usg_caps": strconv.FormatFloat(u.UsgCaps, 'f', 6, 64), - "speedtest-status-saved": strconv.FormatBool(u.SpeedtestStatusSaved), + "speedtest-status-saved": u.SpeedtestStatusSaved.Txt, } fields := map[string]interface{}{ "ip": u.IP, @@ -53,9 +53,9 @@ func (u USG) Points() ([]*influx.Point, error) { "uptime": u.Uptime, "considered_lost_at": u.ConsideredLostAt, "next_heartbeat_at": u.NextHeartbeatAt, - "roll_upgrade": u.Rollupgrade, + "roll_upgrade": u.Rollupgrade.Txt, "state": u.State, - "upgradable": u.Upgradable, + "upgradable": u.Upgradable.Txt, "user-num_sta": u.UserNumSta, "version": u.Version, "num_desktop": u.NumDesktop, @@ -74,7 +74,7 @@ func (u USG) Points() ([]*influx.Point, error) { "config_network_wan_type": u.ConfigNetworkWan.Type, "wan1_bytes-r": u.Wan1.BytesR, "wan1_enable": u.Wan1.Enable, - "wan1_full_duplex": u.Wan1.FullDuplex, + "wan1_full_duplex": u.Wan1.FullDuplex.Txt, "wan1_purpose": "uplink", // because it should have a purpose. "wan1_gateway": u.Wan1.Gateway, "wan1_ifname": u.Wan1.Ifname, @@ -136,21 +136,21 @@ func (u USG) Points() ([]*influx.Point, error) { "device_id": u.ID, "device_mac": u.Mac, "name": p.Name, - "dhcpd_dns_enabled": strconv.FormatBool(p.DhcpdDNSEnabled), - "dhcpd_enabled": strconv.FormatBool(p.DhcpdEnabled), - "dhcpd_ntp_enabled": strconv.FormatBool(p.DhcpdNtpEnabled), - "dhcpd_time_offset_enabled": strconv.FormatBool(p.DhcpdTimeOffsetEnabled), - "dhcp_relay_enabledy": strconv.FormatBool(p.DhcpRelayEnabled), - "dhcpd_gateway_enabled": strconv.FormatBool(p.DhcpdGatewayEnabled), - "dhcpd_wins_enabled": strconv.FormatBool(p.DhcpdWinsEnabled), - "dhcpguard_enabled": strconv.FormatBool(p.DhcpguardEnabled), - "enabled": strconv.FormatBool(p.Enabled), - "vlan_enabled": strconv.FormatBool(p.VlanEnabled), - "attr_no_delete": strconv.FormatBool(p.AttrNoDelete), - "upnp_lan_enabled": strconv.FormatBool(p.UpnpLanEnabled), - "igmp_snooping": strconv.FormatBool(p.IgmpSnooping), - "is_guest": strconv.FormatBool(p.IsGuest), - "is_nat": strconv.FormatBool(p.IsNat), + "dhcpd_dns_enabled": p.DhcpdDNSEnabled.Txt, + "dhcpd_enabled": p.DhcpdEnabled.Txt, + "dhcpd_ntp_enabled": p.DhcpdNtpEnabled.Txt, + "dhcpd_time_offset_enabled": p.DhcpdTimeOffsetEnabled.Txt, + "dhcp_relay_enabledy": p.DhcpRelayEnabled.Txt, + "dhcpd_gateway_enabled": p.DhcpdGatewayEnabled.Txt, + "dhcpd_wins_enabled": p.DhcpdWinsEnabled.Txt, + "dhcpguard_enabled": p.DhcpguardEnabled.Txt, + "enabled": p.Enabled.Txt, + "vlan_enabled": p.VlanEnabled.Txt, + "attr_no_delete": p.AttrNoDelete.Txt, + "upnp_lan_enabled": p.UpnpLanEnabled.Txt, + "igmp_snooping": p.IgmpSnooping.Txt, + "is_guest": p.IsGuest.Txt, + "is_nat": p.IsNat.Txt, "networkgroup": p.Networkgroup, "site_id": p.SiteID, } diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index e8bc453f..1dad0fca 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -4,13 +4,13 @@ import "encoding/json" // USG represents all the data from the Ubiquiti Controller for a Unifi Security Gateway. type USG struct { - ID string `json:"_id"` - UUptime float64 `json:"_uptime"` - AdoptIP string `json:"adopt_ip"` - AdoptURL string `json:"adopt_url"` - Adopted bool `json:"adopted"` - Bytes float64 `json:"bytes"` - Cfgversion string `json:"cfgversion"` + ID string `json:"_id"` + UUptime float64 `json:"_uptime"` + AdoptIP string `json:"adopt_ip"` + AdoptURL string `json:"adopt_url"` + Adopted FlexBool `json:"adopted"` + Bytes float64 `json:"bytes"` + Cfgversion string `json:"cfgversion"` ConfigNetwork struct { IP string `json:"ip"` Type string `json:"type"` @@ -18,48 +18,48 @@ type USG struct { ConfigNetworkWan struct { Type string `json:"type"` } `json:"config_network_wan"` - ConnectRequestIP string `json:"connect_request_ip"` - ConnectRequestPort string `json:"connect_request_port"` - ConsideredLostAt float64 `json:"considered_lost_at"` - Default bool `json:"default"` - DeviceID string `json:"device_id"` - DiscoveredVia string `json:"discovered_via"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + ConsideredLostAt float64 `json:"considered_lost_at"` + Default FlexBool `json:"default"` + DeviceID string `json:"device_id"` + DiscoveredVia string `json:"discovered_via"` EthernetTable []struct { Mac string `json:"mac"` Name string `json:"name"` NumPort float64 `json:"num_port"` } `json:"ethernet_table"` - FwCaps float64 `json:"fw_caps"` - GuestNumSta float64 `json:"guest-num_sta"` - GuestToken string `json:"guest_token"` - InformIP string `json:"inform_ip"` - InformURL string `json:"inform_url"` - IP string `json:"ip"` - KnownCfgversion string `json:"known_cfgversion"` - LastSeen float64 `json:"last_seen"` - LedOverride string `json:"led_override"` - LicenseState string `json:"license_state"` - Locating bool `json:"locating"` - Mac string `json:"mac"` - Model string `json:"model"` - Name string `json:"name"` + FwCaps float64 `json:"fw_caps"` + GuestNumSta float64 `json:"guest-num_sta"` + GuestToken string `json:"guest_token"` + InformIP string `json:"inform_ip"` + InformURL string `json:"inform_url"` + IP string `json:"ip"` + KnownCfgversion string `json:"known_cfgversion"` + LastSeen float64 `json:"last_seen"` + LedOverride string `json:"led_override"` + LicenseState string `json:"license_state"` + Locating FlexBool `json:"locating"` + Mac string `json:"mac"` + Model string `json:"model"` + Name string `json:"name"` NetworkTable []struct { ID string `json:"_id"` - DhcpdDNSEnabled bool `json:"dhcpd_dns_enabled"` - DhcpdEnabled bool `json:"dhcpd_enabled"` + DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"` + DhcpdEnabled FlexBool `json:"dhcpd_enabled"` DhcpdIP1 string `json:"dhcpd_ip_1,omitempty"` DhcpdLeasetime json.Number `json:"dhcpd_leasetime,Number"` DhcpdStart string `json:"dhcpd_start"` DhcpdStop string `json:"dhcpd_stop"` - DhcpdWinsEnabled bool `json:"dhcpd_wins_enabled,omitempty"` - DhcpguardEnabled bool `json:"dhcpguard_enabled,omitempty"` + DhcpdWinsEnabled FlexBool `json:"dhcpd_wins_enabled,omitempty"` + DhcpguardEnabled FlexBool `json:"dhcpguard_enabled,omitempty"` DomainName string `json:"domain_name"` - Enabled bool `json:"enabled"` - IgmpSnooping bool `json:"igmp_snooping,omitempty"` + Enabled FlexBool `json:"enabled"` + IgmpSnooping FlexBool `json:"igmp_snooping,omitempty"` IP string `json:"ip"` IPSubnet string `json:"ip_subnet"` - IsGuest bool `json:"is_guest"` - IsNat bool `json:"is_nat"` + IsGuest FlexBool `json:"is_guest"` + IsNat FlexBool `json:"is_nat"` Mac string `json:"mac"` Name string `json:"name"` Networkgroup string `json:"networkgroup"` @@ -72,17 +72,17 @@ type USG struct { TxPackets float64 `json:"tx_packets"` Up FlexBool `json:"up"` Vlan string `json:"vlan,omitempty"` - VlanEnabled bool `json:"vlan_enabled"` - DhcpRelayEnabled bool `json:"dhcp_relay_enabled,omitempty"` - DhcpdGatewayEnabled bool `json:"dhcpd_gateway_enabled,omitempty"` + VlanEnabled FlexBool `json:"vlan_enabled"` + DhcpRelayEnabled FlexBool `json:"dhcp_relay_enabled,omitempty"` + DhcpdGatewayEnabled FlexBool `json:"dhcpd_gateway_enabled,omitempty"` DhcpdNtp1 string `json:"dhcpd_ntp_1,omitempty"` - DhcpdNtpEnabled bool `json:"dhcpd_ntp_enabled,omitempty"` - DhcpdTimeOffsetEnabled bool `json:"dhcpd_time_offset_enabled,omitempty"` + DhcpdNtpEnabled FlexBool `json:"dhcpd_ntp_enabled,omitempty"` + DhcpdTimeOffsetEnabled FlexBool `json:"dhcpd_time_offset_enabled,omitempty"` DhcpdUnifiController string `json:"dhcpd_unifi_controller,omitempty"` Ipv6InterfaceType string `json:"ipv6_interface_type,omitempty"` AttrHiddenID string `json:"attr_hidden_id,omitempty"` - AttrNoDelete bool `json:"attr_no_delete,omitempty"` - UpnpLanEnabled bool `json:"upnp_lan_enabled,omitempty"` + AttrNoDelete FlexBool `json:"attr_no_delete,omitempty"` + UpnpLanEnabled FlexBool `json:"upnp_lan_enabled,omitempty"` } `json:"network_table"` NextHeartbeatAt float64 `json:"next_heartbeat_at"` NumDesktop float64 `json:"num_desktop"` @@ -92,8 +92,8 @@ type USG struct { OutdoorModeOverride string `json:"outdoor_mode_override"` PortTable []struct { DNS []string `json:"dns,omitempty"` - Enable bool `json:"enable"` - FullDuplex bool `json:"full_duplex"` + Enable FlexBool `json:"enable"` + FullDuplex FlexBool `json:"full_duplex"` Gateway string `json:"gateway,omitempty"` Ifname string `json:"ifname"` IP string `json:"ip"` @@ -112,10 +112,10 @@ type USG struct { TxPackets float64 `json:"tx_packets"` Up FlexBool `json:"up"` } `json:"port_table"` - Rollupgrade bool `json:"rollupgrade"` - RxBytes float64 `json:"rx_bytes"` - Serial string `json:"serial"` - SiteID string `json:"site_id"` + Rollupgrade FlexBool `json:"rollupgrade"` + RxBytes float64 `json:"rx_bytes"` + Serial string `json:"serial"` + SiteID string `json:"site_id"` SpeedtestStatus struct { Latency float64 `json:"latency"` Rundate float64 `json:"rundate"` @@ -127,7 +127,7 @@ type USG struct { XputDownload float64 `json:"xput_download"` XputUpload float64 `json:"xput_upload"` } `json:"speedtest-status"` - SpeedtestStatusSaved bool `json:"speedtest-status-saved"` + SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"` Stat struct { Datetime string `json:"datetime"` Duration float64 `json:"duration"` @@ -160,14 +160,14 @@ type USG struct { Mem float64 `json:"mem,string"` Uptime float64 `json:"uptime,string"` } `json:"system-stats"` - TxBytes float64 `json:"tx_bytes"` - Type string `json:"type"` - Upgradable bool `json:"upgradable"` + TxBytes float64 `json:"tx_bytes"` + Type string `json:"type"` + Upgradable FlexBool `json:"upgradable"` Uplink struct { BytesR float64 `json:"bytes-r"` Drops float64 `json:"drops"` - Enable bool `json:"enable"` - FullDuplex bool `json:"full_duplex"` + Enable FlexBool `json:"enable"` + FullDuplex FlexBool `json:"full_duplex"` Gateways []string `json:"gateways"` IP string `json:"ip"` Latency float64 `json:"latency"` @@ -198,16 +198,16 @@ type USG struct { XputDown float64 `json:"xput_down"` XputUp float64 `json:"xput_up"` } `json:"uplink"` - Uptime float64 `json:"uptime"` - UserNumSta float64 `json:"user-num_sta"` - UsgCaps float64 `json:"usg_caps"` - Version string `json:"version"` - VersionIncompatible bool `json:"version_incompatible"` + Uptime float64 `json:"uptime"` + UserNumSta float64 `json:"user-num_sta"` + UsgCaps float64 `json:"usg_caps"` + Version string `json:"version"` + VersionIncompatible FlexBool `json:"version_incompatible"` Wan1 struct { BytesR float64 `json:"bytes-r"` DNS []string `json:"dns"` - Enable bool `json:"enable"` - FullDuplex bool `json:"full_duplex"` + Enable FlexBool `json:"enable"` + FullDuplex FlexBool `json:"full_duplex"` Gateway string `json:"gateway"` Ifname string `json:"ifname"` IP string `json:"ip"` @@ -233,8 +233,8 @@ type USG struct { Wan2 struct { BytesR float64 `json:"bytes-r"` DNS []string `json:"dns"` - Enable bool `json:"enable"` - FullDuplex bool `json:"full_duplex"` + Enable FlexBool `json:"enable"` + FullDuplex FlexBool `json:"full_duplex"` Gateway string `json:"gateway"` Ifname string `json:"ifname"` IP string `json:"ip"` diff --git a/core/unifi/usw_influx.go b/core/unifi/usw_influx.go index 810148de..d4e3db0b 100644 --- a/core/unifi/usw_influx.go +++ b/core/unifi/usw_influx.go @@ -1,7 +1,6 @@ package unifi import ( - "strconv" "time" influx "github.com/influxdata/influxdb1-client/v2" @@ -17,7 +16,7 @@ func (u USW) Points() ([]*influx.Point, error) { "device_oid": u.Stat.Oid, "site_id": u.SiteID, "name": u.Name, - "adopted": strconv.FormatBool(u.Adopted), + "adopted": u.Adopted.Txt, "adopt_ip": u.AdoptIP, "adopt_url": u.AdoptURL, "cfgversion": u.Cfgversion, @@ -25,24 +24,24 @@ func (u USW) Points() ([]*influx.Point, error) { "config_network_type": u.ConfigNetwork.Type, "connect_request_ip": u.ConnectRequestIP, "connect_request_port": u.ConnectRequestPort, - "default": strconv.FormatBool(u.Default), + "default": u.Default.Txt, "device_id": u.DeviceID, "discovered_via": u.DiscoveredVia, "inform_ip": u.InformIP, "last_uplink_mac": u.LastUplink.UplinkMac, "known_cfgversion": u.KnownCfgversion, "led_override": u.LedOverride, - "locating": strconv.FormatBool(u.Locating), + "locating": u.Locating.Txt, "model": u.Model, "outdoor_mode_override": u.OutdoorModeOverride, "serial": u.Serial, "type": u.Type, - "version_incompatible": strconv.FormatBool(u.VersionIncompatible), - "dot1x_portctrl_enabled": strconv.FormatBool(u.Dot1XPortctrlEnabled), - "flowctrl_enabled": strconv.FormatBool(u.FlowctrlEnabled), - "has_fan": strconv.FormatBool(u.HasFan), - "has_temperature": strconv.FormatBool(u.HasTemperature), - "jumboframe_enabled": strconv.FormatBool(u.JumboframeEnabled), + "version_incompatible": u.VersionIncompatible.Txt, + "dot1x_portctrl_enabled": u.Dot1XPortctrlEnabled.Txt, + "flowctrl_enabled": u.FlowctrlEnabled.Txt, + "has_fan": u.HasFan.Txt, + "has_temperature": u.HasTemperature.Txt, + "jumboframe_enabled": u.JumboframeEnabled.Txt, "stp_priority": u.StpPriority, "stp_version": u.StpVersion, } @@ -55,15 +54,15 @@ func (u USW) Points() ([]*influx.Point, error) { "general_temperature": u.GeneralTemperature, "last_seen": u.LastSeen, "license_state": u.LicenseState, - "overheating": u.Overheating, + "overheating": u.Overheating.Txt, "rx_bytes": u.RxBytes, "tx_bytes": u.TxBytes, "uptime": u.Uptime, "considered_lost_at": u.ConsideredLostAt, "next_heartbeat_at": u.NextHeartbeatAt, - "roll_upgrade": u.Rollupgrade, + "roll_upgrade": u.Rollupgrade.Txt, "state": u.State, - "upgradable": u.Upgradable, + "upgradable": u.Upgradable.Txt, "user-num_sta": u.UserNumSta, "version": u.Version, "loadavg_1": u.SysStats.Loadavg1, @@ -107,7 +106,7 @@ func (u USW) Points() ([]*influx.Point, error) { "stat_tx_errors": u.Stat.TxErrors, "stat_tx_packets": u.Stat.TxPackets, "stat_tx_retries": u.Stat.TxRetries, - "uplink_depth": strconv.FormatFloat(u.UplinkDepth, 'f', 6, 64), + "uplink_depth": u.UplinkDepth, // Add the port stats too. } pt, err := influx.NewPoint("usw", tags, fields, time.Now()) diff --git a/core/unifi/usw_type.go b/core/unifi/usw_type.go index a0d6485c..a5ae6eca 100644 --- a/core/unifi/usw_type.go +++ b/core/unifi/usw_type.go @@ -2,14 +2,14 @@ package unifi // USW represents all the data from the Ubiquiti Controller for a Unifi Switch. type USW struct { - ID string `json:"_id"` - UUptime float64 `json:"_uptime"` - AdoptIP string `json:"adopt_ip"` - AdoptURL string `json:"adopt_url"` - Adopted bool `json:"adopted"` - BoardRev float64 `json:"board_rev"` - Bytes float64 `json:"bytes"` - Cfgversion string `json:"cfgversion"` + ID string `json:"_id"` + UUptime float64 `json:"_uptime"` + AdoptIP string `json:"adopt_ip"` + AdoptURL string `json:"adopt_url"` + Adopted FlexBool `json:"adopted"` + BoardRev float64 `json:"board_rev"` + Bytes float64 `json:"bytes"` + Cfgversion string `json:"cfgversion"` ConfigNetwork struct { IP string `json:"ip"` Type string `json:"type"` @@ -17,48 +17,48 @@ type USW struct { ConnectRequestIP string `json:"connect_request_ip"` ConnectRequestPort string `json:"connect_request_port"` ConsideredLostAt float64 `json:"considered_lost_at"` - Default bool `json:"default"` + Default FlexBool `json:"default"` DeviceID string `json:"device_id"` DhcpServerTable []interface{} `json:"dhcp_server_table"` DiscoveredVia string `json:"discovered_via"` - Dot1XPortctrlEnabled bool `json:"dot1x_portctrl_enabled"` + Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"` DownlinkTable []struct { - FullDuplex bool `json:"full_duplex"` - Mac string `json:"mac"` - PortIdx float64 `json:"port_idx"` - Speed float64 `json:"speed"` + FullDuplex FlexBool `json:"full_duplex"` + Mac string `json:"mac"` + PortIdx float64 `json:"port_idx"` + Speed float64 `json:"speed"` } `json:"downlink_table"` EthernetTable []struct { Mac string `json:"mac"` Name string `json:"name"` NumPort float64 `json:"num_port,omitempty"` } `json:"ethernet_table"` - FanLevel float64 `json:"fan_level"` - FlowctrlEnabled bool `json:"flowctrl_enabled"` - FwCaps float64 `json:"fw_caps"` - GeneralTemperature float64 `json:"general_temperature"` - GuestNumSta float64 `json:"guest-num_sta"` - HasFan bool `json:"has_fan"` - HasTemperature bool `json:"has_temperature"` - InformIP string `json:"inform_ip"` - InformURL string `json:"inform_url"` - IP string `json:"ip"` - JumboframeEnabled bool `json:"jumboframe_enabled"` - KnownCfgversion string `json:"known_cfgversion"` - LastSeen float64 `json:"last_seen"` + FanLevel float64 `json:"fan_level"` + FlowctrlEnabled FlexBool `json:"flowctrl_enabled"` + FwCaps float64 `json:"fw_caps"` + GeneralTemperature float64 `json:"general_temperature"` + GuestNumSta float64 `json:"guest-num_sta"` + HasFan FlexBool `json:"has_fan"` + HasTemperature FlexBool `json:"has_temperature"` + InformIP string `json:"inform_ip"` + InformURL string `json:"inform_url"` + IP string `json:"ip"` + JumboframeEnabled FlexBool `json:"jumboframe_enabled"` + KnownCfgversion string `json:"known_cfgversion"` + LastSeen float64 `json:"last_seen"` LastUplink struct { UplinkMac string `json:"uplink_mac"` } `json:"last_uplink"` - LedOverride string `json:"led_override"` - LicenseState string `json:"license_state"` - Locating bool `json:"locating"` - Mac string `json:"mac"` - Model string `json:"model"` - Name string `json:"name"` - NextHeartbeatAt float64 `json:"next_heartbeat_at"` - NumSta float64 `json:"num_sta"` - OutdoorModeOverride string `json:"outdoor_mode_override"` - Overheating bool `json:"overheating"` + LedOverride string `json:"led_override"` + LicenseState string `json:"license_state"` + Locating FlexBool `json:"locating"` + Mac string `json:"mac"` + Model string `json:"model"` + Name string `json:"name"` + NextHeartbeatAt float64 `json:"next_heartbeat_at"` + NumSta float64 `json:"num_sta"` + OutdoorModeOverride string `json:"outdoor_mode_override"` + Overheating FlexBool `json:"overheating"` PortOverrides []struct { Name string `json:"name,omitempty"` PoeMode string `json:"poe_mode,omitempty"` @@ -66,32 +66,32 @@ type USW struct { PortconfID string `json:"portconf_id"` } `json:"port_overrides"` PortTable []struct { - AggregatedBy bool `json:"aggregated_by"` - Autoneg bool `json:"autoneg"` + AggregatedBy FlexBool `json:"aggregated_by"` + Autoneg FlexBool `json:"autoneg"` BytesR float64 `json:"bytes-r"` Dot1XMode string `json:"dot1x_mode"` Dot1XStatus string `json:"dot1x_status"` - Enable bool `json:"enable"` - FlowctrlRx bool `json:"flowctrl_rx"` - FlowctrlTx bool `json:"flowctrl_tx"` - FullDuplex bool `json:"full_duplex"` - IsUplink bool `json:"is_uplink"` - Jumbo bool `json:"jumbo"` + Enable FlexBool `json:"enable"` + FlowctrlRx FlexBool `json:"flowctrl_rx"` + FlowctrlTx FlexBool `json:"flowctrl_tx"` + FullDuplex FlexBool `json:"full_duplex"` + IsUplink FlexBool `json:"is_uplink"` + Jumbo FlexBool `json:"jumbo"` LldpTable []interface{} `json:"lldp_table"` - Masked bool `json:"masked"` + Masked FlexBool `json:"masked"` Media string `json:"media"` Name string `json:"name"` OpMode string `json:"op_mode"` PoeCaps float64 `json:"poe_caps"` PoeClass string `json:"poe_class,omitempty"` PoeCurrent string `json:"poe_current,omitempty"` - PoeEnable bool `json:"poe_enable,omitempty"` - PoeGood bool `json:"poe_good,omitempty"` + PoeEnable FlexBool `json:"poe_enable,omitempty"` + PoeGood FlexBool `json:"poe_good,omitempty"` PoeMode string `json:"poe_mode,omitempty"` PoePower string `json:"poe_power,omitempty"` PoeVoltage string `json:"poe_voltage,omitempty"` PortIdx float64 `json:"port_idx"` - PortPoe bool `json:"port_poe"` + PortPoe FlexBool `json:"port_poe"` PortconfID string `json:"portconf_id"` RxBroadcast float64 `json:"rx_broadcast"` RxBytes float64 `json:"rx_bytes"` @@ -110,10 +110,10 @@ type USW struct { TxErrors float64 `json:"tx_errors"` TxMulticast float64 `json:"tx_multicast"` TxPackets float64 `json:"tx_packets"` - Up bool `json:"up"` - SfpFound bool `json:"sfp_found,omitempty"` + Up FlexBool `json:"up"` + SfpFound FlexBool `json:"sfp_found,omitempty"` } `json:"port_table"` - Rollupgrade bool `json:"rollupgrade"` + Rollupgrade FlexBool `json:"rollupgrade"` RxBytes float64 `json:"rx_bytes"` Serial string `json:"serial"` SiteID string `json:"site_id"` @@ -378,38 +378,38 @@ type USW struct { Mem float64 `json:"mem,string"` Uptime float64 `json:"uptime,string"` } `json:"system-stats"` - TxBytes float64 `json:"tx_bytes"` - Type string `json:"type"` - Upgradable bool `json:"upgradable"` + TxBytes float64 `json:"tx_bytes"` + Type string `json:"type"` + Upgradable FlexBool `json:"upgradable"` Uplink struct { - FullDuplex bool `json:"full_duplex"` - IP string `json:"ip"` - Mac string `json:"mac"` - MaxSpeed float64 `json:"max_speed"` - Media string `json:"media"` - Name string `json:"name"` - Netmask string `json:"netmask"` - NumPort float64 `json:"num_port"` - PortIdx float64 `json:"port_idx"` - RxBytes float64 `json:"rx_bytes"` - RxBytesR float64 `json:"rx_bytes-r"` - RxDropped float64 `json:"rx_dropped"` - RxErrors float64 `json:"rx_errors"` - RxMulticast float64 `json:"rx_multicast"` - RxPackets float64 `json:"rx_packets"` - Speed float64 `json:"speed"` - TxBytes float64 `json:"tx_bytes"` - TxBytesR float64 `json:"tx_bytes-r"` - TxDropped float64 `json:"tx_dropped"` - TxErrors float64 `json:"tx_errors"` - TxPackets float64 `json:"tx_packets"` - Type string `json:"type"` - Up bool `json:"up"` - UplinkMac string `json:"uplink_mac"` + FullDuplex FlexBool `json:"full_duplex"` + IP string `json:"ip"` + Mac string `json:"mac"` + MaxSpeed float64 `json:"max_speed"` + Media string `json:"media"` + Name string `json:"name"` + Netmask string `json:"netmask"` + NumPort float64 `json:"num_port"` + PortIdx float64 `json:"port_idx"` + RxBytes float64 `json:"rx_bytes"` + RxBytesR float64 `json:"rx_bytes-r"` + RxDropped float64 `json:"rx_dropped"` + RxErrors float64 `json:"rx_errors"` + RxMulticast float64 `json:"rx_multicast"` + RxPackets float64 `json:"rx_packets"` + Speed float64 `json:"speed"` + TxBytes float64 `json:"tx_bytes"` + TxBytesR float64 `json:"tx_bytes-r"` + TxDropped float64 `json:"tx_dropped"` + TxErrors float64 `json:"tx_errors"` + TxPackets float64 `json:"tx_packets"` + Type string `json:"type"` + Up FlexBool `json:"up"` + UplinkMac string `json:"uplink_mac"` } `json:"uplink"` - UplinkDepth float64 `json:"uplink_depth"` - Uptime float64 `json:"uptime"` - UserNumSta float64 `json:"user-num_sta"` - Version string `json:"version"` - VersionIncompatible bool `json:"version_incompatible"` + UplinkDepth float64 `json:"uplink_depth"` + Uptime float64 `json:"uptime"` + UserNumSta float64 `json:"user-num_sta"` + Version string `json:"version"` + VersionIncompatible FlexBool `json:"version_incompatible"` } From 3349e422a34bd6af4f334146a502506f37122304 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Thu, 30 May 2019 01:45:02 -0700 Subject: [PATCH 031/194] Avoid field errors. Fix influxdb regressions. --- core/unifi/uap_influx.go | 22 +++++++++++----------- core/unifi/usg_influx.go | 8 ++++---- core/unifi/usw_influx.go | 8 ++++---- core/unifi/usw_type.go | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/core/unifi/uap_influx.go b/core/unifi/uap_influx.go index 04811da4..3b5072f2 100644 --- a/core/unifi/uap_influx.go +++ b/core/unifi/uap_influx.go @@ -65,11 +65,11 @@ func (u UAP) Points() ([]*influx.Point, error) { "uptime": u.Uptime.Val, "considered_lost_at": u.ConsideredLostAt, "next_heartbeat_at": u.NextHeartbeatAt, - "scanning": u.Scanning.Txt, - "spectrum_scanning": u.SpectrumScanning, - "roll_upgrade": u.Rollupgrade.Txt, + "scanning": u.Scanning.Val, + "spectrum_scanning": u.SpectrumScanning.Val, + "roll_upgrade": u.Rollupgrade.Val, "state": u.State, - "upgradable": u.Upgradable.Txt, + "upgradable": u.Upgradable.Val, "user-num_sta": u.UserNumSta, "version": u.Version, "loadavg_1": u.SysStats.Loadavg1, @@ -187,16 +187,16 @@ func (u UAP) Points() ([]*influx.Point, error) { fields := map[string]interface{}{ "builtin_ant_gain": p.BuiltinAntGain, "current_antenna_gain": p.CurrentAntennaGain, - "has_dfs": p.HasDfs.Txt, - "has_fccdfs": p.HasFccdfs.Txt, + "has_dfs": p.HasDfs.Val, + "has_fccdfs": p.HasFccdfs.Val, "ht": p.Ht, - "is_11ac": p.Is11Ac.Txt, + "is_11ac": p.Is11Ac.Val, "max_txpower": p.MaxTxpower, - "min_rssi_enabled": p.MinRssiEnabled.Txt, + "min_rssi_enabled": p.MinRssiEnabled.Val, "min_txpower": p.MinTxpower, "nss": p.Nss, "radio_caps": p.RadioCaps, - "tx_power": p.TxPower.Val, + "tx_power": int(p.TxPower.Val), // this will go float in 2.1. "tx_power_mode": p.TxPowerMode, } @@ -234,8 +234,8 @@ func (u UAP) Points() ([]*influx.Point, error) { fields["ccq"] = s.Ccq fields["essid"] = s.Essid fields["extchannel"] = s.Extchannel - fields["is_guest"] = s.IsGuest.Txt - fields["is_wep"] = s.IsWep.Txt + fields["is_guest"] = s.IsGuest.Val + fields["is_wep"] = s.IsWep.Val fields["mac_filter_rejections"] = s.MacFilterRejections fields["map_id"] = s.MapID fields["vap_rx_bytes"] = s.RxBytes diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index a3f0c520..cd35ffc6 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -53,9 +53,9 @@ func (u USG) Points() ([]*influx.Point, error) { "uptime": u.Uptime, "considered_lost_at": u.ConsideredLostAt, "next_heartbeat_at": u.NextHeartbeatAt, - "roll_upgrade": u.Rollupgrade.Txt, + "roll_upgrade": u.Rollupgrade.Val, "state": u.State, - "upgradable": u.Upgradable.Txt, + "upgradable": u.Upgradable.Val, "user-num_sta": u.UserNumSta, "version": u.Version, "num_desktop": u.NumDesktop, @@ -73,8 +73,8 @@ func (u USG) Points() ([]*influx.Point, error) { // have two WANs? mmmm, go ahead and add it. ;) "config_network_wan_type": u.ConfigNetworkWan.Type, "wan1_bytes-r": u.Wan1.BytesR, - "wan1_enable": u.Wan1.Enable, - "wan1_full_duplex": u.Wan1.FullDuplex.Txt, + "wan1_enable": u.Wan1.Enable.Val, + "wan1_full_duplex": u.Wan1.FullDuplex.Val, "wan1_purpose": "uplink", // because it should have a purpose. "wan1_gateway": u.Wan1.Gateway, "wan1_ifname": u.Wan1.Ifname, diff --git a/core/unifi/usw_influx.go b/core/unifi/usw_influx.go index d4e3db0b..8435c53e 100644 --- a/core/unifi/usw_influx.go +++ b/core/unifi/usw_influx.go @@ -54,15 +54,15 @@ func (u USW) Points() ([]*influx.Point, error) { "general_temperature": u.GeneralTemperature, "last_seen": u.LastSeen, "license_state": u.LicenseState, - "overheating": u.Overheating.Txt, + "overheating": u.Overheating.Val, "rx_bytes": u.RxBytes, "tx_bytes": u.TxBytes, "uptime": u.Uptime, "considered_lost_at": u.ConsideredLostAt, "next_heartbeat_at": u.NextHeartbeatAt, - "roll_upgrade": u.Rollupgrade.Txt, + "roll_upgrade": u.Rollupgrade.Val, "state": u.State, - "upgradable": u.Upgradable.Txt, + "upgradable": u.Upgradable.Val, "user-num_sta": u.UserNumSta, "version": u.Version, "loadavg_1": u.SysStats.Loadavg1, @@ -106,7 +106,7 @@ func (u USW) Points() ([]*influx.Point, error) { "stat_tx_errors": u.Stat.TxErrors, "stat_tx_packets": u.Stat.TxPackets, "stat_tx_retries": u.Stat.TxRetries, - "uplink_depth": u.UplinkDepth, + "uplink_depth": u.UplinkDepth.Txt, // Add the port stats too. } pt, err := influx.NewPoint("usw", tags, fields, time.Now()) diff --git a/core/unifi/usw_type.go b/core/unifi/usw_type.go index a5ae6eca..ef0081ff 100644 --- a/core/unifi/usw_type.go +++ b/core/unifi/usw_type.go @@ -407,7 +407,7 @@ type USW struct { Up FlexBool `json:"up"` UplinkMac string `json:"uplink_mac"` } `json:"uplink"` - UplinkDepth float64 `json:"uplink_depth"` + UplinkDepth FlexInt `json:"uplink_depth"` Uptime float64 `json:"uptime"` UserNumSta float64 `json:"user-num_sta"` Version string `json:"version"` From 78cf4e282a6799cce8a141cb8b2785878e77e48c Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Thu, 30 May 2019 11:00:09 -0700 Subject: [PATCH 032/194] Convert rxbytes in USG to FlexInt --- core/unifi/usg_influx.go | 6 +++--- core/unifi/usg_type.go | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index cd35ffc6..380b1b14 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -48,7 +48,7 @@ func (u USG) Points() ([]*influx.Point, error) { "license_state": u.LicenseState, "fw_caps": u.FwCaps, "guest-num_sta": u.GuestNumSta, - "rx_bytes": u.RxBytes, + "rx_bytes": u.RxBytes.Val, "tx_bytes": u.TxBytes, "uptime": u.Uptime, "considered_lost_at": u.ConsideredLostAt, @@ -83,7 +83,7 @@ func (u USG) Points() ([]*influx.Point, error) { "wan1_max_speed": u.Wan1.MaxSpeed, "wan1_name": u.Wan1.Name, "wan1_netmask": u.Wan1.Netmask, - "wan1_rx_bytes": u.Wan1.RxBytes, + "wan1_rx_bytes": u.Wan1.RxBytes.Val, "wan1_rx_bytes-r": u.Wan1.RxBytesR, "wan1_rx_dropped": u.Wan1.RxDropped, "wan1_rx_errors": u.Wan1.RxErrors, @@ -165,7 +165,7 @@ func (u USG) Points() ([]*influx.Point, error) { "name": p.Name, "num_sta": p.NumSta, "purpose": p.Purpose, - "rx_bytes": p.RxBytes, + "rx_bytes": p.RxBytes.Val, "rx_packets": p.RxPackets, "tx_bytes": p.TxBytes, "tx_packets": p.TxPackets, diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index 1dad0fca..897f5b80 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -65,7 +65,7 @@ type USG struct { Networkgroup string `json:"networkgroup"` NumSta float64 `json:"num_sta"` Purpose string `json:"purpose"` - RxBytes float64 `json:"rx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` RxPackets float64 `json:"rx_packets"` SiteID string `json:"site_id"` TxBytes float64 `json:"tx_bytes"` @@ -100,7 +100,7 @@ type USG struct { Mac string `json:"mac"` Name string `json:"name"` Netmask string `json:"netmask"` - RxBytes float64 `json:"rx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` RxDropped float64 `json:"rx_dropped"` RxErrors float64 `json:"rx_errors"` RxMulticast float64 `json:"rx_multicast"` @@ -113,7 +113,7 @@ type USG struct { Up FlexBool `json:"up"` } `json:"port_table"` Rollupgrade FlexBool `json:"rollupgrade"` - RxBytes float64 `json:"rx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` Serial string `json:"serial"` SiteID string `json:"site_id"` SpeedtestStatus struct { @@ -177,7 +177,7 @@ type USG struct { Nameservers []string `json:"nameservers"` Netmask string `json:"netmask"` NumPort float64 `json:"num_port"` - RxBytes float64 `json:"rx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` RxBytesR float64 `json:"rx_bytes-r"` RxDropped float64 `json:"rx_dropped"` RxErrors float64 `json:"rx_errors"` @@ -215,7 +215,7 @@ type USG struct { MaxSpeed float64 `json:"max_speed"` Name string `json:"name"` Netmask string `json:"netmask"` - RxBytes float64 `json:"rx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` RxBytesR float64 `json:"rx_bytes-r"` RxDropped float64 `json:"rx_dropped"` RxErrors float64 `json:"rx_errors"` @@ -242,7 +242,7 @@ type USG struct { MaxSpeed float64 `json:"max_speed"` Name string `json:"name"` Netmask string `json:"netmask"` - RxBytes float64 `json:"rx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` RxBytesR float64 `json:"rx_bytes-r"` RxDropped float64 `json:"rx_dropped"` RxErrors float64 `json:"rx_errors"` From 5dd618867633ebaffe0efe06c9d5572f297cb19b Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Thu, 30 May 2019 18:44:20 -0700 Subject: [PATCH 033/194] Convert txbytes in USG to FlexInt --- core/unifi/usg_influx.go | 6 +++--- core/unifi/usg_type.go | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index 380b1b14..c6225788 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -49,7 +49,7 @@ func (u USG) Points() ([]*influx.Point, error) { "fw_caps": u.FwCaps, "guest-num_sta": u.GuestNumSta, "rx_bytes": u.RxBytes.Val, - "tx_bytes": u.TxBytes, + "tx_bytes": u.TxBytes.Val, "uptime": u.Uptime, "considered_lost_at": u.ConsideredLostAt, "next_heartbeat_at": u.NextHeartbeatAt, @@ -92,7 +92,7 @@ func (u USG) Points() ([]*influx.Point, error) { "wan1_type": u.Wan1.Type, "wan1_speed": u.Wan1.Speed, "wan1_up": u.Wan1.Up.Val, - "wan1_tx_bytes": u.Wan1.TxBytes, + "wan1_tx_bytes": u.Wan1.TxBytes.Val, "wan1_tx_bytes-r": u.Wan1.TxBytesR, "wan1_tx_dropped": u.Wan1.TxDropped, "wan1_tx_errors": u.Wan1.TxErrors, @@ -167,7 +167,7 @@ func (u USG) Points() ([]*influx.Point, error) { "purpose": p.Purpose, "rx_bytes": p.RxBytes.Val, "rx_packets": p.RxPackets, - "tx_bytes": p.TxBytes, + "tx_bytes": p.TxBytes.Val, "tx_packets": p.TxPackets, "up": p.Up.Txt, "vlan": p.Vlan, diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index 897f5b80..014fdad1 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -68,7 +68,7 @@ type USG struct { RxBytes FlexInt `json:"rx_bytes"` RxPackets float64 `json:"rx_packets"` SiteID string `json:"site_id"` - TxBytes float64 `json:"tx_bytes"` + TxBytes FlexInt `json:"tx_bytes"` TxPackets float64 `json:"tx_packets"` Up FlexBool `json:"up"` Vlan string `json:"vlan,omitempty"` @@ -106,7 +106,7 @@ type USG struct { RxMulticast float64 `json:"rx_multicast"` RxPackets float64 `json:"rx_packets"` Speed float64 `json:"speed"` - TxBytes float64 `json:"tx_bytes"` + TxBytes FlexInt `json:"tx_bytes"` TxDropped float64 `json:"tx_dropped"` TxErrors float64 `json:"tx_errors"` TxPackets float64 `json:"tx_packets"` @@ -160,7 +160,7 @@ type USG struct { Mem float64 `json:"mem,string"` Uptime float64 `json:"uptime,string"` } `json:"system-stats"` - TxBytes float64 `json:"tx_bytes"` + TxBytes FlexInt `json:"tx_bytes"` Type string `json:"type"` Upgradable FlexBool `json:"upgradable"` Uplink struct { @@ -187,7 +187,7 @@ type USG struct { SpeedtestLastrun float64 `json:"speedtest_lastrun"` SpeedtestPing float64 `json:"speedtest_ping"` SpeedtestStatus string `json:"speedtest_status"` - TxBytes float64 `json:"tx_bytes"` + TxBytes FlexInt `json:"tx_bytes"` TxBytesR float64 `json:"tx_bytes-r"` TxDropped float64 `json:"tx_dropped"` TxErrors float64 `json:"tx_errors"` @@ -222,7 +222,7 @@ type USG struct { RxMulticast float64 `json:"rx_multicast"` RxPackets float64 `json:"rx_packets"` Speed float64 `json:"speed"` - TxBytes float64 `json:"tx_bytes"` + TxBytes FlexInt `json:"tx_bytes"` TxBytesR float64 `json:"tx_bytes-r"` TxDropped float64 `json:"tx_dropped"` TxErrors float64 `json:"tx_errors"` @@ -249,7 +249,7 @@ type USG struct { RxMulticast float64 `json:"rx_multicast"` RxPackets float64 `json:"rx_packets"` Speed float64 `json:"speed"` - TxBytes float64 `json:"tx_bytes"` + TxBytes FlexInt `json:"tx_bytes"` TxBytesR float64 `json:"tx_bytes-r"` TxDropped float64 `json:"tx_dropped"` TxErrors float64 `json:"tx_errors"` From 6b25037aa4ace29d8a06ec5c4007924df961765c Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 5 Jun 2019 13:37:13 -0700 Subject: [PATCH 034/194] Bug Fix --- core/unifi/clients_influx.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/clients_influx.go b/core/unifi/clients_influx.go index f1dc92d7..402bb428 100644 --- a/core/unifi/clients_influx.go +++ b/core/unifi/clients_influx.go @@ -99,7 +99,7 @@ func (c UCL) Points() ([]*influx.Point, error) { "wired-tx_packets": c.WiredTxPackets, } pt, err := influx.NewPoint("clients", tags, fields, time.Now()) - if err == nil { + if err != nil { return nil, err } return []*influx.Point{pt}, nil From 094f45d3a342f048a1cb18fde0f8c08ebccda5b8 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 5 Jun 2019 17:12:59 -0700 Subject: [PATCH 035/194] Add site name to all assets. Include Travis build. --- core/unifi/.travis.yml | 14 ++++++++++++++ core/unifi/clients_influx.go | 1 + core/unifi/clients_type.go | 1 + core/unifi/parsers.go | 5 ++++- core/unifi/uap_influx.go | 1 + core/unifi/uap_type.go | 1 + core/unifi/unifi.go | 26 +++++++++++++++++++++----- core/unifi/unifi_test.go | 3 ++- core/unifi/usg_influx.go | 1 + core/unifi/usg_type.go | 1 + core/unifi/usw_influx.go | 1 + core/unifi/usw_type.go | 1 + 12 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 core/unifi/.travis.yml diff --git a/core/unifi/.travis.yml b/core/unifi/.travis.yml new file mode 100644 index 00000000..c95dc3ca --- /dev/null +++ b/core/unifi/.travis.yml @@ -0,0 +1,14 @@ +language: go +go: +- 1.12.x +before_install: +- mkdir -p $GOPATH/bin + # Download the `dep` binary to bin folder in $GOPATH +- curl -sLo $GOPATH/bin/dep https://github.com/golang/dep/releases/download/v0.5.3/dep-darwin-amd64 +- chmod +x $GOPATH/bin/dep + # download super-linter: golangci-lint +- curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin latest +install: +- dep ensure +script: +- golangci-lint run --enable-all -e G402 diff --git a/core/unifi/clients_influx.go b/core/unifi/clients_influx.go index 402bb428..9219c785 100644 --- a/core/unifi/clients_influx.go +++ b/core/unifi/clients_influx.go @@ -25,6 +25,7 @@ func (c UCL) Points() ([]*influx.Point, error) { "mac": c.Mac, "user_id": c.UserID, "site_id": c.SiteID, + "site_name": c.SiteName, "network_id": c.NetworkID, "usergroup_id": c.UserGroupID, "ap_mac": c.ApMac, diff --git a/core/unifi/clients_type.go b/core/unifi/clients_type.go index 2ad29ccf..d0a21c04 100644 --- a/core/unifi/clients_type.go +++ b/core/unifi/clients_type.go @@ -66,6 +66,7 @@ type UCL struct { RxRate int64 `json:"rx_rate"` Signal int64 `json:"signal"` SiteID string `json:"site_id"` + SiteName string `json:"-"` SwDepth int `json:"sw_depth"` SwMac string `json:"sw_mac"` SwPort int `json:"sw_port"` diff --git a/core/unifi/parsers.go b/core/unifi/parsers.go index 70c2d193..672187ea 100644 --- a/core/unifi/parsers.go +++ b/core/unifi/parsers.go @@ -3,7 +3,7 @@ package unifi import "encoding/json" // parseDevices parses the raw JSON from the Unifi Controller into device structures. -func (u *Unifi) parseDevices(data []json.RawMessage) *Devices { +func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { devices := new(Devices) for _, r := range data { // Loop each item in the raw JSON message, detect its type and unmarshal it. @@ -18,14 +18,17 @@ func (u *Unifi) parseDevices(data []json.RawMessage) *Devices { switch assetType { // Unmarshal again into the correct type.. case "uap": if uap := (UAP{}); u.unmarshalDevice(assetType, r, &uap) == nil { + uap.SiteName = siteName devices.UAPs = append(devices.UAPs, uap) } case "ugw", "usg": // in case they ever fix the name in the api. if usg := (USG{}); u.unmarshalDevice(assetType, r, &usg) == nil { + usg.SiteName = siteName devices.USGs = append(devices.USGs, usg) } case "usw": if usw := (USW{}); u.unmarshalDevice(assetType, r, &usw) == nil { + usw.SiteName = siteName devices.USWs = append(devices.USWs, usw) } default: diff --git a/core/unifi/uap_influx.go b/core/unifi/uap_influx.go index 3b5072f2..53a369f3 100644 --- a/core/unifi/uap_influx.go +++ b/core/unifi/uap_influx.go @@ -20,6 +20,7 @@ func (u UAP) Points() ([]*influx.Point, error) { "device_oid": u.Stat.Oid, "device_ap": u.Stat.Ap, "site_id": u.SiteID, + "site_name": u.SiteName, "name": u.Name, "adopted": u.Adopted.Txt, "bandsteering_mode": u.BandsteeringMode, diff --git a/core/unifi/uap_type.go b/core/unifi/uap_type.go index 5ceae3f4..2250f4e5 100644 --- a/core/unifi/uap_type.go +++ b/core/unifi/uap_type.go @@ -163,6 +163,7 @@ type UAP struct { Scanning FlexBool `json:"scanning"` Serial string `json:"serial"` SiteID string `json:"site_id"` + SiteName string `json:"-"` SpectrumScanning FlexBool `json:"spectrum_scanning"` SSHSessionTable []interface{} `json:"ssh_session_table"` Stat struct { diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 0422a529..02ee58e6 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -60,7 +60,7 @@ func (u *Unifi) getController(user, pass string) error { // GetClients returns a response full of clients' data from the Unifi Controller. func (u *Unifi) GetClients(sites []Site) (*Clients, error) { - var data []UCL + data := make([]UCL, 0) for _, site := range sites { var response struct { Data []UCL `json:"data"` @@ -71,6 +71,9 @@ func (u *Unifi) GetClients(sites []Site) (*Clients, error) { if err := u.GetData(clientPath, &response); err != nil { return nil, err } + for i := range response.Data { + response.Data[i].SiteName = site.Name + } data = append(data, response.Data...) } return &Clients{UCLs: data}, nil @@ -78,7 +81,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) { - var data []json.RawMessage + devices := new(Devices) for _, site := range sites { u.dLogf("Polling Site '%s' (%s) Devices", site.Name, site.Desc) var response struct { @@ -88,9 +91,22 @@ func (u *Unifi) GetDevices(sites []Site) (*Devices, error) { if err := u.GetData(devicePath, &response); err != nil { return nil, err } - data = append(data, response.Data...) + loopDevices := u.parseDevices(response.Data, site.Name) + // Add SiteName to each device asset. + for i := range loopDevices.UAPs { + loopDevices.UAPs[i].SiteName = site.Name + } + for i := range loopDevices.USGs { + loopDevices.USGs[i].SiteName = site.Name + } + for i := range loopDevices.USWs { + loopDevices.USWs[i].SiteName = site.Name + } + devices.UAPs = append(devices.UAPs, loopDevices.UAPs...) + devices.USGs = append(devices.USGs, loopDevices.USGs...) + devices.USWs = append(devices.USWs, loopDevices.USWs...) } - return u.parseDevices(data), nil + return devices, nil } // GetSites returns a list of configured sites on the Unifi controller. @@ -101,7 +117,7 @@ func (u *Unifi) GetSites() ([]Site, error) { if err := u.GetData(SiteList, &response); err != nil { return nil, err } - var sites []string + sites := make([]string, 0) for i := range response.Data { sites = append(sites, response.Data[i].Name) } diff --git a/core/unifi/unifi_test.go b/core/unifi/unifi_test.go index dff7687d..7ab1df31 100644 --- a/core/unifi/unifi_test.go +++ b/core/unifi/unifi_test.go @@ -17,7 +17,8 @@ func TestNewUnifi(t *testing.T) { a.EqualValues(url, authReq.baseURL) a.Contains(err.Error(), "authReq.Do(req):", "an invalid destination should product a .Do(req) error.") /* TODO: OPEN web server, check parameters posted, more. This test is incomplete. - a.EqualValues(`{"username": "user1","password": "pass2"}`, string(post_params), "user/pass json parameters improperly encoded") + a.EqualValues(`{"username": "user1","password": "pass2"}`, string(post_params), + "user/pass json parameters improperly encoded") */ } diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index c6225788..1ab176ae 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -16,6 +16,7 @@ func (u USG) Points() ([]*influx.Point, error) { "device_type": u.Stat.O, "device_oid": u.Stat.Oid, "site_id": u.SiteID, + "site_name": u.SiteName, "adopted": u.Adopted.Txt, "name": u.Name, "adopt_ip": u.AdoptIP, diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index 014fdad1..b7762c73 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -116,6 +116,7 @@ type USG struct { RxBytes FlexInt `json:"rx_bytes"` Serial string `json:"serial"` SiteID string `json:"site_id"` + SiteName string `json:"-"` SpeedtestStatus struct { Latency float64 `json:"latency"` Rundate float64 `json:"rundate"` diff --git a/core/unifi/usw_influx.go b/core/unifi/usw_influx.go index 8435c53e..fa77d2aa 100644 --- a/core/unifi/usw_influx.go +++ b/core/unifi/usw_influx.go @@ -15,6 +15,7 @@ func (u USW) Points() ([]*influx.Point, error) { "device_type": u.Stat.O, "device_oid": u.Stat.Oid, "site_id": u.SiteID, + "site_name": u.SiteName, "name": u.Name, "adopted": u.Adopted.Txt, "adopt_ip": u.AdoptIP, diff --git a/core/unifi/usw_type.go b/core/unifi/usw_type.go index ef0081ff..c234eba7 100644 --- a/core/unifi/usw_type.go +++ b/core/unifi/usw_type.go @@ -117,6 +117,7 @@ type USW struct { RxBytes float64 `json:"rx_bytes"` Serial string `json:"serial"` SiteID string `json:"site_id"` + SiteName string `json:"-"` SSHSessionTable []interface{} `json:"ssh_session_table"` Stat struct { From 381ad45f12de4013af84611ab70d958ff1dafbb4 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 5 Jun 2019 17:32:30 -0700 Subject: [PATCH 036/194] Fix binary --- core/unifi/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/.travis.yml b/core/unifi/.travis.yml index c95dc3ca..b0d7f087 100644 --- a/core/unifi/.travis.yml +++ b/core/unifi/.travis.yml @@ -4,7 +4,7 @@ go: before_install: - mkdir -p $GOPATH/bin # Download the `dep` binary to bin folder in $GOPATH -- curl -sLo $GOPATH/bin/dep https://github.com/golang/dep/releases/download/v0.5.3/dep-darwin-amd64 +- curl -sLo $GOPATH/bin/dep https://github.com/golang/dep/releases/download/v0.5.3/dep-linux-amd64 - chmod +x $GOPATH/bin/dep # download super-linter: golangci-lint - curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin latest From d2519412c4f2d761c40b7a2de1a15e231373363d Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 5 Jun 2019 17:46:31 -0700 Subject: [PATCH 037/194] add more site names. --- core/unifi/Gopkg.lock | 2 +- core/unifi/uap_type.go | 1 + core/unifi/unifi.go | 6 ++++++ core/unifi/usg_type.go | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/core/unifi/Gopkg.lock b/core/unifi/Gopkg.lock index 92114921..0ee3eca3 100644 --- a/core/unifi/Gopkg.lock +++ b/core/unifi/Gopkg.lock @@ -19,7 +19,7 @@ "v2", ] pruneopts = "UT" - revision = "16c852ea613fa2d42fcdccc9a8b0802a8bdc6140" + revision = "8ff2fc3824fcb533795f9a2f233275f0bb18d6c5" [[projects]] digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b" diff --git a/core/unifi/uap_type.go b/core/unifi/uap_type.go index 2250f4e5..3b804501 100644 --- a/core/unifi/uap_type.go +++ b/core/unifi/uap_type.go @@ -333,6 +333,7 @@ type UAP struct { RxNwids float64 `json:"rx_nwids"` RxPackets float64 `json:"rx_packets"` SiteID string `json:"site_id"` + SiteName string `json:"-"` State string `json:"state"` T string `json:"t"` TxBytes float64 `json:"tx_bytes"` diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 02ee58e6..4c3754fa 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -95,9 +95,15 @@ func (u *Unifi) GetDevices(sites []Site) (*Devices, error) { // Add SiteName to each device asset. for i := range loopDevices.UAPs { loopDevices.UAPs[i].SiteName = site.Name + for j := range loopDevices.UAPs[i].VapTable { + loopDevices.UAPs[i].VapTable[j].SiteName = site.Name + } } for i := range loopDevices.USGs { loopDevices.USGs[i].SiteName = site.Name + for j := range loopDevices.USGs[i].NetworkTable { + loopDevices.USGs[i].NetworkTable[j].SiteName = site.Name + } } for i := range loopDevices.USWs { loopDevices.USWs[i].SiteName = site.Name diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index b7762c73..2f95a552 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -68,6 +68,7 @@ type USG struct { RxBytes FlexInt `json:"rx_bytes"` RxPackets float64 `json:"rx_packets"` SiteID string `json:"site_id"` + SiteName string `json:"-"` TxBytes FlexInt `json:"tx_bytes"` TxPackets float64 `json:"tx_packets"` Up FlexBool `json:"up"` From 03be1deae06ef1ebf20e01195397ddc190a20935 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 5 Jun 2019 18:00:11 -0700 Subject: [PATCH 038/194] Add site id and name to network tables --- core/unifi/uap_influx.go | 2 ++ core/unifi/usg_influx.go | 1 + 2 files changed, 3 insertions(+) diff --git a/core/unifi/uap_influx.go b/core/unifi/uap_influx.go index 53a369f3..e0945ed1 100644 --- a/core/unifi/uap_influx.go +++ b/core/unifi/uap_influx.go @@ -232,6 +232,8 @@ func (u UAP) Points() ([]*influx.Point, error) { tags["vap_id"] = s.ID tags["vap_name"] = s.Name tags["wlanconf_id"] = s.WlanconfID + tags["site_id"] = s.SiteID + tags["site_name"] = s.SiteName fields["ccq"] = s.Ccq fields["essid"] = s.Essid fields["extchannel"] = s.Extchannel diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index 1ab176ae..bfd8ecc9 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -154,6 +154,7 @@ func (u USG) Points() ([]*influx.Point, error) { "is_nat": p.IsNat.Txt, "networkgroup": p.Networkgroup, "site_id": p.SiteID, + "site_name": p.SiteName, } fields := map[string]interface{}{ "dhcpd_ip_1": p.DhcpdIP1, From 67237e9c38afe5dda30083ce920d640b8fc823c2 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Thu, 6 Jun 2019 16:40:32 -0700 Subject: [PATCH 039/194] Update USW device collection. --- core/unifi/usw_influx.go | 178 +++++++++++++++++++++++++-------------- core/unifi/usw_type.go | 44 +++++----- 2 files changed, 138 insertions(+), 84 deletions(-) diff --git a/core/unifi/usw_influx.go b/core/unifi/usw_influx.go index fa77d2aa..505812ee 100644 --- a/core/unifi/usw_influx.go +++ b/core/unifi/usw_influx.go @@ -47,72 +47,126 @@ func (u USW) Points() ([]*influx.Point, error) { "stp_version": u.StpVersion, } fields := map[string]interface{}{ - "fw_caps": u.FwCaps, - "guest-num_sta": u.GuestNumSta, - "ip": u.IP, - "bytes": u.Bytes, - "fan_level": u.FanLevel, - "general_temperature": u.GeneralTemperature, - "last_seen": u.LastSeen, - "license_state": u.LicenseState, - "overheating": u.Overheating.Val, - "rx_bytes": u.RxBytes, - "tx_bytes": u.TxBytes, - "uptime": u.Uptime, - "considered_lost_at": u.ConsideredLostAt, - "next_heartbeat_at": u.NextHeartbeatAt, - "roll_upgrade": u.Rollupgrade.Val, - "state": u.State, - "upgradable": u.Upgradable.Val, - "user-num_sta": u.UserNumSta, - "version": u.Version, - "loadavg_1": u.SysStats.Loadavg1, - "loadavg_5": u.SysStats.Loadavg5, - "loadavg_15": u.SysStats.Loadavg15, - "mem_buffer": u.SysStats.MemBuffer, - "mem_used": u.SysStats.MemUsed, - "mem_total": u.SysStats.MemTotal, - "cpu": u.SystemStats.CPU, - "mem": u.SystemStats.Mem, - "system_uptime": u.SystemStats.Uptime, - "stat_bytes": u.Stat.Bytes, - "stat_duration": u.Stat.Duration, - "stat_guest-rx_bytes": u.Stat.RxBytes, - "stat_guest-rx_crypts": u.Stat.RxCrypts, - "stat_guest-rx_dropped": u.Stat.RxDropped, - "stat_guest-rx_errors": u.Stat.RxErrors, - "stat_guest-rx_frags": u.Stat.RxFrags, - "stat_guest-rx_packets": u.Stat.RxPackets, - "stat_guest-tx_bytes": u.Stat.TxBytes, - "stat_guest-tx_dropped": u.Stat.TxDropped, - "stat_guest-tx_errors": u.Stat.TxErrors, - "stat_guest-tx_packets": u.Stat.TxPackets, - "stat_guest-tx_retries": u.Stat.TxRetries, - "stat_port_1-rx_broadcast": u.Stat.Port1RxBroadcast, - "stat_port_1-rx_bytes": u.Stat.Port1RxBytes, - "stat_port_1-rx_multicast": u.Stat.Port1RxMulticast, - "stat_port_1-rx_packets": u.Stat.Port1RxPackets, - "stat_port_1-tx_broadcast": u.Stat.Port1TxBroadcast, - "stat_port_1-tx_bytes": u.Stat.Port1TxBytes, - "stat_port_1-tx_multicast": u.Stat.Port1TxMulticast, - "stat_port_1-tx_packets": u.Stat.Port1TxPackets, - "stat_rx_bytes": u.Stat.RxBytes, - "stat_rx_crypts": u.Stat.RxCrypts, - "stat_rx_dropped": u.Stat.RxDropped, - "stat_rx_errors": u.Stat.RxErrors, - "stat_rx_frags": u.Stat.RxFrags, - "stat_rx_packets": u.Stat.TxPackets, - "stat_tx_bytes": u.Stat.TxBytes, - "stat_tx_dropped": u.Stat.TxDropped, - "stat_tx_errors": u.Stat.TxErrors, - "stat_tx_packets": u.Stat.TxPackets, - "stat_tx_retries": u.Stat.TxRetries, - "uplink_depth": u.UplinkDepth.Txt, + "fw_caps": u.FwCaps, + "guest-num_sta": u.GuestNumSta, + "ip": u.IP, + "bytes": u.Bytes, + "fan_level": u.FanLevel, + "general_temperature": u.GeneralTemperature, + "last_seen": u.LastSeen, + "license_state": u.LicenseState, + "overheating": u.Overheating.Val, + "rx_bytes": u.RxBytes, + "tx_bytes": u.TxBytes, + "uptime": u.Uptime, + "considered_lost_at": u.ConsideredLostAt, + "next_heartbeat_at": u.NextHeartbeatAt, + "roll_upgrade": u.Rollupgrade.Val, + "state": u.State, + "upgradable": u.Upgradable.Val, + "user-num_sta": u.UserNumSta, + "version": u.Version, + "loadavg_1": u.SysStats.Loadavg1, + "loadavg_5": u.SysStats.Loadavg5, + "loadavg_15": u.SysStats.Loadavg15, + "mem_buffer": u.SysStats.MemBuffer, + "mem_used": u.SysStats.MemUsed, + "mem_total": u.SysStats.MemTotal, + "cpu": u.SystemStats.CPU, + "mem": u.SystemStats.Mem, + "system_uptime": u.SystemStats.Uptime, + "stat_bytes": u.Stat.Bytes, + "stat_duration": u.Stat.Duration, + "stat_guest-rx_bytes": u.Stat.RxBytes, + "stat_guest-rx_crypts": u.Stat.RxCrypts, + "stat_guest-rx_dropped": u.Stat.RxDropped, + "stat_guest-rx_errors": u.Stat.RxErrors, + "stat_guest-rx_frags": u.Stat.RxFrags, + "stat_guest-rx_packets": u.Stat.RxPackets, + "stat_guest-tx_bytes": u.Stat.TxBytes, + "stat_guest-tx_dropped": u.Stat.TxDropped, + "stat_guest-tx_errors": u.Stat.TxErrors, + "stat_guest-tx_packets": u.Stat.TxPackets, + "stat_guest-tx_retries": u.Stat.TxRetries, + "stat_rx_bytes": u.Stat.RxBytes, + "stat_rx_crypts": u.Stat.RxCrypts, + "stat_rx_dropped": u.Stat.RxDropped, + "stat_rx_errors": u.Stat.RxErrors, + "stat_rx_frags": u.Stat.RxFrags, + "stat_rx_packets": u.Stat.TxPackets, + "stat_tx_bytes": u.Stat.TxBytes, + "stat_tx_dropped": u.Stat.TxDropped, + "stat_tx_errors": u.Stat.TxErrors, + "stat_tx_packets": u.Stat.TxPackets, + "stat_tx_retries": u.Stat.TxRetries, + "uplink_depth": u.UplinkDepth.Txt, // Add the port stats too. } pt, err := influx.NewPoint("usw", tags, fields, time.Now()) if err != nil { return nil, err } - return []*influx.Point{pt}, nil + points := []*influx.Point{pt} + for _, p := range u.PortTable { + tags := map[string]string{ + "site_id": u.SiteID, + "site_name": u.SiteName, + "device_name": u.Name, + "name": p.Name, + "enable": p.Enable.Txt, + "is_uplink": p.IsUplink.Txt, + "up": p.Up.Txt, + "portconf_id": p.PortconfID, + "dot1x_mode": p.Dot1XMode, + "dot1x_status": p.Dot1XStatus, + "stp_state": p.StpState, + "sfp_found": p.SfpFound.Txt, + "op_mode": p.OpMode, + "poe_mode": p.PoeMode, + "port_poe": p.PortPoe.Txt, + "port_idx": p.PortIdx.Txt, + "port_id": u.Name + " Port " + p.PortIdx.Txt, + "poe_enable": p.PoeEnable.Txt, + "flowctrl_rx": p.FlowctrlRx.Txt, + "flowctrl_tx": p.FlowctrlTx.Txt, + "autoneg": p.Autoneg.Txt, + "full_duplex": p.FullDuplex.Txt, + "jumbo": p.Jumbo.Txt, + "masked": p.Masked.Txt, + "poe_good": p.PoeGood.Txt, + "media": p.Media, + "poe_class": p.PoeClass, + "poe_caps": p.PoeCaps.Txt, + "aggregated_by": p.AggregatedBy.Txt, + } + fields := map[string]interface{}{ + "dbytes_r": p.BytesR.Val, + "rx_broadcast": p.RxBroadcast.Val, + "rx_bytes": p.RxBytes.Val, + "rx_bytes-r": p.RxBytesR.Val, + "rx_dropped": p.RxDropped.Val, + "rx_errors": p.RxErrors.Val, + "rx_multicast": p.RxMulticast.Val, + "rx_packets": p.RxPackets.Val, + "speed": p.Speed.Val, + "stp_pathcost": p.StpPathcost.Val, + "tx_broadcast": p.TxBroadcast.Val, + "tx_bytes": p.TxBytes.Val, + "tx_bytes-r": p.TxBytesR.Val, + "tx_dropped": p.TxDropped.Val, + "tx_errors": p.TxErrors.Val, + "tx_multicast": p.TxMulticast.Val, + "tx_packets": p.TxPackets.Val, + "poe_current": p.PoeCurrent.Val, + "poe_power": p.PoePower.Val, + "poe_voltage": p.PoeVoltage.Val, + "full_duplex": p.FullDuplex.Val, + } + pt, err = influx.NewPoint("usw_ports", tags, fields, time.Now()) + if err != nil { + return points, err + } + points = append(points, pt) + } + return points, nil } diff --git a/core/unifi/usw_type.go b/core/unifi/usw_type.go index c234eba7..c912f5d2 100644 --- a/core/unifi/usw_type.go +++ b/core/unifi/usw_type.go @@ -68,7 +68,7 @@ type USW struct { PortTable []struct { AggregatedBy FlexBool `json:"aggregated_by"` Autoneg FlexBool `json:"autoneg"` - BytesR float64 `json:"bytes-r"` + BytesR FlexInt `json:"bytes-r"` Dot1XMode string `json:"dot1x_mode"` Dot1XStatus string `json:"dot1x_status"` Enable FlexBool `json:"enable"` @@ -82,34 +82,34 @@ type USW struct { Media string `json:"media"` Name string `json:"name"` OpMode string `json:"op_mode"` - PoeCaps float64 `json:"poe_caps"` + PoeCaps FlexInt `json:"poe_caps"` PoeClass string `json:"poe_class,omitempty"` - PoeCurrent string `json:"poe_current,omitempty"` + PoeCurrent FlexInt `json:"poe_current,omitempty"` PoeEnable FlexBool `json:"poe_enable,omitempty"` PoeGood FlexBool `json:"poe_good,omitempty"` PoeMode string `json:"poe_mode,omitempty"` - PoePower string `json:"poe_power,omitempty"` - PoeVoltage string `json:"poe_voltage,omitempty"` - PortIdx float64 `json:"port_idx"` + PoePower FlexInt `json:"poe_power,omitempty"` + PoeVoltage FlexInt `json:"poe_voltage,omitempty"` + PortIdx FlexInt `json:"port_idx"` PortPoe FlexBool `json:"port_poe"` PortconfID string `json:"portconf_id"` - RxBroadcast float64 `json:"rx_broadcast"` - RxBytes float64 `json:"rx_bytes"` - RxBytesR float64 `json:"rx_bytes-r"` - RxDropped float64 `json:"rx_dropped"` - RxErrors float64 `json:"rx_errors"` - RxMulticast float64 `json:"rx_multicast"` - RxPackets float64 `json:"rx_packets"` - Speed float64 `json:"speed"` - StpPathcost float64 `json:"stp_pathcost"` + RxBroadcast FlexInt `json:"rx_broadcast"` + RxBytes FlexInt `json:"rx_bytes"` + RxBytesR FlexInt `json:"rx_bytes-r"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxMulticast FlexInt `json:"rx_multicast"` + RxPackets FlexInt `json:"rx_packets"` + Speed FlexInt `json:"speed"` + StpPathcost FlexInt `json:"stp_pathcost"` StpState string `json:"stp_state"` - TxBroadcast float64 `json:"tx_broadcast"` - TxBytes float64 `json:"tx_bytes"` - TxBytesR float64 `json:"tx_bytes-r"` - TxDropped float64 `json:"tx_dropped"` - TxErrors float64 `json:"tx_errors"` - TxMulticast float64 `json:"tx_multicast"` - TxPackets float64 `json:"tx_packets"` + TxBroadcast FlexInt `json:"tx_broadcast"` + TxBytes FlexInt `json:"tx_bytes"` + TxBytesR FlexInt `json:"tx_bytes-r"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxMulticast FlexInt `json:"tx_multicast"` + TxPackets FlexInt `json:"tx_packets"` Up FlexBool `json:"up"` SfpFound FlexBool `json:"sfp_found,omitempty"` } `json:"port_table"` From 9fc268211ed674d3ce0bfcd1a3b0d55b20a694c3 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Thu, 6 Jun 2019 17:44:25 -0700 Subject: [PATCH 040/194] Better site output --- core/unifi/unifi.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 4c3754fa..b12aeb41 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -72,7 +72,7 @@ func (u *Unifi) GetClients(sites []Site) (*Clients, error) { return nil, err } for i := range response.Data { - response.Data[i].SiteName = site.Name + response.Data[i].SiteName = site.Desc + " (" + site.Name + ")" } data = append(data, response.Data...) } @@ -91,22 +91,22 @@ func (u *Unifi) GetDevices(sites []Site) (*Devices, error) { if err := u.GetData(devicePath, &response); err != nil { return nil, err } - loopDevices := u.parseDevices(response.Data, site.Name) + loopDevices := u.parseDevices(response.Data, site.Desc+" ("+site.Name+")") // Add SiteName to each device asset. for i := range loopDevices.UAPs { loopDevices.UAPs[i].SiteName = site.Name for j := range loopDevices.UAPs[i].VapTable { - loopDevices.UAPs[i].VapTable[j].SiteName = site.Name + loopDevices.UAPs[i].VapTable[j].SiteName = site.Desc + " (" + site.Name + ")" } } for i := range loopDevices.USGs { loopDevices.USGs[i].SiteName = site.Name for j := range loopDevices.USGs[i].NetworkTable { - loopDevices.USGs[i].NetworkTable[j].SiteName = site.Name + loopDevices.USGs[i].NetworkTable[j].SiteName = site.Desc + " (" + site.Name + ")" } } for i := range loopDevices.USWs { - loopDevices.USWs[i].SiteName = site.Name + loopDevices.USWs[i].SiteName = site.Desc + " (" + site.Name + ")" } devices.UAPs = append(devices.UAPs, loopDevices.UAPs...) devices.USGs = append(devices.USGs, loopDevices.USGs...) From bad744c1b297cfae6ab1b1ccb50a980b7b0a0b8f Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Thu, 6 Jun 2019 18:12:27 -0700 Subject: [PATCH 041/194] missed two --- core/unifi/unifi.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index b12aeb41..b7e45f6c 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -94,13 +94,13 @@ func (u *Unifi) GetDevices(sites []Site) (*Devices, error) { loopDevices := u.parseDevices(response.Data, site.Desc+" ("+site.Name+")") // Add SiteName to each device asset. for i := range loopDevices.UAPs { - loopDevices.UAPs[i].SiteName = site.Name + loopDevices.UAPs[i].SiteName = site.Desc + " (" + site.Name + ")" for j := range loopDevices.UAPs[i].VapTable { loopDevices.UAPs[i].VapTable[j].SiteName = site.Desc + " (" + site.Name + ")" } } for i := range loopDevices.USGs { - loopDevices.USGs[i].SiteName = site.Name + loopDevices.USGs[i].SiteName = site.Desc + " (" + site.Name + ")" for j := range loopDevices.USGs[i].NetworkTable { loopDevices.USGs[i].NetworkTable[j].SiteName = site.Desc + " (" + site.Name + ")" } From 62484143912b635b60d7b590ad70259f3514c63a Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Fri, 14 Jun 2019 02:25:34 -0700 Subject: [PATCH 042/194] Provide Points for sites. Add GetServer/version. --- core/unifi/site_influx.go | 81 +++++++++++++++++++++++++++++++++++++++ core/unifi/site_type.go | 57 +++++++++++++++++++++++++++ core/unifi/types.go | 16 ++++---- core/unifi/unifi.go | 9 +++++ 4 files changed, 156 insertions(+), 7 deletions(-) create mode 100644 core/unifi/site_influx.go create mode 100644 core/unifi/site_type.go diff --git a/core/unifi/site_influx.go b/core/unifi/site_influx.go new file mode 100644 index 00000000..f78b3c3e --- /dev/null +++ b/core/unifi/site_influx.go @@ -0,0 +1,81 @@ +package unifi + +import ( + "strings" + "time" + + influx "github.com/influxdata/influxdb1-client/v2" +) + +// Points generates Unifi Sites' datapoints for InfluxDB. +// These points can be passed directly to influx. +func (u Site) Points() ([]*influx.Point, error) { + points := make([]*influx.Point, 1) + for _, s := range u.Health { + tags := map[string]string{ + "id": u.ID, + "name": u.Name, + "desc": u.Desc, + "status": s.Status, + "subsystem": s.Subsystem, + "wan_ip": s.WanIP, + "netmask": s.Netmask, + "gw_name": s.GwName, + "gw_mac": s.GwMac, + "gw_version": s.GwVersion, + "speedtest_status": s.SpeedtestStatus, + "lan_ip": s.LanIP, + "remote_user_enabled": s.RemoteUserEnabled.Txt, + "site_to_site_enabled": s.SiteToSiteEnabled.Txt, + "nameservers": strings.Join(s.Nameservers, ","), + "gateways": strings.Join(s.Gateways, ","), + "num_new_alarms": u.NumNewAlarms.Txt, + "attr_hidden_id": u.AttrHiddenID, + "attr_no_delete": u.AttrNoDelete.Txt, + } + fields := map[string]interface{}{ + "attr_hidden_id": u.AttrHiddenID, + "attr_no_delete": u.AttrNoDelete.Val, + "num_user": s.NumUser.Val, + "num_guest": s.NumGuest.Val, + "num_iot": s.NumIot.Val, + "tx_bytes-r": s.TxBytesR.Val, + "rx_bytes-r": s.RxBytesR.Val, + "status": s.Status, + "num_ap": s.NumAp.Val, + "num_adopted": s.NumAdopted.Val, + "num_disabled": s.NumDisabled.Val, + "num_disconnected": s.NumDisconnected.Val, + "num_pending": s.NumPending.Val, + "num_gw": s.NumGw.Val, + "wan_ip": s.WanIP, + "num_sta": s.NumSta.Val, + "gw_cpu": s.GwSystemStats.CPU.Val, + "gw_mem": s.GwSystemStats.Mem.Val, + "gw_uptime": s.GwSystemStats.Uptime.Val, + "latency": s.Latency.Val, + "uptime": s.Uptime.Val, + "drops": s.Drops.Val, + "xput_up": s.XputUp.Val, + "xput_down": s.XputDown.Val, + "speedtest_ping": s.SpeedtestPing.Val, + "speedtest_lastrun": s.SpeedtestLastrun.Val, + "num_sw": s.NumSw.Val, + "remote_user_num_active": s.RemoteUserNumActive.Val, + "remote_user_num_inactive": s.RemoteUserNumInactive.Val, + "remote_user_rx_bytes": s.RemoteUserRxBytes.Val, + "remote_user_tx_bytes": s.RemoteUserTxBytes.Val, + "remote_user_rx_packets": s.RemoteUserRxPackets.Val, + "remote_user_tx_packets": s.RemoteUserTxPackets.Val, + "num_new_alarms": u.NumNewAlarms.Val, + "nameservers": len(s.Nameservers), + "gateways": len(s.Gateways), + } + pt, err := influx.NewPoint("subsystems", tags, fields, time.Now()) + if err != nil { + return points, err + } + points = append(points, pt) + } + return points, nil +} diff --git a/core/unifi/site_type.go b/core/unifi/site_type.go new file mode 100644 index 00000000..b215363f --- /dev/null +++ b/core/unifi/site_type.go @@ -0,0 +1,57 @@ +package unifi + +// Site represents a site's data. +type Site struct { + ID string `json:"_id"` + Name string `json:"name"` + Desc string `json:"desc"` + AttrHiddenID string `json:"attr_hidden_id"` + AttrNoDelete FlexBool `json:"attr_no_delete"` + Health []struct { + Subsystem string `json:"subsystem"` + NumUser FlexInt `json:"num_user,omitempty"` + NumGuest FlexInt `json:"num_guest,omitempty"` + NumIot FlexInt `json:"num_iot,omitempty"` + TxBytesR FlexInt `json:"tx_bytes-r,omitempty"` + RxBytesR FlexInt `json:"rx_bytes-r,omitempty"` + Status string `json:"status"` + NumAp FlexInt `json:"num_ap,omitempty"` + NumAdopted FlexInt `json:"num_adopted,omitempty"` + NumDisabled FlexInt `json:"num_disabled,omitempty"` + NumDisconnected FlexInt `json:"num_disconnected,omitempty"` + NumPending FlexInt `json:"num_pending,omitempty"` + NumGw FlexInt `json:"num_gw,omitempty"` + WanIP string `json:"wan_ip,omitempty"` + Gateways []string `json:"gateways,omitempty"` + Netmask string `json:"netmask,omitempty"` + Nameservers []string `json:"nameservers,omitempty"` + NumSta FlexInt `json:"num_sta,omitempty"` + GwMac string `json:"gw_mac,omitempty"` + GwName string `json:"gw_name,omitempty"` + GwSystemStats struct { + CPU FlexInt `json:"cpu"` + Mem FlexInt `json:"mem"` + Uptime FlexInt `json:"uptime"` + } `json:"gw_system-stats,omitempty"` + GwVersion string `json:"gw_version,omitempty"` + Latency FlexInt `json:"latency,omitempty"` + Uptime FlexInt `json:"uptime,omitempty"` + Drops FlexInt `json:"drops,omitempty"` + XputUp FlexInt `json:"xput_up,omitempty"` + XputDown FlexInt `json:"xput_down,omitempty"` + SpeedtestStatus string `json:"speedtest_status,omitempty"` + SpeedtestLastrun FlexInt `json:"speedtest_lastrun,omitempty"` + SpeedtestPing FlexInt `json:"speedtest_ping,omitempty"` + LanIP string `json:"lan_ip,omitempty"` + NumSw FlexInt `json:"num_sw,omitempty"` + RemoteUserEnabled FlexBool `json:"remote_user_enabled,omitempty"` + RemoteUserNumActive FlexInt `json:"remote_user_num_active,omitempty"` + RemoteUserNumInactive FlexInt `json:"remote_user_num_inactive,omitempty"` + RemoteUserRxBytes FlexInt `json:"remote_user_rx_bytes,omitempty"` + RemoteUserTxBytes FlexInt `json:"remote_user_tx_bytes,omitempty"` + RemoteUserRxPackets FlexInt `json:"remote_user_rx_packets,omitempty"` + RemoteUserTxPackets FlexInt `json:"remote_user_tx_packets,omitempty"` + SiteToSiteEnabled FlexBool `json:"site_to_site_enabled,omitempty"` + } `json:"health"` + NumNewAlarms FlexInt `json:"num_new_alarms"` +} diff --git a/core/unifi/types.go b/core/unifi/types.go index 61266609..ab075bbe 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -12,8 +12,10 @@ import ( // This is a list of unifi API paths. // The %s in each string must be replaced with a Site.Name. const ( + // StatusPath shows Controller version. + StatusPath string = "/status" // SiteList is the path to the api site list. - SiteList string = "/api/self/sites" + SiteList string = "/api/stat/sites" // ClientPath is Unifi Clients API Path ClientPath string = "/api/s/%s/stat/sta" // DevicePath is where we get data about Unifi devices. @@ -67,11 +69,11 @@ type Unifi struct { DebugLog Logger } -// Site represents a site's data. There are more pieces to this, but this is -// all we expose. -type Site struct { - Name string `json:"name"` - Desc string `json:"desc"` +// Server is the /status endpoint from the Unifi controller. +type Server struct { + Up FlexBool `json:"up"` + ServerVersion string `json:"server_version"` + UUID string `json:"uuid"` } // FlexInt provides a container and unmarshalling for fields that may be @@ -109,7 +111,7 @@ type FlexBool struct { Txt string } -// UnmarshalJSO method converts armed/disarmed, yes/no, active/inactive or 0/1 to true/false. +// UnmarshalJSON method converts armed/disarmed, yes/no, active/inactive or 0/1 to true/false. // Really it converts ready, up, t, armed, yes, active, enabled, 1, true to true. Anything else is false. func (f *FlexBool) UnmarshalJSON(b []byte) error { f.Txt = strings.Trim(string(b), `"`) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index b7e45f6c..7afb2af2 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -58,6 +58,15 @@ func (u *Unifi) getController(user, pass string) error { return nil } +// GetServer returns the controller's version and UUID. +func (u *Unifi) GetServer() (Server, error) { + var response struct { + Data Server `json:"meta"` + } + err := u.GetData(StatusPath, &response) + return response.Data, err +} + // GetClients returns a response full of clients' data from the Unifi Controller. func (u *Unifi) GetClients(sites []Site) (*Clients, error) { data := make([]UCL, 0) From 96b55d2acc9d3eb592a60a0c350fb77a130d6474 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Fri, 14 Jun 2019 02:43:52 -0700 Subject: [PATCH 043/194] Make bools say false. --- core/unifi/types.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/unifi/types.go b/core/unifi/types.go index ab075bbe..a592886e 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -114,8 +114,10 @@ type FlexBool struct { // UnmarshalJSON method converts armed/disarmed, yes/no, active/inactive or 0/1 to true/false. // Really it converts ready, up, t, armed, yes, active, enabled, 1, true to true. Anything else is false. func (f *FlexBool) UnmarshalJSON(b []byte) error { - f.Txt = strings.Trim(string(b), `"`) - f.Val = f.Txt == "1" || strings.EqualFold(f.Txt, "true") || strings.EqualFold(f.Txt, "yes") || + if f.Txt = strings.Trim(string(b), `"`); f.Txt == "" { + f.Txt = "false" + } + f.Val = f.Txt == "1" || strings.EqualFold(f.Txt, "true") || strings.EqualFold(f.Txt, "yes") || strings.EqualFold(f.Txt, "ok") || strings.EqualFold(f.Txt, "t") || strings.EqualFold(f.Txt, "armed") || strings.EqualFold(f.Txt, "active") || strings.EqualFold(f.Txt, "enabled") || strings.EqualFold(f.Txt, "ready") || strings.EqualFold(f.Txt, "up") return nil From f30b2f1c4c3d93265288f776b92251557d478217 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Fri, 14 Jun 2019 02:53:59 -0700 Subject: [PATCH 044/194] missed one --- core/unifi/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/types.go b/core/unifi/types.go index a592886e..f595f5f7 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -112,7 +112,7 @@ type FlexBool struct { } // UnmarshalJSON method converts armed/disarmed, yes/no, active/inactive or 0/1 to true/false. -// Really it converts ready, up, t, armed, yes, active, enabled, 1, true to true. Anything else is false. +// Really it converts ready, ok, up, t, armed, yes, active, enabled, 1, true to true. Anything else is false. func (f *FlexBool) UnmarshalJSON(b []byte) error { if f.Txt = strings.Trim(string(b), `"`); f.Txt == "" { f.Txt = "false" From f2ea58b00764f257f61abddf18ab381f46b81478 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Fri, 14 Jun 2019 02:56:21 -0700 Subject: [PATCH 045/194] Shorten line --- core/unifi/types.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/unifi/types.go b/core/unifi/types.go index f595f5f7..63530eec 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -117,8 +117,9 @@ func (f *FlexBool) UnmarshalJSON(b []byte) error { if f.Txt = strings.Trim(string(b), `"`); f.Txt == "" { f.Txt = "false" } - f.Val = f.Txt == "1" || strings.EqualFold(f.Txt, "true") || strings.EqualFold(f.Txt, "yes") || strings.EqualFold(f.Txt, "ok") || + f.Val = f.Txt == "1" || strings.EqualFold(f.Txt, "true") || strings.EqualFold(f.Txt, "yes") || strings.EqualFold(f.Txt, "t") || strings.EqualFold(f.Txt, "armed") || strings.EqualFold(f.Txt, "active") || - strings.EqualFold(f.Txt, "enabled") || strings.EqualFold(f.Txt, "ready") || strings.EqualFold(f.Txt, "up") + strings.EqualFold(f.Txt, "enabled") || strings.EqualFold(f.Txt, "ready") || strings.EqualFold(f.Txt, "up") || + strings.EqualFold(f.Txt, "ok") return nil } From 3f95db9deb3a1999f92e3d6cebaffb5cbfc41d36 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Fri, 14 Jun 2019 03:07:52 -0700 Subject: [PATCH 046/194] attempt to fix build --- core/unifi/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/.travis.yml b/core/unifi/.travis.yml index b0d7f087..1027a41e 100644 --- a/core/unifi/.travis.yml +++ b/core/unifi/.travis.yml @@ -7,7 +7,7 @@ before_install: - curl -sLo $GOPATH/bin/dep https://github.com/golang/dep/releases/download/v0.5.3/dep-linux-amd64 - chmod +x $GOPATH/bin/dep # download super-linter: golangci-lint -- curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin latest +- curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin latest install: - dep ensure script: From 9cac7db8590267bc4659d45665f4c44bc2c2630a Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Fri, 14 Jun 2019 03:09:39 -0700 Subject: [PATCH 047/194] attempt to fix build again --- core/unifi/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/.travis.yml b/core/unifi/.travis.yml index 1027a41e..24c1ed7e 100644 --- a/core/unifi/.travis.yml +++ b/core/unifi/.travis.yml @@ -7,7 +7,7 @@ before_install: - curl -sLo $GOPATH/bin/dep https://github.com/golang/dep/releases/download/v0.5.3/dep-linux-amd64 - chmod +x $GOPATH/bin/dep # download super-linter: golangci-lint -- curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin latest +- curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.16.0 install: - dep ensure script: From cec0cfec60b2bec2a9290e94fddcd29b908d44a9 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Fri, 14 Jun 2019 20:12:28 -0700 Subject: [PATCH 048/194] cleanup --- core/unifi/clients_type.go | 5 +++++ core/unifi/site_influx.go | 2 +- core/unifi/site_type.go | 3 +++ core/unifi/types.go | 5 ----- core/unifi/unifi.go | 2 +- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/core/unifi/clients_type.go b/core/unifi/clients_type.go index d0a21c04..820e4b48 100644 --- a/core/unifi/clients_type.go +++ b/core/unifi/clients_type.go @@ -1,5 +1,10 @@ package unifi +// Clients contains a list that contains all of the unifi clients from a controller. +type Clients struct { + UCLs []UCL +} + // UCL defines all the data a connected-network client contains. type UCL struct { ID string `json:"_id"` diff --git a/core/unifi/site_influx.go b/core/unifi/site_influx.go index f78b3c3e..a0ad2c77 100644 --- a/core/unifi/site_influx.go +++ b/core/unifi/site_influx.go @@ -10,7 +10,7 @@ import ( // Points generates Unifi Sites' datapoints for InfluxDB. // These points can be passed directly to influx. func (u Site) Points() ([]*influx.Point, error) { - points := make([]*influx.Point, 1) + var points []*influx.Point for _, s := range u.Health { tags := map[string]string{ "id": u.ID, diff --git a/core/unifi/site_type.go b/core/unifi/site_type.go index b215363f..23eba62c 100644 --- a/core/unifi/site_type.go +++ b/core/unifi/site_type.go @@ -1,5 +1,8 @@ package unifi +// Sites is a struct to match Devices and Clients. +type Sites []Site + // Site represents a site's data. type Site struct { ID string `json:"_id"` diff --git a/core/unifi/types.go b/core/unifi/types.go index 63530eec..a2795ade 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -54,11 +54,6 @@ type Devices struct { USWs []USW } -// Clients contains a list that contains all of the unifi clients from a controller. -type Clients struct { - UCLs []UCL -} - // Unifi is what you get in return for providing a password! Unifi represents // a controller that you can make authenticated requests to. Use this to make // additional requests for devices, clients or other custom data. diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 7afb2af2..0676b3e1 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -125,7 +125,7 @@ func (u *Unifi) GetDevices(sites []Site) (*Devices, error) { } // GetSites returns a list of configured sites on the Unifi controller. -func (u *Unifi) GetSites() ([]Site, error) { +func (u *Unifi) GetSites() (Sites, error) { var response struct { Data []Site `json:"data"` } From 13274f142342ac7aed385c44ee51cc0b388f1cab Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Fri, 14 Jun 2019 21:01:47 -0700 Subject: [PATCH 049/194] Make Clients normal --- core/unifi/clients_influx.go | 2 +- core/unifi/clients_type.go | 8 +++----- core/unifi/parsers.go | 2 +- core/unifi/site_influx.go | 2 +- core/unifi/unifi.go | 14 ++++++-------- 5 files changed, 12 insertions(+), 16 deletions(-) diff --git a/core/unifi/clients_influx.go b/core/unifi/clients_influx.go index 9219c785..e59bbcf7 100644 --- a/core/unifi/clients_influx.go +++ b/core/unifi/clients_influx.go @@ -9,7 +9,7 @@ import ( // Points generates Unifi Client datapoints for InfluxDB. // These points can be passed directly to influx. -func (c UCL) Points() ([]*influx.Point, error) { +func (c Client) Points() ([]*influx.Point, error) { // Fix name and hostname fields. Sometimes one or the other is blank. switch { case c.Hostname == "" && c.Name == "": diff --git a/core/unifi/clients_type.go b/core/unifi/clients_type.go index 820e4b48..662a4ca6 100644 --- a/core/unifi/clients_type.go +++ b/core/unifi/clients_type.go @@ -1,12 +1,10 @@ package unifi // Clients contains a list that contains all of the unifi clients from a controller. -type Clients struct { - UCLs []UCL -} +type Clients []Client -// UCL defines all the data a connected-network client contains. -type UCL struct { +// Client defines all the data a connected-network client contains. +type Client struct { ID string `json:"_id"` IsGuestByUAP FlexBool `json:"_is_guest_by_uap"` IsGuestByUGW FlexBool `json:"_is_guest_by_ugw"` diff --git a/core/unifi/parsers.go b/core/unifi/parsers.go index 672187ea..a2b97ce5 100644 --- a/core/unifi/parsers.go +++ b/core/unifi/parsers.go @@ -13,7 +13,7 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { } else if t, ok := o["type"].(string); ok { assetType = t } - u.dLogf("Unmarshalling Device Type: %v", assetType) + u.dLogf("Unmarshalling Device Type: %v, site %s ", assetType, siteName) // Choose which type to unmarshal into based on the "type" json key. switch assetType { // Unmarshal again into the correct type.. case "uap": diff --git a/core/unifi/site_influx.go b/core/unifi/site_influx.go index a0ad2c77..bd219ba9 100644 --- a/core/unifi/site_influx.go +++ b/core/unifi/site_influx.go @@ -10,7 +10,7 @@ import ( // Points generates Unifi Sites' datapoints for InfluxDB. // These points can be passed directly to influx. func (u Site) Points() ([]*influx.Point, error) { - var points []*influx.Point + points := []*influx.Point{} for _, s := range u.Health { tags := map[string]string{ "id": u.ID, diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 0676b3e1..aacd9cf3 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -68,14 +68,13 @@ func (u *Unifi) GetServer() (Server, error) { } // GetClients returns a response full of clients' data from the Unifi Controller. -func (u *Unifi) GetClients(sites []Site) (*Clients, error) { - data := make([]UCL, 0) +func (u *Unifi) GetClients(sites []Site) (Clients, error) { + data := make([]Client, 0) for _, site := range sites { var response struct { - Data []UCL `json:"data"` + Data []Client `json:"data"` } - u.dLogf("Polling Site '%s' (%s) Clients", site.Name, site.Desc) - u.dLogf("Unmarshalling Device Type: ucl") + u.dLogf("Polling Controller, retreiving Unifi Clients, site %s (%s) ", site.Name, site.Desc) clientPath := fmt.Sprintf(ClientPath, site.Name) if err := u.GetData(clientPath, &response); err != nil { return nil, err @@ -85,14 +84,13 @@ func (u *Unifi) GetClients(sites []Site) (*Clients, error) { } data = append(data, response.Data...) } - return &Clients{UCLs: data}, nil + return data, nil } // GetDevices returns a response full of devices' data from the Unifi Controller. func (u *Unifi) GetDevices(sites []Site) (*Devices, error) { devices := new(Devices) for _, site := range sites { - u.dLogf("Polling Site '%s' (%s) Devices", site.Name, site.Desc) var response struct { Data []json.RawMessage `json:"data"` } @@ -136,7 +134,7 @@ func (u *Unifi) GetSites() (Sites, error) { for i := range response.Data { sites = append(sites, response.Data[i].Name) } - u.dLogf("Found %d sites: %s", len(sites), strings.Join(sites, ",")) + u.dLogf("Found %d site(s): %s", len(sites), strings.Join(sites, ",")) return response.Data, nil } From 7fff26c20e562c245ac73f8e992a80bc88d86275 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Fri, 14 Jun 2019 21:05:13 -0700 Subject: [PATCH 050/194] fix readme --- core/unifi/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/unifi/README.md b/core/unifi/README.md index 177519ef..c0cf00e9 100644 --- a/core/unifi/README.md +++ b/core/unifi/README.md @@ -45,8 +45,8 @@ func main() { } log.Println(len(sites), "Unifi Sites Found: ", sites) - log.Println(len(clients.UCLs), "Clients connected:") - for i, client := range clients.UCLs { + log.Println(len(clients), "Clients connected:") + for i, client := range clients { log.Println(i+1, client.ID, client.Hostname, client.IP, client.Name, client.LastSeen) } From 633dbda4d334c01dd968ef2ea9a1872ca5f734e4 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 15 Jun 2019 12:49:46 -0700 Subject: [PATCH 051/194] Add full site name to sites. --- core/unifi/site_influx.go | 1 + core/unifi/site_type.go | 1 + core/unifi/unifi.go | 1 + 3 files changed, 3 insertions(+) diff --git a/core/unifi/site_influx.go b/core/unifi/site_influx.go index bd219ba9..20a7543d 100644 --- a/core/unifi/site_influx.go +++ b/core/unifi/site_influx.go @@ -15,6 +15,7 @@ func (u Site) Points() ([]*influx.Point, error) { tags := map[string]string{ "id": u.ID, "name": u.Name, + "site_name": u.SiteName, "desc": u.Desc, "status": s.Status, "subsystem": s.Subsystem, diff --git a/core/unifi/site_type.go b/core/unifi/site_type.go index 23eba62c..fd695457 100644 --- a/core/unifi/site_type.go +++ b/core/unifi/site_type.go @@ -8,6 +8,7 @@ type Site struct { ID string `json:"_id"` Name string `json:"name"` Desc string `json:"desc"` + SiteName string `json:"-"` AttrHiddenID string `json:"attr_hidden_id"` AttrNoDelete FlexBool `json:"attr_no_delete"` Health []struct { diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index aacd9cf3..39a08282 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -132,6 +132,7 @@ func (u *Unifi) GetSites() (Sites, error) { } sites := make([]string, 0) for i := range response.Data { + response.Data[i].SiteName = response.Data[i].Desc + " (" + response.Data[i].Name + ")" sites = append(sites, response.Data[i].Name) } u.dLogf("Found %d site(s): %s", len(sites), strings.Join(sites, ",")) From 910304e7f6df8f109db009d07b91972c9ac2ca48 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 15 Jun 2019 20:17:04 -0700 Subject: [PATCH 052/194] typo --- core/unifi/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/types.go b/core/unifi/types.go index a2795ade..77be80e7 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -39,7 +39,7 @@ func (u *Unifi) dLogf(msg string, v ...interface{}) { } } -// dLogf logs an error message. +// eLogf logs an error message. func (u *Unifi) eLogf(msg string, v ...interface{}) { if u.ErrorLog != nil { u.ErrorLog("[ERROR] "+msg, v...) From 562e2444513ef28fbd2115297906b16cb23b043c Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Mon, 17 Jun 2019 12:46:19 -0700 Subject: [PATCH 053/194] Add wan2 metrics to InfluxDB. --- core/unifi/usg_influx.go | 134 +++++++++++++++++++++++---------------- core/unifi/usg_type.go | 48 +++++++------- 2 files changed, 104 insertions(+), 78 deletions(-) diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index bfd8ecc9..f53da9a5 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -41,6 +41,8 @@ func (u USG) Points() ([]*influx.Point, error) { "version_incompatible": u.VersionIncompatible.Txt, "usg_caps": strconv.FormatFloat(u.UsgCaps, 'f', 6, 64), "speedtest-status-saved": u.SpeedtestStatusSaved.Txt, + "wan1_up": u.Wan2.Up.Txt, + "wan2_up": u.Wan2.Up.Txt, } fields := map[string]interface{}{ "ip": u.IP, @@ -71,60 +73,84 @@ func (u USG) Points() ([]*influx.Point, error) { "speedtest-status_upload": u.SpeedtestStatus.StatusUpload, "speedtest-status_xput_download": u.SpeedtestStatus.XputDownload, "speedtest-status_xput_upload": u.SpeedtestStatus.XputUpload, - // have two WANs? mmmm, go ahead and add it. ;) - "config_network_wan_type": u.ConfigNetworkWan.Type, - "wan1_bytes-r": u.Wan1.BytesR, - "wan1_enable": u.Wan1.Enable.Val, - "wan1_full_duplex": u.Wan1.FullDuplex.Val, - "wan1_purpose": "uplink", // because it should have a purpose. - "wan1_gateway": u.Wan1.Gateway, - "wan1_ifname": u.Wan1.Ifname, - "wan1_ip": u.Wan1.IP, - "wan1_mac": u.Wan1.Mac, - "wan1_max_speed": u.Wan1.MaxSpeed, - "wan1_name": u.Wan1.Name, - "wan1_netmask": u.Wan1.Netmask, - "wan1_rx_bytes": u.Wan1.RxBytes.Val, - "wan1_rx_bytes-r": u.Wan1.RxBytesR, - "wan1_rx_dropped": u.Wan1.RxDropped, - "wan1_rx_errors": u.Wan1.RxErrors, - "wan1_rx_multicast": u.Wan1.RxMulticast, - "wan1_rx_packets": u.Wan1.RxPackets, - "wan1_type": u.Wan1.Type, - "wan1_speed": u.Wan1.Speed, - "wan1_up": u.Wan1.Up.Val, - "wan1_tx_bytes": u.Wan1.TxBytes.Val, - "wan1_tx_bytes-r": u.Wan1.TxBytesR, - "wan1_tx_dropped": u.Wan1.TxDropped, - "wan1_tx_errors": u.Wan1.TxErrors, - "wan1_tx_packets": u.Wan1.TxPackets, - "loadavg_1": u.SysStats.Loadavg1, - "loadavg_5": u.SysStats.Loadavg5, - "loadavg_15": u.SysStats.Loadavg15, - "mem_used": u.SysStats.MemUsed, - "mem_buffer": u.SysStats.MemBuffer, - "mem_total": u.SysStats.MemTotal, - "cpu": u.SystemStats.CPU, - "mem": u.SystemStats.Mem, - "system_uptime": u.SystemStats.Uptime, - "stat_duration": u.Stat.Duration, - "stat_datetime": u.Stat.Datetime, - "gw": u.Stat.Gw, - "false": "false", // to fill holes in graphs. - "lan-rx_bytes": u.Stat.LanRxBytes, - "lan-rx_packets": u.Stat.LanRxPackets, - "lan-tx_bytes": u.Stat.LanTxBytes, - "lan-tx_packets": u.Stat.LanTxPackets, - "wan-rx_bytes": u.Stat.WanRxBytes, - "wan-rx_dropped": u.Stat.WanRxDropped, - "wan-rx_packets": u.Stat.WanRxPackets, - "wan-tx_bytes": u.Stat.WanTxBytes, - "wan-tx_packets": u.Stat.WanTxPackets, - "uplink_name": u.Uplink.Name, - "uplink_latency": u.Uplink.Latency, - "uplink_speed": u.Uplink.Speed, - "uplink_num_ports": u.Uplink.NumPort, - "uplink_max_speed": u.Uplink.MaxSpeed, + "config_network_wan_type": u.ConfigNetworkWan.Type, + "wan1_bytes-r": u.Wan1.BytesR.Val, + "wan1_enable": u.Wan1.Enable.Val, + "wan1_full_duplex": u.Wan1.FullDuplex.Val, + "wan1_purpose": "uplink", // because it should have a purpose. + "wan1_gateway": u.Wan1.Gateway, + "wan1_ifname": u.Wan1.Ifname, + "wan1_ip": u.Wan1.IP, + "wan1_mac": u.Wan1.Mac, + "wan1_max_speed": u.Wan1.MaxSpeed.Val, + "wan1_name": u.Wan1.Name, + "wan1_netmask": u.Wan1.Netmask, + "wan1_rx_bytes": u.Wan1.RxBytes.Val, + "wan1_rx_bytes-r": u.Wan1.RxBytesR.Val, + "wan1_rx_dropped": u.Wan1.RxDropped.Val, + "wan1_rx_errors": u.Wan1.RxErrors.Val, + "wan1_rx_multicast": u.Wan1.RxMulticast.Val, + "wan1_rx_packets": u.Wan1.RxPackets.Val, + "wan1_type": u.Wan1.Type, + "wan1_speed": u.Wan1.Speed.Val, + "wan1_up": u.Wan1.Up.Val, + "wan1_tx_bytes": u.Wan1.TxBytes.Val, + "wan1_tx_bytes-r": u.Wan1.TxBytesR.Val, + "wan1_tx_dropped": u.Wan1.TxDropped.Val, + "wan1_tx_errors": u.Wan1.TxErrors.Val, + "wan1_tx_packets": u.Wan1.TxPackets.Val, + "wan2_bytes-r": u.Wan2.BytesR.Val, + "wan2_enable": u.Wan2.Enable.Val, + "wan2_full_duplex": u.Wan2.FullDuplex.Val, + "wan2_purpose": "uplink", // because it should have a purpose. + "wan2_gateway": u.Wan2.Gateway, + "wan2_ifname": u.Wan2.Ifname, + "wan2_ip": u.Wan2.IP, + "wan2_mac": u.Wan2.Mac, + "wan2_max_speed": u.Wan2.MaxSpeed.Val, + "wan2_name": u.Wan2.Name, + "wan2_netmask": u.Wan2.Netmask, + "wan2_rx_bytes": u.Wan2.RxBytes.Val, + "wan2_rx_bytes-r": u.Wan2.RxBytesR.Val, + "wan2_rx_dropped": u.Wan2.RxDropped.Val, + "wan2_rx_errors": u.Wan2.RxErrors.Val, + "wan2_rx_multicast": u.Wan2.RxMulticast.Val, + "wan2_rx_packets": u.Wan2.RxPackets.Val, + "wan2_type": u.Wan2.Type, + "wan2_speed": u.Wan2.Speed.Val, + "wan2_up": u.Wan2.Up.Val, + "wan2_tx_bytes": u.Wan2.TxBytes.Val, + "wan2_tx_bytes-r": u.Wan2.TxBytesR.Val, + "wan2_tx_dropped": u.Wan2.TxDropped.Val, + "wan2_tx_errors": u.Wan2.TxErrors.Val, + "wan2_tx_packets": u.Wan2.TxPackets.Val, + "loadavg_1": u.SysStats.Loadavg1, + "loadavg_5": u.SysStats.Loadavg5, + "loadavg_15": u.SysStats.Loadavg15, + "mem_used": u.SysStats.MemUsed, + "mem_buffer": u.SysStats.MemBuffer, + "mem_total": u.SysStats.MemTotal, + "cpu": u.SystemStats.CPU, + "mem": u.SystemStats.Mem, + "system_uptime": u.SystemStats.Uptime, + "stat_duration": u.Stat.Duration, + "stat_datetime": u.Stat.Datetime, + "gw": u.Stat.Gw, + "false": "false", // to fill holes in graphs. + "lan-rx_bytes": u.Stat.LanRxBytes, + "lan-rx_packets": u.Stat.LanRxPackets, + "lan-tx_bytes": u.Stat.LanTxBytes, + "lan-tx_packets": u.Stat.LanTxPackets, + "wan-rx_bytes": u.Stat.WanRxBytes, + "wan-rx_dropped": u.Stat.WanRxDropped, + "wan-rx_packets": u.Stat.WanRxPackets, + "wan-tx_bytes": u.Stat.WanTxBytes, + "wan-tx_packets": u.Stat.WanTxPackets, + "uplink_name": u.Uplink.Name, + "uplink_latency": u.Uplink.Latency, + "uplink_speed": u.Uplink.Speed, + "uplink_num_ports": u.Uplink.NumPort, + "uplink_max_speed": u.Uplink.MaxSpeed, } pt, err := influx.NewPoint("usg", tags, fields, time.Now()) if err != nil { diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index 2f95a552..2c4d769e 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -206,7 +206,7 @@ type USG struct { Version string `json:"version"` VersionIncompatible FlexBool `json:"version_incompatible"` Wan1 struct { - BytesR float64 `json:"bytes-r"` + BytesR FlexInt `json:"bytes-r"` DNS []string `json:"dns"` Enable FlexBool `json:"enable"` FullDuplex FlexBool `json:"full_duplex"` @@ -214,26 +214,26 @@ type USG struct { Ifname string `json:"ifname"` IP string `json:"ip"` Mac string `json:"mac"` - MaxSpeed float64 `json:"max_speed"` + MaxSpeed FlexInt `json:"max_speed"` Name string `json:"name"` Netmask string `json:"netmask"` RxBytes FlexInt `json:"rx_bytes"` - RxBytesR float64 `json:"rx_bytes-r"` - RxDropped float64 `json:"rx_dropped"` - RxErrors float64 `json:"rx_errors"` - RxMulticast float64 `json:"rx_multicast"` - RxPackets float64 `json:"rx_packets"` - Speed float64 `json:"speed"` + RxBytesR FlexInt `json:"rx_bytes-r"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxMulticast FlexInt `json:"rx_multicast"` + RxPackets FlexInt `json:"rx_packets"` + Speed FlexInt `json:"speed"` TxBytes FlexInt `json:"tx_bytes"` - TxBytesR float64 `json:"tx_bytes-r"` - TxDropped float64 `json:"tx_dropped"` - TxErrors float64 `json:"tx_errors"` - TxPackets float64 `json:"tx_packets"` + TxBytesR FlexInt `json:"tx_bytes-r"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxPackets FlexInt `json:"tx_packets"` Type string `json:"type"` Up FlexBool `json:"up"` } `json:"wan1"` Wan2 struct { - BytesR float64 `json:"bytes-r"` + BytesR FlexInt `json:"bytes-r"` DNS []string `json:"dns"` Enable FlexBool `json:"enable"` FullDuplex FlexBool `json:"full_duplex"` @@ -241,21 +241,21 @@ type USG struct { Ifname string `json:"ifname"` IP string `json:"ip"` Mac string `json:"mac"` - MaxSpeed float64 `json:"max_speed"` + MaxSpeed FlexInt `json:"max_speed"` Name string `json:"name"` Netmask string `json:"netmask"` RxBytes FlexInt `json:"rx_bytes"` - RxBytesR float64 `json:"rx_bytes-r"` - RxDropped float64 `json:"rx_dropped"` - RxErrors float64 `json:"rx_errors"` - RxMulticast float64 `json:"rx_multicast"` - RxPackets float64 `json:"rx_packets"` - Speed float64 `json:"speed"` + RxBytesR FlexInt `json:"rx_bytes-r"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxMulticast FlexInt `json:"rx_multicast"` + RxPackets FlexInt `json:"rx_packets"` + Speed FlexInt `json:"speed"` TxBytes FlexInt `json:"tx_bytes"` - TxBytesR float64 `json:"tx_bytes-r"` - TxDropped float64 `json:"tx_dropped"` - TxErrors float64 `json:"tx_errors"` - TxPackets float64 `json:"tx_packets"` + TxBytesR FlexInt `json:"tx_bytes-r"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxPackets FlexInt `json:"tx_packets"` Type string `json:"type"` Up FlexBool `json:"up"` } `json:"wan2"` From bfda3820a46ff487ca53d0f4e593aa1a7483e167 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Tue, 18 Jun 2019 00:33:08 -0700 Subject: [PATCH 054/194] bug squash --- core/unifi/uap_influx.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/uap_influx.go b/core/unifi/uap_influx.go index e0945ed1..06657ef7 100644 --- a/core/unifi/uap_influx.go +++ b/core/unifi/uap_influx.go @@ -34,7 +34,6 @@ func (u UAP) Points() ([]*influx.Point, error) { "device_id": u.DeviceID, "discovered_via": u.DiscoveredVia, "fw_caps": strconv.Itoa(u.FwCaps), - "guest-num_sta": strconv.Itoa(u.GuestNumSta), "guest_token": u.GuestToken, "has_eth1": u.HasEth1.Txt, "has_speaker": u.HasSpeaker.Txt, @@ -72,6 +71,7 @@ func (u UAP) Points() ([]*influx.Point, error) { "state": u.State, "upgradable": u.Upgradable.Val, "user-num_sta": u.UserNumSta, + "guest-num_sta": u.GuestNumSta, "version": u.Version, "loadavg_1": u.SysStats.Loadavg1, "loadavg_5": u.SysStats.Loadavg5, From d2b84ca8366c8c2337a83c2224d4e082dfeddf02 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Tue, 18 Jun 2019 01:11:00 -0700 Subject: [PATCH 055/194] oops --- core/unifi/usg_influx.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index f53da9a5..6bd273d0 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -41,7 +41,7 @@ func (u USG) Points() ([]*influx.Point, error) { "version_incompatible": u.VersionIncompatible.Txt, "usg_caps": strconv.FormatFloat(u.UsgCaps, 'f', 6, 64), "speedtest-status-saved": u.SpeedtestStatusSaved.Txt, - "wan1_up": u.Wan2.Up.Txt, + "wan1_up": u.Wan1.Up.Txt, "wan2_up": u.Wan2.Up.Txt, } fields := map[string]interface{}{ From 70783bb1b0ca6376ce49cdbd4f462f74ebe16ee2 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Tue, 18 Jun 2019 19:47:05 -0700 Subject: [PATCH 056/194] Add client DPI stats --- core/unifi/clients_influx.go | 6 ++++++ core/unifi/clients_type.go | 12 ++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/core/unifi/clients_influx.go b/core/unifi/clients_influx.go index e59bbcf7..da58ea50 100644 --- a/core/unifi/clients_influx.go +++ b/core/unifi/clients_influx.go @@ -98,6 +98,12 @@ func (c Client) Points() ([]*influx.Point, error) { "wired-tx_bytes": c.WiredTxBytes, "wired-tx_bytes-r": c.WiredTxBytesR, "wired-tx_packets": c.WiredTxPackets, + "dpi_app": c.DpiStats.App.Val, + "dpi_cat": c.DpiStats.Cat.Val, + "dpi_rx_bytes": c.DpiStats.RxBytes.Val, + "dpi_rx_packets": c.DpiStats.RxPackets.Val, + "dpi_tx_bytes": c.DpiStats.TxBytes.Val, + "dpi_tx_packets": c.DpiStats.TxPackets.Val, } pt, err := influx.NewPoint("clients", tags, fields, time.Now()) if err != nil { diff --git a/core/unifi/clients_type.go b/core/unifi/clients_type.go index 662a4ca6..436b6018 100644 --- a/core/unifi/clients_type.go +++ b/core/unifi/clients_type.go @@ -26,12 +26,12 @@ type Client struct { DevFamily int `json:"dev_family"` DevID int `json:"dev_id"` DpiStats struct { - App int64 - Cat int64 - RxBytes int64 - RxPackets int64 - TxBytes int64 - TxPackets int64 + App FlexInt + Cat FlexInt + RxBytes FlexInt + RxPackets FlexInt + TxBytes FlexInt + TxPackets FlexInt } `json:"dpi_stats"` DpiStatsLastUpdated int64 `json:"dpi_stats_last_updated"` Essid string `json:"essid"` From 9ca669fe59ef77e7caae433deebcf90b3fb93270 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Tue, 18 Jun 2019 23:38:18 -0700 Subject: [PATCH 057/194] Return error on error reply. --- core/unifi/unifi.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 39a08282..e41348ff 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -157,6 +157,9 @@ func (u *Unifi) GetData(methodPath string, v interface{}) error { } else if err = json.Unmarshal(body, v); err != nil { return errors.Wrapf(err, "json.Unmarshal(%s)", methodPath) } + if resp.StatusCode != http.StatusOK { + return errors.Errorf("invalid status code from server %v %v", resp.StatusCode, resp.Status) + } return nil } From a5724ab60100c26b2fcb0a066b6fc7fadaf6ae8f Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 19 Jun 2019 00:31:40 -0700 Subject: [PATCH 058/194] make another method --- core/unifi/unifi.go | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index e41348ff..ec76cf7a 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -141,25 +141,11 @@ func (u *Unifi) GetSites() (Sites, error) { // GetData makes a unifi request and unmarshal the response into a provided pointer. func (u *Unifi) GetData(methodPath string, v interface{}) error { - req, err := u.UniReq(methodPath, "") - if err != nil { - return errors.Wrapf(err, "c.UniReq(%s)", methodPath) - } - resp, err := u.Do(req) - if err != nil { - return errors.Wrapf(err, "c.Do(%s)", methodPath) - } - defer func() { - _ = resp.Body.Close() - }() - if body, err := ioutil.ReadAll(resp.Body); err != nil { + if body, err := u.GetJSON(methodPath); err != nil { return errors.Wrapf(err, "ioutil.ReadAll(%s)", methodPath) } else if err = json.Unmarshal(body, v); err != nil { return errors.Wrapf(err, "json.Unmarshal(%s)", methodPath) } - if resp.StatusCode != http.StatusOK { - return errors.Errorf("invalid status code from server %v %v", resp.StatusCode, resp.Status) - } return nil } @@ -178,3 +164,26 @@ func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err er } return } + +// GetJSON returns the raw JSON from a path. This is useful for debugging. +func (u *Unifi) GetJSON(apiPath string) ([]byte, error) { + req, err := u.UniReq(apiPath, "") + if err != nil { + return []byte{}, errors.Wrapf(err, "c.UniReq(%s)", apiPath) + } + resp, err := u.Do(req) + if err != nil { + return []byte{}, errors.Wrapf(err, "c.Do(%s)", apiPath) + } + defer func() { + _ = resp.Body.Close() + }() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return body, err + } + if resp.StatusCode != http.StatusOK { + err = errors.Errorf("invalid status code from server %v %v", resp.StatusCode, resp.Status) + } + return body, err +} From 4e56ad4d2b276e2ae8a6d1e1c13e133d694a9c92 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 19 Jun 2019 00:32:57 -0700 Subject: [PATCH 059/194] fix errors --- core/unifi/unifi.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index ec76cf7a..2324256f 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -142,7 +142,7 @@ func (u *Unifi) GetSites() (Sites, error) { // GetData makes a unifi request and unmarshal the response into a provided pointer. func (u *Unifi) GetData(methodPath string, v interface{}) error { if body, err := u.GetJSON(methodPath); err != nil { - return errors.Wrapf(err, "ioutil.ReadAll(%s)", methodPath) + return err } else if err = json.Unmarshal(body, v); err != nil { return errors.Wrapf(err, "json.Unmarshal(%s)", methodPath) } @@ -180,7 +180,7 @@ func (u *Unifi) GetJSON(apiPath string) ([]byte, error) { }() body, err := ioutil.ReadAll(resp.Body) if err != nil { - return body, err + return body, errors.Wrapf(err, "ioutil.ReadAll(%s)", apiPath) } if resp.StatusCode != http.StatusOK { err = errors.Errorf("invalid status code from server %v %v", resp.StatusCode, resp.Status) From 638e16f2b05612b15970d18c6ab811a9aa0c31ff Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 19 Jun 2019 00:40:25 -0700 Subject: [PATCH 060/194] less is more --- core/unifi/unifi.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 2324256f..c8db87d7 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -141,12 +141,12 @@ func (u *Unifi) GetSites() (Sites, error) { // GetData makes a unifi request and unmarshal the response into a provided pointer. func (u *Unifi) GetData(methodPath string, v interface{}) error { - if body, err := u.GetJSON(methodPath); err != nil { + body, err := u.GetJSON(methodPath) + if err != nil { return err - } else if err = json.Unmarshal(body, v); err != nil { - return errors.Wrapf(err, "json.Unmarshal(%s)", methodPath) } - return nil + err = json.Unmarshal(body, v) + return errors.Wrapf(err, "json.Unmarshal(%s)", methodPath) } // UniReq is a small helper function that adds an Accept header. From 3a8fcda20ac04d458a17837eb6355ca78f8eb316 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 19 Jun 2019 00:55:19 -0700 Subject: [PATCH 061/194] more cleanup --- core/unifi/unifi.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index c8db87d7..3b408db7 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -39,7 +39,7 @@ func NewUnifi(user, pass, url string, verifySSL bool) (*Unifi, error) { // getController is a helper method to make testsing a bit easier. func (u *Unifi) getController(user, pass string) error { // magic login. - req, err := u.UniReq(LoginPath, `{"username": "`+user+`","password": "`+pass+`"}`) + req, err := u.UniReq(LoginPath, fmt.Sprintf(`{"username":"%s","password":"%s"}`, user, pass)) if err != nil { return errors.Wrap(err, "UniReq(LoginPath, json)") } @@ -52,8 +52,8 @@ func (u *Unifi) getController(user, pass string) error { _ = resp.Body.Close() }() if resp.StatusCode != http.StatusOK { - return errors.Errorf("authentication failed (user: %s): %s (status: %d/%s)", - user, u.baseURL+LoginPath, resp.StatusCode, resp.Status) + return errors.Errorf("authentication failed (user: %s): %s (status: %s)", + user, u.baseURL+LoginPath, resp.Status) } return nil } @@ -154,10 +154,11 @@ func (u *Unifi) GetData(methodPath string, v interface{}) error { // And if you're doing that... sumbut a pull request with your new struct. :) // This is a helper method that is exposed for convenience. func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err error) { - if params != "" { - req, err = http.NewRequest("POST", u.baseURL+apiPath, bytes.NewBufferString(params)) - } else { - req, err = http.NewRequest("GET", u.baseURL+apiPath, nil) + switch path := u.baseURL + apiPath; { + case params == "": + req, err = http.NewRequest("GET", path, nil) + default: + req, err = http.NewRequest("POST", path, bytes.NewBufferString(params)) } if err == nil { req.Header.Add("Accept", "application/json") @@ -183,7 +184,7 @@ func (u *Unifi) GetJSON(apiPath string) ([]byte, error) { return body, errors.Wrapf(err, "ioutil.ReadAll(%s)", apiPath) } if resp.StatusCode != http.StatusOK { - err = errors.Errorf("invalid status code from server %v %v", resp.StatusCode, resp.Status) + err = errors.Errorf("invalid status code from server %s", resp.Status) } return body, err } From a423a8aebe1a136b4acdf23d53909af286d70734 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 19 Jun 2019 01:26:21 -0700 Subject: [PATCH 062/194] Get rid of intermediate logger. --- core/unifi/{parsers.go => devices.go} | 14 +++++++------- core/unifi/types.go | 15 +++------------ core/unifi/unifi.go | 6 ++++-- 3 files changed, 14 insertions(+), 21 deletions(-) rename core/unifi/{parsers.go => devices.go} (75%) diff --git a/core/unifi/parsers.go b/core/unifi/devices.go similarity index 75% rename from core/unifi/parsers.go rename to core/unifi/devices.go index a2b97ce5..20a6a580 100644 --- a/core/unifi/parsers.go +++ b/core/unifi/devices.go @@ -13,7 +13,7 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { } else if t, ok := o["type"].(string); ok { assetType = t } - u.dLogf("Unmarshalling Device Type: %v, site %s ", assetType, siteName) + u.DebugLog("Unmarshalling Device Type: %v, site %s ", assetType, siteName) // Choose which type to unmarshal into based on the "type" json key. switch assetType { // Unmarshal again into the correct type.. case "uap": @@ -32,7 +32,7 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { devices.USWs = append(devices.USWs, usw) } default: - u.eLogf("unknown asset type - %v - skipping", assetType) + u.ErrorLog("unknown asset type - %v - skipping", assetType) } } return devices @@ -41,12 +41,12 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { // unmarshalDevice handles logging for the unmarshal operations in parseDevices(). func (u *Unifi) unmarshalDevice(dev string, data json.RawMessage, v interface{}) (err error) { if err = json.Unmarshal(data, v); err != nil { - u.eLogf("json.Unmarshal(%v): %v", dev, err) - u.eLogf("Enable Debug Logging to output the failed payload.") + u.ErrorLog("json.Unmarshal(%v): %v", dev, err) + u.ErrorLog("Enable Debug Logging to output the failed payload.") json, err := data.MarshalJSON() - u.dLogf("Failed Payload: %s (marshal err: %v)", json, err) - u.dLogf("The above payload can prove useful during torubleshooting when you open an Issue:") - u.dLogf("==- https://github.com/golift/unifi/issues/new -==") + u.DebugLog("Failed Payload: %s (marshal err: %v)", json, err) + u.DebugLog("The above payload can prove useful during torubleshooting when you open an Issue:") + u.DebugLog("==- https://github.com/golift/unifi/issues/new -==") } return err } diff --git a/core/unifi/types.go b/core/unifi/types.go index 77be80e7..a1782e83 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -32,18 +32,9 @@ const ( // that matches this interface to capture debug and error logs. type Logger func(msg string, fmt ...interface{}) -// dLogf logs a debug message. -func (u *Unifi) dLogf(msg string, v ...interface{}) { - if u.DebugLog != nil { - u.DebugLog("[DEBUG] "+msg, v...) - } -} - -// eLogf logs an error message. -func (u *Unifi) eLogf(msg string, v ...interface{}) { - if u.ErrorLog != nil { - u.ErrorLog("[ERROR] "+msg, v...) - } +// DiscardLogs is the default logger. +func DiscardLogs(msg string, v ...interface{}) { + // do nothing. } // Devices contains a list of all the unifi devices from a controller. diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 3b408db7..cac82978 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -32,6 +32,8 @@ func NewUnifi(user, pass, url string, verifySSL bool) (*Unifi, error) { Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !verifySSL}}, Jar: jar, }, + ErrorLog: DiscardLogs, + DebugLog: DiscardLogs, } return u, u.getController(user, pass) } @@ -74,7 +76,7 @@ func (u *Unifi) GetClients(sites []Site) (Clients, error) { var response struct { Data []Client `json:"data"` } - u.dLogf("Polling Controller, retreiving Unifi Clients, site %s (%s) ", site.Name, site.Desc) + u.DebugLog("Polling Controller, retreiving Unifi Clients, site %s (%s) ", site.Name, site.Desc) clientPath := fmt.Sprintf(ClientPath, site.Name) if err := u.GetData(clientPath, &response); err != nil { return nil, err @@ -135,7 +137,7 @@ func (u *Unifi) GetSites() (Sites, error) { response.Data[i].SiteName = response.Data[i].Desc + " (" + response.Data[i].Name + ")" sites = append(sites, response.Data[i].Name) } - u.dLogf("Found %d site(s): %s", len(sites), strings.Join(sites, ",")) + u.DebugLog("Found %d site(s): %s", len(sites), strings.Join(sites, ",")) return response.Data, nil } From 254b2e5e568da5a4ff9db148b9eaf0adfa8a6f18 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 19 Jun 2019 01:36:28 -0700 Subject: [PATCH 063/194] better error log default. --- core/unifi/types.go | 2 +- core/unifi/unifi.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/unifi/types.go b/core/unifi/types.go index a1782e83..9330318e 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -32,7 +32,7 @@ const ( // that matches this interface to capture debug and error logs. type Logger func(msg string, fmt ...interface{}) -// DiscardLogs is the default logger. +// DiscardLogs is the default debug logger. func DiscardLogs(msg string, v ...interface{}) { // do nothing. } diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index cac82978..ccf9e36b 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -12,6 +12,7 @@ import ( "fmt" "io" "io/ioutil" + "log" "net/http" "net/http/cookiejar" "strings" @@ -32,7 +33,7 @@ func NewUnifi(user, pass, url string, verifySSL bool) (*Unifi, error) { Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !verifySSL}}, Jar: jar, }, - ErrorLog: DiscardLogs, + ErrorLog: log.Printf, DebugLog: DiscardLogs, } return u, u.getController(user, pass) From b0eba73ffae5501e1df3ae14dfe27b54982e6ed5 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 19 Jun 2019 01:37:39 -0700 Subject: [PATCH 064/194] update comment --- core/unifi/types.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/unifi/types.go b/core/unifi/types.go index 9330318e..4c3920f0 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -47,7 +47,8 @@ type Devices struct { // Unifi is what you get in return for providing a password! Unifi represents // a controller that you can make authenticated requests to. Use this to make -// additional requests for devices, clients or other custom data. +// additional requests for devices, clients or other custom data. Do not set +// the loggers to nil. Set them to DiscardLogs if you want no logs. type Unifi struct { *http.Client baseURL string From 3c449ea1dc9999e29af3d770959b7ee13512682c Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 3 Jul 2019 22:47:00 -0700 Subject: [PATCH 065/194] Add placeholds for device names. --- core/unifi/clients_type.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/unifi/clients_type.go b/core/unifi/clients_type.go index 436b6018..e2566e03 100644 --- a/core/unifi/clients_type.go +++ b/core/unifi/clients_type.go @@ -16,6 +16,7 @@ type Client struct { UptimeByUGW int64 `json:"_uptime_by_ugw"` UptimeByUSW int64 `json:"_uptime_by_usw"` ApMac string `json:"ap_mac"` + ApName string `json:"-"` AssocTime int64 `json:"assoc_time"` Authorized FlexBool `json:"authorized"` Bssid string `json:"bssid"` @@ -39,6 +40,7 @@ type Client struct { FixedIP string `json:"fixed_ip"` Hostname string `json:"hostname"` GwMac string `json:"gw_mac"` + GwName string `json:"-"` IdleTime int64 `json:"idle_time"` IP string `json:"ip"` Is11R FlexBool `json:"is_11r"` @@ -72,6 +74,7 @@ type Client struct { SiteName string `json:"-"` SwDepth int `json:"sw_depth"` SwMac string `json:"sw_mac"` + SwName string `json:"-"` SwPort int `json:"sw_port"` TxBytes int64 `json:"tx_bytes"` TxBytesR int64 `json:"tx_bytes-r"` From 13161ed28e9b216229d47a4a7042d2486cf76cf3 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 3 Jul 2019 23:51:30 -0700 Subject: [PATCH 066/194] Forgot one step. --- core/unifi/clients_influx.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/unifi/clients_influx.go b/core/unifi/clients_influx.go index da58ea50..ce30c7dd 100644 --- a/core/unifi/clients_influx.go +++ b/core/unifi/clients_influx.go @@ -31,6 +31,9 @@ func (c Client) Points() ([]*influx.Point, error) { "ap_mac": c.ApMac, "gw_mac": c.GwMac, "sw_mac": c.SwMac, + "ap_name": c.ApName, + "gw_name": c.GwName, + "sw_name": c.SwName, "oui": c.Oui, "radio_name": c.RadioName, "radio": c.Radio, From 7cde4b0c261e094913e527e02a62d05bb8c1e9a0 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Thu, 4 Jul 2019 04:02:07 -0700 Subject: [PATCH 067/194] Re-do uap struct and points. --- core/unifi/uap_influx.go | 461 ++++++++++++------------- core/unifi/uap_type.go | 709 ++++++++++++++++++++++----------------- 2 files changed, 622 insertions(+), 548 deletions(-) diff --git a/core/unifi/uap_influx.go b/core/unifi/uap_influx.go index 06657ef7..b46af1f3 100644 --- a/core/unifi/uap_influx.go +++ b/core/unifi/uap_influx.go @@ -1,7 +1,6 @@ package unifi import ( - "strconv" "time" influx "github.com/influxdata/influxdb1-client/v2" @@ -10,258 +9,242 @@ import ( // 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! - */ tags := map[string]string{ - "id": u.ID, - "mac": u.Mac, - "device_type": u.Stat.O, - "device_oid": u.Stat.Oid, - "device_ap": u.Stat.Ap, - "site_id": u.SiteID, - "site_name": u.SiteName, - "name": u.Name, - "adopted": u.Adopted.Txt, - "bandsteering_mode": u.BandsteeringMode, - "board_rev": strconv.Itoa(u.BoardRev), - "cfgversion": u.Cfgversion, - "config_network_ip": u.ConfigNetwork.IP, - "config_network_type": u.ConfigNetwork.Type, - "connect_request_ip": u.ConnectRequestIP, - "connect_request_port": u.ConnectRequestPort, - "default": u.Default.Txt, - "device_id": u.DeviceID, - "discovered_via": u.DiscoveredVia, - "fw_caps": strconv.Itoa(u.FwCaps), - "guest_token": u.GuestToken, - "has_eth1": u.HasEth1.Txt, - "has_speaker": u.HasSpeaker.Txt, - "inform_ip": u.InformIP, - "isolated": u.Isolated.Txt, - "last_uplink_mac": u.LastUplink.UplinkMac, - "last_uplink_remote_port": strconv.Itoa(u.LastUplink.UplinkRemotePort), - "known_cfgversion": u.KnownCfgversion, - "led_override": u.LedOverride, - "locating": u.Locating.Txt, - "model": u.Model, - "outdoor_mode_override": u.OutdoorModeOverride, - "serial": u.Serial, - "type": u.Type, - "version_incompatible": u.VersionIncompatible.Txt, - "vwireEnabled": u.VwireEnabled.Txt, - "wifi_caps": strconv.Itoa(u.WifiCaps), + "id": u.ID, + "mac": u.Mac, + "device_type": u.Stat.O, + "device_oid": u.Stat.Oid, + "device_ap": u.Stat.Ap, + "site_id": u.SiteID, + "site_name": u.SiteName, + "name": u.Name, + "adopted": u.Adopted.Txt, + "cfgversion": u.Cfgversion, + "config_network_ip": u.ConfigNetwork.IP, + "config_network_type": u.ConfigNetwork.Type, + "connect_request_ip": u.ConnectRequestIP, + "device_id": u.DeviceID, + "has_eth1": u.HasEth1.Txt, + "inform_ip": u.InformIP, + "isolated": u.Isolated.Txt, + "known_cfgversion": u.KnownCfgversion, + "model": u.Model, + "outdoor_mode_override": u.OutdoorModeOverride, + "serial": u.Serial, + "type": u.Type, + "vwireEnabled": u.VwireEnabled.Txt, } fields := map[string]interface{}{ - "ip": u.IP, - "bytes": u.Bytes, - "bytes_d": u.BytesD, - "bytes_r": u.BytesR, - "last_seen": u.LastSeen, - "rx_bytes": u.RxBytes, - "rx_bytes-d": u.RxBytesD, - "tx_bytes": u.TxBytes, - "tx_bytes-d": u.TxBytesD, - "uptime": u.Uptime.Val, - "considered_lost_at": u.ConsideredLostAt, - "next_heartbeat_at": u.NextHeartbeatAt, - "scanning": u.Scanning.Val, - "spectrum_scanning": u.SpectrumScanning.Val, - "roll_upgrade": u.Rollupgrade.Val, - "state": u.State, - "upgradable": u.Upgradable.Val, - "user-num_sta": u.UserNumSta, - "guest-num_sta": u.GuestNumSta, - "version": u.Version, - "loadavg_1": u.SysStats.Loadavg1, - "loadavg_5": u.SysStats.Loadavg5, - "loadavg_15": u.SysStats.Loadavg15, - "mem_buffer": u.SysStats.MemBuffer, - "mem_total": u.SysStats.MemTotal, - "mem_used": u.SysStats.MemUsed, - "cpu": u.SystemStats.CPU, - "mem": u.SystemStats.Mem, - "system_uptime": u.SystemStats.Uptime, - "stat_bytes": u.Stat.Bytes, - "stat_duration": u.Stat.Duration, - "stat_guest-rx_bytes": u.Stat.RxBytes, - "stat_guest-rx_crypts": u.Stat.RxCrypts, - "stat_guest-rx_dropped": u.Stat.RxDropped, - "stat_guest-rx_errors": u.Stat.RxErrors, - "stat_guest-rx_frags": u.Stat.RxFrags, - "stat_guest-rx_packets": u.Stat.RxPackets, - "stat_guest-tx_bytes": u.Stat.TxBytes, - "stat_guest-tx_dropped": u.Stat.TxDropped, - "stat_guest-tx_errors": u.Stat.TxErrors, - "stat_guest-tx_packets": u.Stat.TxPackets, - "stat_guest-tx_retries": u.Stat.TxRetries, - "stat_port_1-rx_broadcast": u.Stat.Port1RxBroadcast, - "stat_port_1-rx_bytes": u.Stat.Port1RxBytes, - "stat_port_1-rx_multicast": u.Stat.Port1RxMulticast, - "stat_port_1-rx_packets": u.Stat.Port1RxPackets, - "stat_port_1-tx_broadcast": u.Stat.Port1TxBroadcast, - "stat_port_1-tx_bytes": u.Stat.Port1TxBytes, - "stat_port_1-tx_multicast": u.Stat.Port1TxMulticast, - "stat_port_1-tx_packets": u.Stat.Port1TxPackets, - "stat_rx_bytes": u.Stat.RxBytes, - "stat_rx_crypts": u.Stat.RxCrypts, - "stat_rx_dropped": u.Stat.RxDropped, - "stat_rx_errors": u.Stat.RxErrors, - "stat_rx_frags": u.Stat.RxFrags, - "stat_rx_packets": u.Stat.TxPackets, - "stat_tx_bytes": u.Stat.TxBytes, - "stat_tx_dropped": u.Stat.TxDropped, - "stat_tx_errors": u.Stat.TxErrors, - "stat_tx_packets": u.Stat.TxPackets, - "stat_tx_retries": u.Stat.TxRetries, - "stat_user-rx_bytes": u.Stat.UserRxBytes, - "stat_user-rx_crypts": u.Stat.UserRxCrypts, - "stat_user-rx_dropped": u.Stat.UserRxDropped, - "stat_user-rx_errors": u.Stat.UserRxErrors, - "stat_user-rx_frags": u.Stat.UserRxFrags, - "stat_user-rx_packets": u.Stat.UserRxPackets, - "stat_user-tx_bytes": u.Stat.UserTxBytes, - "stat_user-tx_dropped": u.Stat.UserTxDropped, - "stat_user-tx_errors": u.Stat.UserTxErrors, - "stat_user-tx_packets": u.Stat.UserTxPackets, - "stat_user-tx_retries": u.Stat.UserTxRetries, - "stat_user-wifi0-rx_bytes": u.Stat.UserWifi0RxBytes, - "stat_user-wifi0-rx_crypts": u.Stat.UserWifi0RxCrypts, - "stat_user-wifi0-rx_dropped": u.Stat.UserWifi0RxDropped, - "stat_user-wifi0-rx_errors": u.Stat.UserWifi0RxErrors, - "stat_user-wifi0-rx_frags": u.Stat.UserWifi0RxFrags, - "stat_user-wifi0-rx_packets": u.Stat.UserWifi0RxPackets, - "stat_user-wifi0-tx_bytes": u.Stat.UserWifi0TxBytes, - "stat_user-wifi0-tx_dropped": u.Stat.UserWifi0TxDropped, - "stat_user-wifi0-tx_errors": u.Stat.UserWifi0TxErrors, - "stat_user-wifi0-tx_packets": u.Stat.UserWifi0TxPackets, - "stat_user-wifi0-tx_retries": u.Stat.UserWifi0TxRetries, - "stat_user-wifi1-rx_bytes": u.Stat.UserWifi1RxBytes, - "stat_user-wifi1-rx_crypts": u.Stat.UserWifi1RxCrypts, - "stat_user-wifi1-rx_dropped": u.Stat.UserWifi1RxDropped, - "stat_user-wifi1-rx_errors": u.Stat.UserWifi1RxErrors, - "stat_user-wifi1-rx_frags": u.Stat.UserWifi1RxFrags, - "stat_user-wifi1-rx_packets": u.Stat.UserWifi1RxPackets, - "stat_user-wifi1-tx_bytes": u.Stat.UserWifi1TxBytes, - "stat_user-wifi1-tx_dropped": u.Stat.UserWifi1TxDropped, - "stat_user-wifi1-tx_errors": u.Stat.UserWifi1TxErrors, - "stat_user-wifi1-tx_packets": u.Stat.UserWifi1TxPackets, - "stat_user-wifi1-tx_retries": u.Stat.UserWifi1TxRetries, - "stat_wifi0-rx_bytes": u.Stat.Wifi0RxBytes, - "stat_wifi0-rx_crypts": u.Stat.Wifi0RxCrypts, - "stat_wifi0-rx_dropped": u.Stat.Wifi0RxDropped, - "stat_wifi0-rx_errors": u.Stat.Wifi0RxErrors, - "stat_wifi0-rx_frags": u.Stat.Wifi0RxFrags, - "stat_wifi0-rx_packets": u.Stat.Wifi0RxPackets, - "stat_wifi0-tx_bytes": u.Stat.Wifi0TxBytes, - "stat_wifi0-tx_dropped": u.Stat.Wifi0TxDropped, - "stat_wifi0-tx_errors": u.Stat.Wifi0TxErrors, - "stat_wifi0-tx_packets": u.Stat.Wifi0TxPackets, - "stat_wifi0-tx_retries": u.Stat.Wifi0TxRetries, - "stat_wifi1-rx_bytes": u.Stat.Wifi1RxBytes, - "stat_wifi1-rx_crypts": u.Stat.Wifi1RxCrypts, - "stat_wifi1-rx_dropped": u.Stat.Wifi1RxDropped, - "stat_wifi1-rx_errors": u.Stat.Wifi1RxErrors, - "stat_wifi1-rx_frags": u.Stat.Wifi1RxFrags, - "stat_wifi1-rx_packets": u.Stat.Wifi1RxPackets, - "stat_wifi1-tx_bytes": u.Stat.Wifi1TxBytes, - "stat_wifi1-tx_dropped": u.Stat.Wifi1TxDropped, - "stat_wifi1-tx_errors": u.Stat.Wifi1TxErrors, - "stat_wifi1-tx_packets": u.Stat.Wifi1TxPackets, - "stat_wifi1-tx_retries": u.Stat.Wifi1TxRetries, + "ip": u.IP, + "bytes": u.Bytes.Val, + "bytes_d": u.BytesD.Val, + "bytes_r": u.BytesR.Val, + "last_seen": u.LastSeen.Val, + "rx_bytes": u.RxBytes.Val, + "rx_bytes-d": u.RxBytesD.Val, + "tx_bytes": u.TxBytes.Val, + "tx_bytes-d": u.TxBytesD.Val, + "uptime": u.Uptime.Val, + "scanning": u.Scanning.Val, + "spectrum_scanning": u.SpectrumScanning.Val, + "roll_upgrade": u.Rollupgrade.Val, + "state": u.State, + "upgradable": u.Upgradable.Val, + "user-num_sta": u.UserNumSta, + "guest-num_sta": u.GuestNumSta, + "version": u.Version, + "loadavg_1": u.SysStats.Loadavg1, + "loadavg_5": u.SysStats.Loadavg5, + "loadavg_15": u.SysStats.Loadavg15, + "mem_buffer": u.SysStats.MemBuffer.Val, + "mem_total": u.SysStats.MemTotal.Val, + "mem_used": u.SysStats.MemUsed.Val, + "cpu": u.SystemStats.CPU, + "mem": u.SystemStats.Mem, + "system_uptime": u.SystemStats.Uptime, + "stat_bytes": u.Stat.Bytes.Val, + "stat_duration": u.Stat.Duration.Val, + "stat_guest-rx_bytes": u.Stat.RxBytes.Val, + "stat_guest-rx_crypts": u.Stat.RxCrypts.Val, + "stat_guest-rx_dropped": u.Stat.RxDropped.Val, + "stat_guest-rx_errors": u.Stat.RxErrors.Val, + "stat_guest-rx_frags": u.Stat.RxFrags.Val, + "stat_guest-rx_packets": u.Stat.RxPackets.Val, + "stat_guest-tx_bytes": u.Stat.TxBytes.Val, + "stat_guest-tx_dropped": u.Stat.TxDropped.Val, + "stat_guest-tx_errors": u.Stat.TxErrors.Val, + "stat_guest-tx_packets": u.Stat.TxPackets.Val, + "stat_guest-tx_retries": u.Stat.TxRetries.Val, + /* snip */ + "stat_rx_bytes": u.Stat.RxBytes.Val, + "stat_rx_crypts": u.Stat.RxCrypts.Val, + "stat_rx_dropped": u.Stat.RxDropped.Val, + "stat_rx_errors": u.Stat.RxErrors.Val, + "stat_rx_frags": u.Stat.RxFrags.Val, + "stat_rx_packets": u.Stat.TxPackets.Val, + "stat_tx_bytes": u.Stat.TxBytes.Val, + "stat_tx_dropped": u.Stat.TxDropped.Val, + "stat_tx_errors": u.Stat.TxErrors.Val, + "stat_tx_packets": u.Stat.TxPackets.Val, + "stat_tx_retries": u.Stat.TxRetries.Val, + "stat_user-rx_bytes": u.Stat.UserRxBytes.Val, + "stat_user-rx_crypts": u.Stat.UserRxCrypts.Val, + "stat_user-rx_dropped": u.Stat.UserRxDropped.Val, + "stat_user-rx_errors": u.Stat.UserRxErrors.Val, + "stat_user-rx_frags": u.Stat.UserRxFrags.Val, + "stat_user-rx_packets": u.Stat.UserRxPackets.Val, + "stat_user-tx_bytes": u.Stat.UserTxBytes.Val, + "stat_user-tx_dropped": u.Stat.UserTxDropped.Val, + "stat_user-tx_errors": u.Stat.UserTxErrors.Val, + "stat_user-tx_packets": u.Stat.UserTxPackets.Val, + "stat_user-tx_retries": u.Stat.UserTxRetries.Val, + "stat_user-wifi0-rx_bytes": u.Stat.UserWifi0RxBytes.Val, + "stat_user-wifi0-rx_crypts": u.Stat.UserWifi0RxCrypts.Val, + "stat_user-wifi0-rx_dropped": u.Stat.UserWifi0RxDropped.Val, + "stat_user-wifi0-rx_errors": u.Stat.UserWifi0RxErrors.Val, + "stat_user-wifi0-rx_frags": u.Stat.UserWifi0RxFrags.Val, + "stat_user-wifi0-rx_packets": u.Stat.UserWifi0RxPackets.Val, + "stat_user-wifi0-tx_bytes": u.Stat.UserWifi0TxBytes.Val, + "stat_user-wifi0-tx_dropped": u.Stat.UserWifi0TxDropped.Val, + "stat_user-wifi0-tx_errors": u.Stat.UserWifi0TxErrors.Val, + "stat_user-wifi0-tx_packets": u.Stat.UserWifi0TxPackets.Val, + "stat_user-wifi0-tx_retries": u.Stat.UserWifi0TxRetries.Val, + "stat_user-wifi1-rx_bytes": u.Stat.UserWifi1RxBytes.Val, + "stat_user-wifi1-rx_crypts": u.Stat.UserWifi1RxCrypts.Val, + "stat_user-wifi1-rx_dropped": u.Stat.UserWifi1RxDropped.Val, + "stat_user-wifi1-rx_errors": u.Stat.UserWifi1RxErrors.Val, + "stat_user-wifi1-rx_frags": u.Stat.UserWifi1RxFrags.Val, + "stat_user-wifi1-rx_packets": u.Stat.UserWifi1RxPackets.Val, + "stat_user-wifi1-tx_bytes": u.Stat.UserWifi1TxBytes.Val, + "stat_user-wifi1-tx_dropped": u.Stat.UserWifi1TxDropped.Val, + "stat_user-wifi1-tx_errors": u.Stat.UserWifi1TxErrors.Val, + "stat_user-wifi1-tx_packets": u.Stat.UserWifi1TxPackets.Val, + "stat_user-wifi1-tx_retries": u.Stat.UserWifi1TxRetries.Val, + "stat_wifi0-rx_bytes": u.Stat.Wifi0RxBytes.Val, + "stat_wifi0-rx_crypts": u.Stat.Wifi0RxCrypts.Val, + "stat_wifi0-rx_dropped": u.Stat.Wifi0RxDropped.Val, + "stat_wifi0-rx_errors": u.Stat.Wifi0RxErrors.Val, + "stat_wifi0-rx_frags": u.Stat.Wifi0RxFrags.Val, + "stat_wifi0-rx_packets": u.Stat.Wifi0RxPackets.Val, + "stat_wifi0-tx_bytes": u.Stat.Wifi0TxBytes.Val, + "stat_wifi0-tx_dropped": u.Stat.Wifi0TxDropped.Val, + "stat_wifi0-tx_errors": u.Stat.Wifi0TxErrors.Val, + "stat_wifi0-tx_packets": u.Stat.Wifi0TxPackets.Val, + "stat_wifi0-tx_retries": u.Stat.Wifi0TxRetries.Val, + "stat_wifi1-rx_bytes": u.Stat.Wifi1RxBytes.Val, + "stat_wifi1-rx_crypts": u.Stat.Wifi1RxCrypts.Val, + "stat_wifi1-rx_dropped": u.Stat.Wifi1RxDropped.Val, + "stat_wifi1-rx_errors": u.Stat.Wifi1RxErrors.Val, + "stat_wifi1-rx_frags": u.Stat.Wifi1RxFrags.Val, + "stat_wifi1-rx_packets": u.Stat.Wifi1RxPackets.Val, + "stat_wifi1-tx_bytes": u.Stat.Wifi1TxBytes.Val, + "stat_wifi1-tx_dropped": u.Stat.Wifi1TxDropped.Val, + "stat_wifi1-tx_errors": u.Stat.Wifi1TxErrors.Val, + "stat_wifi1-tx_packets": u.Stat.Wifi1TxPackets.Val, + "stat_wifi1-tx_retries": u.Stat.Wifi1TxRetries.Val, } pt, err := influx.NewPoint("uap", tags, fields, time.Now()) if err != nil { return nil, err } points := []*influx.Point{pt} - for _, p := range u.RadioTable { - tags := map[string]string{ - "device_name": u.Name, - "device_id": u.ID, - "device_mac": u.Mac, - "name": p.Name, - "wlangroup_id": p.WlangroupID, - "channel": p.Channel.Txt, - "radio": p.Radio, - } - fields := map[string]interface{}{ - "builtin_ant_gain": p.BuiltinAntGain, - "current_antenna_gain": p.CurrentAntennaGain, - "has_dfs": p.HasDfs.Val, - "has_fccdfs": p.HasFccdfs.Val, - "ht": p.Ht, - "is_11ac": p.Is11Ac.Val, - "max_txpower": p.MaxTxpower, - "min_rssi_enabled": p.MinRssiEnabled.Val, - "min_txpower": p.MinTxpower, - "nss": p.Nss, - "radio_caps": p.RadioCaps, - "tx_power": int(p.TxPower.Val), // this will go float in 2.1. - "tx_power_mode": p.TxPowerMode, - } - for _, s := range u.RadioTableStats { + tags = make(map[string]string) + fields = make(map[string]interface{}) + // Loop each virtual AP (ESSID) and extract data for it from radio_tables and radio_table_stats. + for _, s := range u.VapTable { + tags["device_name"] = u.Name + tags["device_id"] = u.ID + tags["device_mac"] = u.Mac + tags["site_name"] = u.SiteName + tags["ap_mac"] = s.ApMac + tags["bssid"] = s.Bssid + tags["id"] = s.ID + tags["name"] = s.Name + tags["radio_name"] = s.RadioName + tags["wlanconf_id"] = s.WlanconfID + tags["site_id"] = s.SiteID + fields["ccq"] = s.Ccq + fields["essid"] = s.Essid + fields["extchannel"] = s.Extchannel + fields["is_guest"] = s.IsGuest.Val + fields["is_wep"] = s.IsWep.Val + fields["mac_filter_rejections"] = s.MacFilterRejections + fields["num_satisfaction_sta"] = s.NumSatisfactionSta.Val + fields["avg_client_signal"] = s.AvgClientSignal.Val + fields["satisfaction"] = s.Satisfaction.Val + fields["satisfaction_now"] = s.SatisfactionNow.Val + fields["rx_bytes"] = s.RxBytes.Val + fields["rx_crypts"] = s.RxCrypts.Val + fields["rx_dropped"] = s.RxDropped.Val + fields["rx_errors"] = s.RxErrors.Val + fields["rx_frags"] = s.RxFrags.Val + fields["rx_nwids"] = s.RxNwids.Val + fields["rx_packets"] = s.RxPackets.Val + fields["tx_bytes"] = s.TxBytes.Val + fields["tx_dropped"] = s.TxDropped.Val + fields["tx_errors"] = s.TxErrors.Val + fields["tx_packets"] = s.TxPackets.Val + fields["tx_power"] = s.TxPower.Val + fields["tx_retries"] = s.TxRetries.Val + fields["tx_combined_retries"] = s.TxCombinedRetries.Val + fields["tx_data_mpdu_bytes"] = s.TxDataMpduBytes.Val + fields["tx_rts_retries"] = s.TxRtsRetries.Val + fields["tx_success"] = s.TxSuccess.Val + fields["tx_total"] = s.TxTotal.Val + fields["tx_tcp_goodbytes"] = s.TxTCPStats.Goodbytes.Val + fields["tx_tcp_lat_avg"] = s.TxTCPStats.LatAvg.Val + fields["tx_tcp_lat_max"] = s.TxTCPStats.LatMax.Val + fields["tx_tcp_lat_min"] = s.TxTCPStats.LatMin.Val + fields["rx_tcp_goodbytes"] = s.RxTCPStats.Goodbytes.Val + fields["rx_tcp_lat_avg"] = s.RxTCPStats.LatAvg.Val + fields["rx_tcp_lat_max"] = s.RxTCPStats.LatMax.Val + fields["rx_tcp_lat_min"] = s.RxTCPStats.LatMin.Val + fields["wifi_tx_latency_mov_avg"] = s.WifiTxLatencyMov.Avg.Val + fields["wifi_tx_latency_mov_max"] = s.WifiTxLatencyMov.Max.Val + fields["wifi_tx_latency_mov_min"] = s.WifiTxLatencyMov.Min.Val + fields["wifi_tx_latency_mov_total"] = s.WifiTxLatencyMov.Total.Val + fields["wifi_tx_latency_mov_cuont"] = s.WifiTxLatencyMov.TotalCount.Val + + fields["usage"] = s.Usage + for _, p := range u.RadioTable { + if p.Name != s.RadioName { + continue + } + tags["wlangroup_id"] = p.WlangroupID + tags["channel"] = p.Channel.Txt + tags["radio"] = p.Radio + fields["current_antenna_gain"] = p.CurrentAntennaGain.Val + fields["ht"] = p.Ht + fields["max_txpower"] = p.MaxTxpower.Val + fields["min_rssi_enabled"] = p.MinRssiEnabled.Val + fields["min_txpower"] = p.MinTxpower.Val + fields["nss"] = p.Nss.Val + fields["radio_caps"] = p.RadioCaps.Val + fields["tx_power"] = p.TxPower.Val + } + for _, p := range u.RadioTableStats { // This may be a tad slower but it allows putting // all the radio stats into one table. - if p.Name == s.Name { - fields["ast_be_xmit"] = s.AstBeXmit - fields["ast_cst"] = s.AstCst - fields["channel"] = s.Channel - fields["ast_txto"] = s.AstTxto - fields["cu_self_rx"] = s.CuSelfRx - fields["cu_self_tx"] = s.CuSelfTx - fields["cu_total"] = s.CuTotal - fields["extchannel"] = s.Extchannel - fields["gain"] = s.Gain - fields["guest-num_sta"] = s.GuestNumSta - fields["num_sta"] = s.NumSta - fields["radio"] = s.Radio - fields["state"] = s.State - fields["radio_tx_packets"] = s.TxPackets - fields["radio_tx_power"] = s.TxPower.Val - fields["radio_tx_retries"] = s.TxRetries - fields["user-num_sta"] = s.UserNumSta - break + if p.Name != s.RadioName { + continue } + fields["ast_be_xmit"] = p.AstBeXmit.Val + fields["channel"] = p.Channel.Val + fields["cu_self_rx"] = p.CuSelfRx.Val + fields["cu_self_tx"] = p.CuSelfTx.Val + fields["cu_total"] = p.CuTotal.Val + fields["extchannel"] = p.Extchannel.Val + fields["gain"] = p.Gain.Val + fields["guest-num_sta"] = p.GuestNumSta.Val + fields["num_sta"] = p.NumSta.Val + fields["radio"] = p.Radio + fields["tx_packets"] = p.TxPackets.Val + fields["tx_power"] = p.TxPower.Val + fields["tx_retries"] = p.TxRetries.Val + fields["user-num_sta"] = p.UserNumSta.Val } - for _, s := range u.VapTable { - if p.Name == s.RadioName { - tags["ap_mac"] = s.ApMac - tags["bssid"] = s.Bssid - tags["vap_id"] = s.ID - tags["vap_name"] = s.Name - tags["wlanconf_id"] = s.WlanconfID - tags["site_id"] = s.SiteID - tags["site_name"] = s.SiteName - fields["ccq"] = s.Ccq - fields["essid"] = s.Essid - fields["extchannel"] = s.Extchannel - fields["is_guest"] = s.IsGuest.Val - fields["is_wep"] = s.IsWep.Val - fields["mac_filter_rejections"] = s.MacFilterRejections - fields["map_id"] = s.MapID - fields["vap_rx_bytes"] = s.RxBytes - fields["vap_rx_crypts"] = s.RxCrypts - fields["vap_rx_dropped"] = s.RxDropped - fields["vap_rx_errors"] = s.RxErrors - fields["vap_rx_frags"] = s.RxFrags - fields["vap_rx_nwids"] = s.RxNwids - fields["vap_rx_packets"] = s.RxPackets - fields["vap_tx_bytes"] = s.TxBytes - fields["vap_tx_dropped"] = s.TxDropped - fields["vap_tx_errors"] = s.TxErrors - fields["vap_tx_latency_avg"] = s.TxLatencyAvg - fields["vap_tx_latency_max"] = s.TxLatencyMax - fields["vap_tx_latency_min"] = s.TxLatencyMin - fields["vap_tx_packets"] = s.TxPackets - fields["vap_tx_power"] = s.TxPower.Val - fields["vap_tx_retries"] = s.TxRetries - fields["usage"] = s.Usage - break - } - } - pt, err := influx.NewPoint("uap_radios", tags, fields, time.Now()) + pt, err := influx.NewPoint("uap_vaps", tags, fields, time.Now()) if err != nil { return points, err } diff --git a/core/unifi/uap_type.go b/core/unifi/uap_type.go index 3b804501..43136882 100644 --- a/core/unifi/uap_type.go +++ b/core/unifi/uap_type.go @@ -1,363 +1,454 @@ package unifi +import "time" + // UAP represents all the data from the Ubiquiti 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. - No ones feelings will be hurt if you want to break this - up into multiple structs, and/or make it better in general. */ ID string `json:"_id"` - UUptime float64 `json:"_uptime"` - AdoptIP string `json:"adopt_ip,omitempty"` - AdoptURL string `json:"adopt_url,omitempty"` Adopted FlexBool `json:"adopted"` AntennaTable []struct { - ID float64 `json:"id"` - Name string `json:"name"` - Wifi0Gain float64 `json:"wifi0_gain"` - Wifi1Gain float64 `json:"wifi1_gain"` + Default FlexBool `json:"default"` + ID FlexInt `json:"id"` + Name string `json:"name"` + Wifi0Gain FlexInt `json:"wifi0_gain"` + Wifi1Gain FlexInt `json:"wifi1_gain"` } `json:"antenna_table"` - BandsteeringMode string `json:"bandsteering_mode,omitempty"` - BoardRev int `json:"board_rev"` - Bytes float64 `json:"bytes"` - BytesD float64 `json:"bytes-d"` - BytesR float64 `json:"bytes-r"` - Cfgversion string `json:"cfgversion"` + BandsteeringMode string `json:"bandsteering_mode,omitempty"` + BoardRev int `json:"board_rev"` + Cfgversion string `json:"cfgversion"` ConfigNetwork struct { - IP string `json:"ip"` Type string `json:"type"` + IP string `json:"ip"` } `json:"config_network"` - ConnectRequestIP string `json:"connect_request_ip"` - ConnectRequestPort string `json:"connect_request_port"` - ConsideredLostAt float64 `json:"considered_lost_at"` - CountrycodeTable []float64 `json:"countrycode_table"` - Default FlexBool `json:"default,omitempty"` - DeviceID string `json:"device_id"` - DiscoveredVia string `json:"discovered_via,omitempty"` - DownlinkTable []interface{} `json:"downlink_table"` - EthernetTable []struct { + CountrycodeTable []int `json:"countrycode_table"` + EthernetTable []struct { Mac string `json:"mac"` + NumPort FlexInt `json:"num_port"` Name string `json:"name"` - NumPort float64 `json:"num_port"` } `json:"ethernet_table"` - FwCaps int `json:"fw_caps"` - GuestNumSta int `json:"guest-num_sta"` - GuestToken string `json:"guest_token"` - HasEth1 FlexBool `json:"has_eth1"` - HasSpeaker FlexBool `json:"has_speaker"` - InformIP string `json:"inform_ip"` - InformURL string `json:"inform_url"` - IP string `json:"ip"` - Isolated FlexBool `json:"isolated"` - KnownCfgversion string `json:"known_cfgversion"` - LastSeen float64 `json:"last_seen"` - LastUplink struct { - UplinkMac string `json:"uplink_mac"` - UplinkRemotePort int `json:"uplink_remote_port"` - } `json:"last_uplink"` + FwCaps int `json:"fw_caps"` + HasEth1 FlexBool `json:"has_eth1"` + HasSpeaker FlexBool `json:"has_speaker"` + InformIP string `json:"inform_ip"` + InformURL string `json:"inform_url"` + IP string `json:"ip"` LedOverride string `json:"led_override"` - Locating FlexBool `json:"locating"` Mac string `json:"mac"` + MeshStaVapEnabled FlexBool `json:"mesh_sta_vap_enabled"` Model string `json:"model"` Name string `json:"name"` - NextHeartbeatAt float64 `json:"next_heartbeat_at"` - NumSta float64 `json:"num_sta"` OutdoorModeOverride string `json:"outdoor_mode_override"` PortTable []struct { - AggregatedBy FlexBool `json:"aggregated_by"` - AttrNoEdit FlexBool `json:"attr_no_edit,omitempty"` - Autoneg FlexBool `json:"autoneg"` - BytesR float64 `json:"bytes-r"` - Enable FlexBool `json:"enable"` - FlowctrlRx FlexBool `json:"flowctrl_rx"` - FlowctrlTx FlexBool `json:"flowctrl_tx"` - FullDuplex FlexBool `json:"full_duplex"` - IsUplink FlexBool `json:"is_uplink"` - Jumbo FlexBool `json:"jumbo"` - MacTable []struct { - Age float64 `json:"age"` - Mac string `json:"mac"` - Static FlexBool `json:"static"` - Uptime float64 `json:"uptime"` - Vlan float64 `json:"vlan"` - } `json:"mac_table"` - Masked FlexBool `json:"masked"` - Media string `json:"media"` - Name string `json:"name"` - OpMode string `json:"op_mode"` - PoeCaps float64 `json:"poe_caps"` - PortDelta struct { - RxBytes float64 `json:"rx_bytes"` - RxPackets float64 `json:"rx_packets"` - TimeDelta float64 `json:"time_delta"` - TxBytes float64 `json:"tx_bytes"` - TxPackets float64 `json:"tx_packets"` + PortIdx FlexInt `json:"port_idx"` + OpMode string `json:"op_mode"` + PortconfID string `json:"portconf_id"` + AttrNoEdit FlexBool `json:"attr_no_edit,omitempty"` + Media string `json:"media"` + Name string `json:"name"` + PoeCaps FlexInt `json:"poe_caps"` + PortPoe FlexBool `json:"port_poe"` + TxBytesR FlexInt `json:"tx_bytes-r"` + RxBytesR FlexInt `json:"rx_bytes-r"` + BytesR FlexInt `json:"bytes-r"` + PortDelta struct { + TimeDelta FlexInt `json:"time_delta"` } `json:"port_delta"` - PortIdx float64 `json:"port_idx"` - PortPoe FlexBool `json:"port_poe"` - PortconfID string `json:"portconf_id"` - RxBroadcast float64 `json:"rx_broadcast"` - RxBytes float64 `json:"rx_bytes"` - RxBytesR float64 `json:"rx_bytes-r"` - RxDropped float64 `json:"rx_dropped"` - RxErrors float64 `json:"rx_errors"` - RxMulticast float64 `json:"rx_multicast"` - RxPackets float64 `json:"rx_packets"` - Speed float64 `json:"speed"` - StpPathcost float64 `json:"stp_pathcost"` - StpState string `json:"stp_state"` - TxBroadcast float64 `json:"tx_broadcast"` - TxBytes float64 `json:"tx_bytes"` - TxBytesR float64 `json:"tx_bytes-r"` - TxDropped float64 `json:"tx_dropped"` - TxErrors float64 `json:"tx_errors"` - TxMulticast float64 `json:"tx_multicast"` - TxPackets float64 `json:"tx_packets"` - Up FlexBool `json:"up"` + Enable FlexBool `json:"enable"` + Masked FlexBool `json:"masked"` + AggregatedBy FlexBool `json:"aggregated_by"` } `json:"port_table"` RadioTable []struct { - BuiltinAntGain float64 `json:"builtin_ant_gain"` - BuiltinAntenna FlexBool `json:"builtin_antenna"` - Channel FlexInt `json:"channel"` - CurrentAntennaGain float64 `json:"current_antenna_gain"` - Ht string `json:"ht"` - MaxTxpower float64 `json:"max_txpower"` - MinRssiEnabled FlexBool `json:"min_rssi_enabled"` - MinTxpower float64 `json:"min_txpower"` - Name string `json:"name"` - Nss float64 `json:"nss"` Radio string `json:"radio"` - RadioCaps float64 `json:"radio_caps"` - TxPower FlexInt `json:"tx_power"` + Name string `json:"name"` + Channel FlexInt `json:"channel"` + Ht string `json:"ht"` TxPowerMode string `json:"tx_power_mode"` + TxPower FlexInt `json:"tx_power"` + MaxTxpower FlexInt `json:"max_txpower"` + MinTxpower FlexInt `json:"min_txpower"` + Nss FlexInt `json:"nss"` + MinRssiEnabled FlexBool `json:"min_rssi_enabled"` + BuiltinAntenna FlexBool `json:"builtin_antenna"` + BuiltinAntGain FlexInt `json:"builtin_ant_gain"` + CurrentAntennaGain FlexInt `json:"current_antenna_gain"` + RadioCaps FlexInt `json:"radio_caps"` WlangroupID string `json:"wlangroup_id"` + Is11Ac FlexBool `json:"is_11ac,omitempty"` HasDfs FlexBool `json:"has_dfs,omitempty"` HasFccdfs FlexBool `json:"has_fccdfs,omitempty"` - Is11Ac FlexBool `json:"is_11ac,omitempty"` } `json:"radio_table"` - RadioTableStats []struct { - AstBeXmit float64 `json:"ast_be_xmit"` - AstCst float64 `json:"ast_cst"` - AstTxto float64 `json:"ast_txto"` - Channel float64 `json:"channel"` - CuSelfRx float64 `json:"cu_self_rx"` - CuSelfTx float64 `json:"cu_self_tx"` - CuTotal float64 `json:"cu_total"` - Extchannel float64 `json:"extchannel"` - Gain float64 `json:"gain"` - GuestNumSta float64 `json:"guest-num_sta"` - Name string `json:"name"` - NumSta float64 `json:"num_sta"` - Radio string `json:"radio"` - State string `json:"state"` - TxPackets float64 `json:"tx_packets"` - TxPower FlexInt `json:"tx_power"` - TxRetries float64 `json:"tx_retries"` - UserNumSta float64 `json:"user-num_sta"` - } `json:"radio_table_stats"` - Rollupgrade FlexBool `json:"rollupgrade"` - RxBytes float64 `json:"rx_bytes"` - RxBytesD float64 `json:"rx_bytes-d"` - ScanRadioTable []interface{} `json:"scan_radio_table"` - Scanning FlexBool `json:"scanning"` - Serial string `json:"serial"` - SiteID string `json:"site_id"` - SiteName string `json:"-"` - SpectrumScanning FlexBool `json:"spectrum_scanning"` - SSHSessionTable []interface{} `json:"ssh_session_table"` - Stat struct { - Ap string `json:"ap"` - Bytes float64 `json:"bytes"` - Datetime string `json:"datetime"` - Duration float64 `json:"duration"` - GuestRxBytes float64 `json:"guest-rx_bytes"` - GuestRxCrypts float64 `json:"guest-rx_crypts"` - GuestRxDropped float64 `json:"guest-rx_dropped"` - GuestRxErrors float64 `json:"guest-rx_errors"` - GuestRxFrags float64 `json:"guest-rx_frags"` - GuestRxPackets float64 `json:"guest-rx_packets"` - GuestTxBytes float64 `json:"guest-tx_bytes"` - GuestTxDropped float64 `json:"guest-tx_dropped"` - GuestTxErrors float64 `json:"guest-tx_errors"` - GuestTxPackets float64 `json:"guest-tx_packets"` - GuestTxRetries float64 `json:"guest-tx_retries"` - O string `json:"o"` - Oid string `json:"oid"` - Port1RxBroadcast float64 `json:"port_1-rx_broadcast"` - Port1RxBytes float64 `json:"port_1-rx_bytes"` - Port1RxMulticast float64 `json:"port_1-rx_multicast"` - Port1RxPackets float64 `json:"port_1-rx_packets"` - Port1TxBroadcast float64 `json:"port_1-tx_broadcast"` - Port1TxBytes float64 `json:"port_1-tx_bytes"` - Port1TxMulticast float64 `json:"port_1-tx_multicast"` - Port1TxPackets float64 `json:"port_1-tx_packets"` - RxBytes float64 `json:"rx_bytes"` - RxCrypts float64 `json:"rx_crypts"` - RxDropped float64 `json:"rx_dropped"` - RxErrors float64 `json:"rx_errors"` - RxFrags float64 `json:"rx_frags"` - RxPackets float64 `json:"rx_packets"` - SiteID string `json:"site_id"` - Time float64 `json:"time"` - TxBytes float64 `json:"tx_bytes"` - TxDropped float64 `json:"tx_dropped"` - TxErrors float64 `json:"tx_errors"` - TxPackets float64 `json:"tx_packets"` - TxRetries float64 `json:"tx_retries"` - UserRxBytes float64 `json:"user-rx_bytes"` - UserRxCrypts float64 `json:"user-rx_crypts"` - UserRxDropped float64 `json:"user-rx_dropped"` - UserRxErrors float64 `json:"user-rx_errors"` - UserRxFrags float64 `json:"user-rx_frags"` - UserRxPackets float64 `json:"user-rx_packets"` - UserTxBytes float64 `json:"user-tx_bytes"` - UserTxDropped float64 `json:"user-tx_dropped"` - UserTxErrors float64 `json:"user-tx_errors"` - UserTxPackets float64 `json:"user-tx_packets"` - UserTxRetries float64 `json:"user-tx_retries"` - UserWifi0RxBytes float64 `json:"user-wifi0-rx_bytes"` - UserWifi0RxCrypts float64 `json:"user-wifi0-rx_crypts"` - UserWifi0RxDropped float64 `json:"user-wifi0-rx_dropped"` - UserWifi0RxErrors float64 `json:"user-wifi0-rx_errors"` - UserWifi0RxFrags float64 `json:"user-wifi0-rx_frags"` - UserWifi0RxPackets float64 `json:"user-wifi0-rx_packets"` - UserWifi0TxBytes float64 `json:"user-wifi0-tx_bytes"` - UserWifi0TxDropped float64 `json:"user-wifi0-tx_dropped"` - UserWifi0TxErrors float64 `json:"user-wifi0-tx_errors"` - UserWifi0TxPackets float64 `json:"user-wifi0-tx_packets"` - UserWifi0TxRetries float64 `json:"user-wifi0-tx_retries"` - UserWifi1RxBytes float64 `json:"user-wifi1-rx_bytes"` - UserWifi1RxCrypts float64 `json:"user-wifi1-rx_crypts"` - UserWifi1RxDropped float64 `json:"user-wifi1-rx_dropped"` - UserWifi1RxErrors float64 `json:"user-wifi1-rx_errors"` - UserWifi1RxFrags float64 `json:"user-wifi1-rx_frags"` - UserWifi1RxPackets float64 `json:"user-wifi1-rx_packets"` - UserWifi1TxBytes float64 `json:"user-wifi1-tx_bytes"` - UserWifi1TxDropped float64 `json:"user-wifi1-tx_dropped"` - UserWifi1TxErrors float64 `json:"user-wifi1-tx_errors"` - UserWifi1TxPackets float64 `json:"user-wifi1-tx_packets"` - UserWifi1TxRetries float64 `json:"user-wifi1-tx_retries"` - Wifi0RxBytes float64 `json:"wifi0-rx_bytes"` - Wifi0RxCrypts float64 `json:"wifi0-rx_crypts"` - Wifi0RxDropped float64 `json:"wifi0-rx_dropped"` - Wifi0RxErrors float64 `json:"wifi0-rx_errors"` - Wifi0RxFrags float64 `json:"wifi0-rx_frags"` - Wifi0RxPackets float64 `json:"wifi0-rx_packets"` - Wifi0TxBytes float64 `json:"wifi0-tx_bytes"` - Wifi0TxDropped float64 `json:"wifi0-tx_dropped"` - Wifi0TxErrors float64 `json:"wifi0-tx_errors"` - Wifi0TxPackets float64 `json:"wifi0-tx_packets"` - Wifi0TxRetries float64 `json:"wifi0-tx_retries"` - Wifi1RxBytes float64 `json:"wifi1-rx_bytes"` - Wifi1RxCrypts float64 `json:"wifi1-rx_crypts"` - Wifi1RxDropped float64 `json:"wifi1-rx_dropped"` - Wifi1RxErrors float64 `json:"wifi1-rx_errors"` - Wifi1RxFrags float64 `json:"wifi1-rx_frags"` - Wifi1RxPackets float64 `json:"wifi1-rx_packets"` - Wifi1TxBytes float64 `json:"wifi1-tx_bytes"` - Wifi1TxDropped float64 `json:"wifi1-tx_dropped"` - Wifi1TxErrors float64 `json:"wifi1-tx_errors"` - Wifi1TxPackets float64 `json:"wifi1-tx_packets"` - Wifi1TxRetries float64 `json:"wifi1-tx_retries"` - } `json:"stat"` - State int `json:"state"` - SysStats struct { + ScanRadioTable []interface{} `json:"scan_radio_table"` + Serial string `json:"serial"` + SiteID string `json:"site_id"` + SiteName string `json:"-"` + Type string `json:"type"` + Version string `json:"version"` + VwireTable []interface{} `json:"vwire_table"` + WifiCaps int `json:"wifi_caps"` + WlangroupIDNa string `json:"wlangroup_id_na"` + WlangroupIDNg string `json:"wlangroup_id_ng"` + RequiredVersion string `json:"required_version"` + HwCaps int `json:"hw_caps"` + Unsupported FlexBool `json:"unsupported"` + UnsupportedReason FlexInt `json:"unsupported_reason"` + SysErrorCaps int `json:"sys_error_caps"` + HasFan FlexBool `json:"has_fan"` + HasTemperature FlexBool `json:"has_temperature"` + DeviceID string `json:"device_id"` + State int `json:"state"` + LastSeen FlexInt `json:"last_seen"` + Upgradable FlexBool `json:"upgradable"` + AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` + Rollupgrade FlexBool `json:"rollupgrade"` + KnownCfgversion string `json:"known_cfgversion"` + Uptime FlexInt `json:"uptime"` + UUptime FlexInt `json:"_uptime"` + Locating FlexBool `json:"locating"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + SysStats struct { Loadavg1 float64 `json:"loadavg_1,string"` Loadavg15 float64 `json:"loadavg_15,string"` Loadavg5 float64 `json:"loadavg_5,string"` - MemBuffer float64 `json:"mem_buffer"` - MemTotal float64 `json:"mem_total"` - MemUsed float64 `json:"mem_used"` + MemBuffer FlexInt `json:"mem_buffer"` + MemTotal FlexInt `json:"mem_total"` + MemUsed FlexInt `json:"mem_used"` } `json:"sys_stats"` SystemStats struct { CPU float64 `json:"cpu,string"` Mem float64 `json:"mem,string"` Uptime float64 `json:"uptime,string"` } `json:"system-stats"` - TxBytes float64 `json:"tx_bytes"` - TxBytesD float64 `json:"tx_bytes-d"` - Type string `json:"type"` - Upgradable FlexBool `json:"upgradable"` - Uplink struct { + SSHSessionTable []interface{} `json:"ssh_session_table"` + Scanning FlexBool `json:"scanning"` + SpectrumScanning FlexBool `json:"spectrum_scanning"` + GuestToken string `json:"guest_token"` + Meshv3PeerMac string `json:"meshv3_peer_mac"` + Satisfaction FlexInt `json:"satisfaction"` + Isolated FlexBool `json:"isolated"` + RadioTableStats []struct { + Name string `json:"name"` + Channel FlexInt `json:"channel"` + Radio string `json:"radio"` + AstTxto interface{} `json:"ast_txto"` + AstCst interface{} `json:"ast_cst"` + AstBeXmit FlexInt `json:"ast_be_xmit"` + CuTotal FlexInt `json:"cu_total"` + CuSelfRx FlexInt `json:"cu_self_rx"` + CuSelfTx FlexInt `json:"cu_self_tx"` + Gain FlexInt `json:"gain"` + State string `json:"state"` + Extchannel FlexInt `json:"extchannel"` + TxPower FlexInt `json:"tx_power"` + TxPackets FlexInt `json:"tx_packets"` + TxRetries FlexInt `json:"tx_retries"` + NumSta FlexInt `json:"num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` + } `json:"radio_table_stats"` + Uplink struct { FullDuplex FlexBool `json:"full_duplex"` IP string `json:"ip"` Mac string `json:"mac"` - MaxSpeed int `json:"max_speed"` MaxVlan int `json:"max_vlan"` - Media string `json:"media"` Name string `json:"name"` Netmask string `json:"netmask"` NumPort int `json:"num_port"` - RxBytes float64 `json:"rx_bytes"` - RxBytesR float64 `json:"rx_bytes-r"` - RxDropped float64 `json:"rx_dropped"` - RxErrors float64 `json:"rx_errors"` - RxMulticast float64 `json:"rx_multicast"` - RxPackets float64 `json:"rx_packets"` - Speed float64 `json:"speed"` - TxBytes float64 `json:"tx_bytes"` - TxBytesR float64 `json:"tx_bytes-r"` - TxDropped float64 `json:"tx_dropped"` - TxErrors float64 `json:"tx_errors"` - TxPackets float64 `json:"tx_packets"` - Type string `json:"type"` + RxBytes FlexInt `json:"rx_bytes"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxMulticast FlexInt `json:"rx_multicast"` + RxPackets FlexInt `json:"rx_packets"` + Speed FlexInt `json:"speed"` + TxBytes FlexInt `json:"tx_bytes"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxPackets FlexInt `json:"tx_packets"` Up FlexBool `json:"up"` + MaxSpeed FlexInt `json:"max_speed"` + Type string `json:"type"` + TxBytesR FlexInt `json:"tx_bytes-r"` + RxBytesR FlexInt `json:"rx_bytes-r"` UplinkMac string `json:"uplink_mac"` UplinkRemotePort int `json:"uplink_remote_port"` } `json:"uplink"` - UplinkTable []interface{} `json:"uplink_table"` - Uptime FlexInt `json:"uptime"` - UserNumSta int `json:"user-num_sta"` - VapTable []struct { - ApMac string `json:"ap_mac"` - Bssid string `json:"bssid"` - Ccq int `json:"ccq"` - Channel int `json:"channel"` - Essid string `json:"essid"` - Extchannel int `json:"extchannel"` - ID string `json:"id"` - IsGuest FlexBool `json:"is_guest"` - IsWep FlexBool `json:"is_wep"` - MacFilterRejections int `json:"mac_filter_rejections"` - MapID string `json:"map_id"` - Name string `json:"name"` - NumSta int `json:"num_sta"` - Radio string `json:"radio"` - RadioName string `json:"radio_name"` - RxBytes float64 `json:"rx_bytes"` - RxCrypts float64 `json:"rx_crypts"` - RxDropped float64 `json:"rx_dropped"` - RxErrors float64 `json:"rx_errors"` - RxFrags float64 `json:"rx_frags"` - RxNwids float64 `json:"rx_nwids"` - RxPackets float64 `json:"rx_packets"` - SiteID string `json:"site_id"` - SiteName string `json:"-"` - State string `json:"state"` - T string `json:"t"` - TxBytes float64 `json:"tx_bytes"` - TxDropped float64 `json:"tx_dropped"` - TxErrors float64 `json:"tx_errors"` - TxLatencyAvg float64 `json:"tx_latency_avg"` - TxLatencyMax float64 `json:"tx_latency_max"` - TxLatencyMin float64 `json:"tx_latency_min"` - TxPackets float64 `json:"tx_packets"` - TxPower FlexInt `json:"tx_power"` - TxRetries int `json:"tx_retries"` - Up FlexBool `json:"up"` - Usage string `json:"usage"` - WlanconfID string `json:"wlanconf_id"` + VapTable []struct { + SiteName string `json:"-"` + AnomaliesBarChart struct { + HighTCPLatency FlexInt `json:"high_tcp_latency"` + HighTCPPacketLoss FlexInt `json:"high_tcp_packet_loss"` + HighWifiLatency FlexInt `json:"high_wifi_latency"` + HighWifiRetries FlexInt `json:"high_wifi_retries"` + LowPhyRate FlexInt `json:"low_phy_rate"` + PoorStreamEff FlexInt `json:"poor_stream_eff"` + SleepyClient FlexInt `json:"sleepy_client"` + StaArpTimeout FlexInt `json:"sta_arp_timeout"` + StaDNSTimeout FlexInt `json:"sta_dns_timeout"` + StaIPTimeout FlexInt `json:"sta_ip_timeout"` + WeakSignal FlexInt `json:"weak_signal"` + } `json:"anomalies_bar_chart"` + AnomaliesBarChartNow struct { + HighTCPLatency FlexInt `json:"high_tcp_latency"` + HighTCPPacketLoss FlexInt `json:"high_tcp_packet_loss"` + HighWifiLatency FlexInt `json:"high_wifi_latency"` + HighWifiRetries FlexInt `json:"high_wifi_retries"` + LowPhyRate FlexInt `json:"low_phy_rate"` + PoorStreamEff FlexInt `json:"poor_stream_eff"` + SleepyClient FlexInt `json:"sleepy_client"` + StaArpTimeout FlexInt `json:"sta_arp_timeout"` + StaDNSTimeout FlexInt `json:"sta_dns_timeout"` + StaIPTimeout FlexInt `json:"sta_ip_timeout"` + WeakSignal FlexInt `json:"weak_signal"` + } `json:"anomalies_bar_chart_now"` + AvgClientSignal FlexInt `json:"avg_client_signal"` + Bssid string `json:"bssid"` + Ccq int `json:"ccq"` + Channel int `json:"channel"` + Essid string `json:"essid"` + Extchannel int `json:"extchannel"` + ID string `json:"id"` + MacFilterRejections int `json:"mac_filter_rejections"` + Name string `json:"name"` + NumSatisfactionSta FlexInt `json:"num_satisfaction_sta"` + NumSta int `json:"num_sta"` + Radio string `json:"radio"` + RadioName string `json:"radio_name"` + ReasonsBarChart struct { + PhyRate FlexInt `json:"phy_rate"` + Signal FlexInt `json:"signal"` + SleepyClient FlexInt `json:"sleepy_client"` + StaArpTimeout FlexInt `json:"sta_arp_timeout"` + StaDNSTimeout FlexInt `json:"sta_dns_timeout"` + StaIPTimeout FlexInt `json:"sta_ip_timeout"` + StreamEff FlexInt `json:"stream_eff"` + TCPLatency FlexInt `json:"tcp_latency"` + TCPPacketLoss FlexInt `json:"tcp_packet_loss"` + WifiLatency FlexInt `json:"wifi_latency"` + WifiRetries FlexInt `json:"wifi_retries"` + } `json:"reasons_bar_chart"` + ReasonsBarChartNow struct { + PhyRate FlexInt `json:"phy_rate"` + Signal FlexInt `json:"signal"` + SleepyClient FlexInt `json:"sleepy_client"` + StaArpTimeout FlexInt `json:"sta_arp_timeout"` + StaDNSTimeout FlexInt `json:"sta_dns_timeout"` + StaIPTimeout FlexInt `json:"sta_ip_timeout"` + StreamEff FlexInt `json:"stream_eff"` + TCPLatency FlexInt `json:"tcp_latency"` + TCPPacketLoss FlexInt `json:"tcp_packet_loss"` + WifiLatency FlexInt `json:"wifi_latency"` + WifiRetries FlexInt `json:"wifi_retries"` + } `json:"reasons_bar_chart_now"` + RxBytes FlexInt `json:"rx_bytes"` + RxCrypts FlexInt `json:"rx_crypts"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxFrags FlexInt `json:"rx_frags"` + RxNwids FlexInt `json:"rx_nwids"` + RxPackets FlexInt `json:"rx_packets"` + RxTCPStats struct { + Goodbytes FlexInt `json:"goodbytes"` + LatAvg FlexInt `json:"lat_avg"` + LatMax FlexInt `json:"lat_max"` + LatMin FlexInt `json:"lat_min"` + Stalls FlexInt `json:"stalls"` + } `json:"rx_tcp_stats"` + Satisfaction FlexInt `json:"satisfaction"` + SatisfactionNow FlexInt `json:"satisfaction_now"` + State string `json:"state"` + TxBytes FlexInt `json:"tx_bytes"` + TxCombinedRetries FlexInt `json:"tx_combined_retries"` + TxDataMpduBytes FlexInt `json:"tx_data_mpdu_bytes"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxPackets FlexInt `json:"tx_packets"` + TxPower FlexInt `json:"tx_power"` + TxRetries FlexInt `json:"tx_retries"` + TxRtsRetries FlexInt `json:"tx_rts_retries"` + TxSuccess FlexInt `json:"tx_success"` + TxTCPStats struct { + Goodbytes FlexInt `json:"goodbytes"` + LatAvg FlexInt `json:"lat_avg"` + LatMax FlexInt `json:"lat_max"` + LatMin FlexInt `json:"lat_min"` + Stalls FlexInt `json:"stalls"` + } `json:"tx_tcp_stats"` + TxTotal FlexInt `json:"tx_total"` + Up FlexBool `json:"up"` + Usage string `json:"usage"` + WifiTxAttempts FlexInt `json:"wifi_tx_attempts"` + WifiTxDropped FlexInt `json:"wifi_tx_dropped"` + WifiTxLatencyMov struct { + Avg FlexInt `json:"avg"` + Max FlexInt `json:"max"` + Min FlexInt `json:"min"` + Total FlexInt `json:"total"` + TotalCount FlexInt `json:"total_count"` + } `json:"wifi_tx_latency_mov"` + T string `json:"t"` + WlanconfID string `json:"wlanconf_id"` + IsGuest FlexBool `json:"is_guest"` + IsWep FlexBool `json:"is_wep"` + ApMac string `json:"ap_mac"` + MapID interface{} `json:"map_id"` + SiteID string `json:"site_id"` } `json:"vap_table"` - Version string `json:"version"` - VersionIncompatible FlexBool `json:"version_incompatible"` - VwireEnabled FlexBool `json:"vwireEnabled"` - VwireTable []interface{} `json:"vwire_table"` - VwireVapTable []struct { - Bssid string `json:"bssid"` - Radio string `json:"radio"` - RadioName string `json:"radio_name"` - State string `json:"state"` - } `json:"vwire_vap_table"` - WifiCaps int `json:"wifi_caps"` + DownlinkTable []interface{} `json:"downlink_table"` + VwireVapTable []interface{} `json:"vwire_vap_table"` + BytesD FlexInt `json:"bytes-d"` + TxBytesD FlexInt `json:"tx_bytes-d"` + RxBytesD FlexInt `json:"rx_bytes-d"` + BytesR FlexInt `json:"bytes-r"` + LastUplink struct { + UplinkMac string `json:"uplink_mac"` + UplinkRemotePort int `json:"uplink_remote_port"` + } `json:"last_uplink"` + Stat struct { + SiteID string `json:"site_id"` + O string `json:"o"` + Oid string `json:"oid"` + Ap string `json:"ap"` + Time FlexInt `json:"time"` + Datetime time.Time `json:"datetime"` + GuestWifi0RxPackets FlexInt `json:"guest-wifi0-rx_packets"` + GuestWifi1RxPackets FlexInt `json:"guest-wifi1-rx_packets"` + UserWifi1RxPackets FlexInt `json:"user-wifi1-rx_packets"` + UserWifi0RxPackets FlexInt `json:"user-wifi0-rx_packets"` + UserRxPackets FlexInt `json:"user-rx_packets"` + GuestRxPackets FlexInt `json:"guest-rx_packets"` + Wifi0RxPackets FlexInt `json:"wifi0-rx_packets"` + Wifi1RxPackets FlexInt `json:"wifi1-rx_packets"` + RxPackets FlexInt `json:"rx_packets"` + GuestWifi0RxBytes FlexInt `json:"guest-wifi0-rx_bytes"` + GuestWifi1RxBytes FlexInt `json:"guest-wifi1-rx_bytes"` + UserWifi1RxBytes FlexInt `json:"user-wifi1-rx_bytes"` + UserWifi0RxBytes FlexInt `json:"user-wifi0-rx_bytes"` + UserRxBytes FlexInt `json:"user-rx_bytes"` + GuestRxBytes FlexInt `json:"guest-rx_bytes"` + Wifi0RxBytes FlexInt `json:"wifi0-rx_bytes"` + Wifi1RxBytes FlexInt `json:"wifi1-rx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + GuestWifi0RxErrors FlexInt `json:"guest-wifi0-rx_errors"` + GuestWifi1RxErrors FlexInt `json:"guest-wifi1-rx_errors"` + UserWifi1RxErrors FlexInt `json:"user-wifi1-rx_errors"` + UserWifi0RxErrors FlexInt `json:"user-wifi0-rx_errors"` + UserRxErrors FlexInt `json:"user-rx_errors"` + GuestRxErrors FlexInt `json:"guest-rx_errors"` + Wifi0RxErrors FlexInt `json:"wifi0-rx_errors"` + Wifi1RxErrors FlexInt `json:"wifi1-rx_errors"` + RxErrors FlexInt `json:"rx_errors"` + GuestWifi0RxDropped FlexInt `json:"guest-wifi0-rx_dropped"` + GuestWifi1RxDropped FlexInt `json:"guest-wifi1-rx_dropped"` + UserWifi1RxDropped FlexInt `json:"user-wifi1-rx_dropped"` + UserWifi0RxDropped FlexInt `json:"user-wifi0-rx_dropped"` + UserRxDropped FlexInt `json:"user-rx_dropped"` + GuestRxDropped FlexInt `json:"guest-rx_dropped"` + Wifi0RxDropped FlexInt `json:"wifi0-rx_dropped"` + Wifi1RxDropped FlexInt `json:"wifi1-rx_dropped"` + RxDropped FlexInt `json:"rx_dropped"` + GuestWifi0RxCrypts FlexInt `json:"guest-wifi0-rx_crypts"` + GuestWifi1RxCrypts FlexInt `json:"guest-wifi1-rx_crypts"` + UserWifi1RxCrypts FlexInt `json:"user-wifi1-rx_crypts"` + UserWifi0RxCrypts FlexInt `json:"user-wifi0-rx_crypts"` + UserRxCrypts FlexInt `json:"user-rx_crypts"` + GuestRxCrypts FlexInt `json:"guest-rx_crypts"` + Wifi0RxCrypts FlexInt `json:"wifi0-rx_crypts"` + Wifi1RxCrypts FlexInt `json:"wifi1-rx_crypts"` + RxCrypts FlexInt `json:"rx_crypts"` + GuestWifi0RxFrags FlexInt `json:"guest-wifi0-rx_frags"` + GuestWifi1RxFrags FlexInt `json:"guest-wifi1-rx_frags"` + UserWifi1RxFrags FlexInt `json:"user-wifi1-rx_frags"` + UserWifi0RxFrags FlexInt `json:"user-wifi0-rx_frags"` + UserRxFrags FlexInt `json:"user-rx_frags"` + GuestRxFrags FlexInt `json:"guest-rx_frags"` + Wifi0RxFrags FlexInt `json:"wifi0-rx_frags"` + Wifi1RxFrags FlexInt `json:"wifi1-rx_frags"` + RxFrags FlexInt `json:"rx_frags"` + GuestWifi0TxPackets FlexInt `json:"guest-wifi0-tx_packets"` + GuestWifi1TxPackets FlexInt `json:"guest-wifi1-tx_packets"` + UserWifi1TxPackets FlexInt `json:"user-wifi1-tx_packets"` + UserWifi0TxPackets FlexInt `json:"user-wifi0-tx_packets"` + UserTxPackets FlexInt `json:"user-tx_packets"` + GuestTxPackets FlexInt `json:"guest-tx_packets"` + Wifi0TxPackets FlexInt `json:"wifi0-tx_packets"` + Wifi1TxPackets FlexInt `json:"wifi1-tx_packets"` + TxPackets FlexInt `json:"tx_packets"` + GuestWifi0TxBytes FlexInt `json:"guest-wifi0-tx_bytes"` + GuestWifi1TxBytes FlexInt `json:"guest-wifi1-tx_bytes"` + UserWifi1TxBytes FlexInt `json:"user-wifi1-tx_bytes"` + UserWifi0TxBytes FlexInt `json:"user-wifi0-tx_bytes"` + UserTxBytes FlexInt `json:"user-tx_bytes"` + GuestTxBytes FlexInt `json:"guest-tx_bytes"` + Wifi0TxBytes FlexInt `json:"wifi0-tx_bytes"` + Wifi1TxBytes FlexInt `json:"wifi1-tx_bytes"` + TxBytes FlexInt `json:"tx_bytes"` + GuestWifi0TxErrors FlexInt `json:"guest-wifi0-tx_errors"` + GuestWifi1TxErrors FlexInt `json:"guest-wifi1-tx_errors"` + UserWifi1TxErrors FlexInt `json:"user-wifi1-tx_errors"` + UserWifi0TxErrors FlexInt `json:"user-wifi0-tx_errors"` + UserTxErrors FlexInt `json:"user-tx_errors"` + GuestTxErrors FlexInt `json:"guest-tx_errors"` + Wifi0TxErrors FlexInt `json:"wifi0-tx_errors"` + Wifi1TxErrors FlexInt `json:"wifi1-tx_errors"` + TxErrors FlexInt `json:"tx_errors"` + GuestWifi0TxDropped FlexInt `json:"guest-wifi0-tx_dropped"` + GuestWifi1TxDropped FlexInt `json:"guest-wifi1-tx_dropped"` + UserWifi1TxDropped FlexInt `json:"user-wifi1-tx_dropped"` + UserWifi0TxDropped FlexInt `json:"user-wifi0-tx_dropped"` + UserTxDropped FlexInt `json:"user-tx_dropped"` + GuestTxDropped FlexInt `json:"guest-tx_dropped"` + Wifi0TxDropped FlexInt `json:"wifi0-tx_dropped"` + Wifi1TxDropped FlexInt `json:"wifi1-tx_dropped"` + TxDropped FlexInt `json:"tx_dropped"` + GuestWifi0TxRetries FlexInt `json:"guest-wifi0-tx_retries"` + GuestWifi1TxRetries FlexInt `json:"guest-wifi1-tx_retries"` + UserWifi1TxRetries FlexInt `json:"user-wifi1-tx_retries"` + UserWifi0TxRetries FlexInt `json:"user-wifi0-tx_retries"` + UserTxRetries FlexInt `json:"user-tx_retries"` + GuestTxRetries FlexInt `json:"guest-tx_retries"` + Wifi0TxRetries FlexInt `json:"wifi0-tx_retries"` + Wifi1TxRetries FlexInt `json:"wifi1-tx_retries"` + TxRetries FlexInt `json:"tx_retries"` + GuestWifi0MacFilterRejections FlexInt `json:"guest-wifi0-mac_filter_rejections"` + GuestWifi1MacFilterRejections FlexInt `json:"guest-wifi1-mac_filter_rejections"` + UserWifi1MacFilterRejections FlexInt `json:"user-wifi1-mac_filter_rejections"` + UserWifi0MacFilterRejections FlexInt `json:"user-wifi0-mac_filter_rejections"` + UserMacFilterRejections FlexInt `json:"user-mac_filter_rejections"` + GuestMacFilterRejections FlexInt `json:"guest-mac_filter_rejections"` + Wifi0MacFilterRejections FlexInt `json:"wifi0-mac_filter_rejections"` + Wifi1MacFilterRejections FlexInt `json:"wifi1-mac_filter_rejections"` + MacFilterRejections FlexInt `json:"mac_filter_rejections"` + GuestWifi0WifiTxAttempts FlexInt `json:"guest-wifi0-wifi_tx_attempts"` + GuestWifi1WifiTxAttempts FlexInt `json:"guest-wifi1-wifi_tx_attempts"` + UserWifi1WifiTxAttempts FlexInt `json:"user-wifi1-wifi_tx_attempts"` + UserWifi0WifiTxAttempts FlexInt `json:"user-wifi0-wifi_tx_attempts"` + UserWifiTxAttempts FlexInt `json:"user-wifi_tx_attempts"` + GuestWifiTxAttempts FlexInt `json:"guest-wifi_tx_attempts"` + Wifi0WifiTxAttempts FlexInt `json:"wifi0-wifi_tx_attempts"` + Wifi1WifiTxAttempts FlexInt `json:"wifi1-wifi_tx_attempts"` + WifiTxAttempts FlexInt `json:"wifi_tx_attempts"` + GuestWifi0WifiTxDropped FlexInt `json:"guest-wifi0-wifi_tx_dropped"` + GuestWifi1WifiTxDropped FlexInt `json:"guest-wifi1-wifi_tx_dropped"` + UserWifi1WifiTxDropped FlexInt `json:"user-wifi1-wifi_tx_dropped"` + UserWifi0WifiTxDropped FlexInt `json:"user-wifi0-wifi_tx_dropped"` + UserWifiTxDropped FlexInt `json:"user-wifi_tx_dropped"` + GuestWifiTxDropped FlexInt `json:"guest-wifi_tx_dropped"` + Wifi0WifiTxDropped FlexInt `json:"wifi0-wifi_tx_dropped"` + Wifi1WifiTxDropped FlexInt `json:"wifi1-wifi_tx_dropped"` + WifiTxDropped FlexInt `json:"wifi_tx_dropped"` + Bytes FlexInt `json:"bytes"` + Duration FlexInt `json:"duration"` + } `json:"stat,omitempty"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + VwireEnabled FlexBool `json:"vwireEnabled"` + UplinkTable []interface{} `json:"uplink_table"` + NumSta int `json:"num_sta"` + UserNumSta int `json:"user-num_sta"` + GuestNumSta int `json:"guest-num_sta"` + TwoPhaseAdopt FlexBool `json:"two_phase_adopt,omitempty"` } From d96d4dc941b50ac8af458c7a405c0a04dd2b15e6 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Thu, 4 Jul 2019 04:05:25 -0700 Subject: [PATCH 068/194] fix #17 too. --- core/unifi/usg_influx.go | 2 +- core/unifi/usg_type.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index 6bd273d0..bb357736 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -198,7 +198,7 @@ func (u USG) Points() ([]*influx.Point, error) { "tx_bytes": p.TxBytes.Val, "tx_packets": p.TxPackets, "up": p.Up.Txt, - "vlan": p.Vlan, + "vlan": p.Vlan.Val, "dhcpd_ntp_1": p.DhcpdNtp1, "dhcpd_unifi_controller": p.DhcpdUnifiController, "ipv6_interface_type": p.Ipv6InterfaceType, diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index 2c4d769e..be751f1d 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -72,7 +72,7 @@ type USG struct { TxBytes FlexInt `json:"tx_bytes"` TxPackets float64 `json:"tx_packets"` Up FlexBool `json:"up"` - Vlan string `json:"vlan,omitempty"` + Vlan FlexInt `json:"vlan,omitempty"` VlanEnabled FlexBool `json:"vlan_enabled"` DhcpRelayEnabled FlexBool `json:"dhcp_relay_enabled,omitempty"` DhcpdGatewayEnabled FlexBool `json:"dhcpd_gateway_enabled,omitempty"` From a44a7a9399d7cfb0f164d63c817ab3147019afa0 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Thu, 4 Jul 2019 20:51:20 -0700 Subject: [PATCH 069/194] all the data --- core/unifi/uap_influx.go | 243 +++++++++++++++++++++------------------ core/unifi/usg_influx.go | 2 +- 2 files changed, 132 insertions(+), 113 deletions(-) diff --git a/core/unifi/uap_influx.go b/core/unifi/uap_influx.go index b46af1f3..54328b99 100644 --- a/core/unifi/uap_influx.go +++ b/core/unifi/uap_influx.go @@ -35,113 +35,131 @@ func (u UAP) Points() ([]*influx.Point, error) { "vwireEnabled": u.VwireEnabled.Txt, } fields := map[string]interface{}{ - "ip": u.IP, - "bytes": u.Bytes.Val, - "bytes_d": u.BytesD.Val, - "bytes_r": u.BytesR.Val, - "last_seen": u.LastSeen.Val, - "rx_bytes": u.RxBytes.Val, - "rx_bytes-d": u.RxBytesD.Val, - "tx_bytes": u.TxBytes.Val, - "tx_bytes-d": u.TxBytesD.Val, - "uptime": u.Uptime.Val, - "scanning": u.Scanning.Val, - "spectrum_scanning": u.SpectrumScanning.Val, - "roll_upgrade": u.Rollupgrade.Val, - "state": u.State, - "upgradable": u.Upgradable.Val, - "user-num_sta": u.UserNumSta, - "guest-num_sta": u.GuestNumSta, - "version": u.Version, - "loadavg_1": u.SysStats.Loadavg1, - "loadavg_5": u.SysStats.Loadavg5, - "loadavg_15": u.SysStats.Loadavg15, - "mem_buffer": u.SysStats.MemBuffer.Val, - "mem_total": u.SysStats.MemTotal.Val, - "mem_used": u.SysStats.MemUsed.Val, - "cpu": u.SystemStats.CPU, - "mem": u.SystemStats.Mem, - "system_uptime": u.SystemStats.Uptime, - "stat_bytes": u.Stat.Bytes.Val, - "stat_duration": u.Stat.Duration.Val, - "stat_guest-rx_bytes": u.Stat.RxBytes.Val, - "stat_guest-rx_crypts": u.Stat.RxCrypts.Val, - "stat_guest-rx_dropped": u.Stat.RxDropped.Val, - "stat_guest-rx_errors": u.Stat.RxErrors.Val, - "stat_guest-rx_frags": u.Stat.RxFrags.Val, - "stat_guest-rx_packets": u.Stat.RxPackets.Val, - "stat_guest-tx_bytes": u.Stat.TxBytes.Val, - "stat_guest-tx_dropped": u.Stat.TxDropped.Val, - "stat_guest-tx_errors": u.Stat.TxErrors.Val, - "stat_guest-tx_packets": u.Stat.TxPackets.Val, - "stat_guest-tx_retries": u.Stat.TxRetries.Val, - /* snip */ - "stat_rx_bytes": u.Stat.RxBytes.Val, - "stat_rx_crypts": u.Stat.RxCrypts.Val, - "stat_rx_dropped": u.Stat.RxDropped.Val, - "stat_rx_errors": u.Stat.RxErrors.Val, - "stat_rx_frags": u.Stat.RxFrags.Val, - "stat_rx_packets": u.Stat.TxPackets.Val, - "stat_tx_bytes": u.Stat.TxBytes.Val, - "stat_tx_dropped": u.Stat.TxDropped.Val, - "stat_tx_errors": u.Stat.TxErrors.Val, - "stat_tx_packets": u.Stat.TxPackets.Val, - "stat_tx_retries": u.Stat.TxRetries.Val, - "stat_user-rx_bytes": u.Stat.UserRxBytes.Val, - "stat_user-rx_crypts": u.Stat.UserRxCrypts.Val, - "stat_user-rx_dropped": u.Stat.UserRxDropped.Val, - "stat_user-rx_errors": u.Stat.UserRxErrors.Val, - "stat_user-rx_frags": u.Stat.UserRxFrags.Val, - "stat_user-rx_packets": u.Stat.UserRxPackets.Val, - "stat_user-tx_bytes": u.Stat.UserTxBytes.Val, - "stat_user-tx_dropped": u.Stat.UserTxDropped.Val, - "stat_user-tx_errors": u.Stat.UserTxErrors.Val, - "stat_user-tx_packets": u.Stat.UserTxPackets.Val, - "stat_user-tx_retries": u.Stat.UserTxRetries.Val, - "stat_user-wifi0-rx_bytes": u.Stat.UserWifi0RxBytes.Val, - "stat_user-wifi0-rx_crypts": u.Stat.UserWifi0RxCrypts.Val, - "stat_user-wifi0-rx_dropped": u.Stat.UserWifi0RxDropped.Val, - "stat_user-wifi0-rx_errors": u.Stat.UserWifi0RxErrors.Val, - "stat_user-wifi0-rx_frags": u.Stat.UserWifi0RxFrags.Val, - "stat_user-wifi0-rx_packets": u.Stat.UserWifi0RxPackets.Val, - "stat_user-wifi0-tx_bytes": u.Stat.UserWifi0TxBytes.Val, - "stat_user-wifi0-tx_dropped": u.Stat.UserWifi0TxDropped.Val, - "stat_user-wifi0-tx_errors": u.Stat.UserWifi0TxErrors.Val, - "stat_user-wifi0-tx_packets": u.Stat.UserWifi0TxPackets.Val, - "stat_user-wifi0-tx_retries": u.Stat.UserWifi0TxRetries.Val, - "stat_user-wifi1-rx_bytes": u.Stat.UserWifi1RxBytes.Val, - "stat_user-wifi1-rx_crypts": u.Stat.UserWifi1RxCrypts.Val, - "stat_user-wifi1-rx_dropped": u.Stat.UserWifi1RxDropped.Val, - "stat_user-wifi1-rx_errors": u.Stat.UserWifi1RxErrors.Val, - "stat_user-wifi1-rx_frags": u.Stat.UserWifi1RxFrags.Val, - "stat_user-wifi1-rx_packets": u.Stat.UserWifi1RxPackets.Val, - "stat_user-wifi1-tx_bytes": u.Stat.UserWifi1TxBytes.Val, - "stat_user-wifi1-tx_dropped": u.Stat.UserWifi1TxDropped.Val, - "stat_user-wifi1-tx_errors": u.Stat.UserWifi1TxErrors.Val, - "stat_user-wifi1-tx_packets": u.Stat.UserWifi1TxPackets.Val, - "stat_user-wifi1-tx_retries": u.Stat.UserWifi1TxRetries.Val, - "stat_wifi0-rx_bytes": u.Stat.Wifi0RxBytes.Val, - "stat_wifi0-rx_crypts": u.Stat.Wifi0RxCrypts.Val, - "stat_wifi0-rx_dropped": u.Stat.Wifi0RxDropped.Val, - "stat_wifi0-rx_errors": u.Stat.Wifi0RxErrors.Val, - "stat_wifi0-rx_frags": u.Stat.Wifi0RxFrags.Val, - "stat_wifi0-rx_packets": u.Stat.Wifi0RxPackets.Val, - "stat_wifi0-tx_bytes": u.Stat.Wifi0TxBytes.Val, - "stat_wifi0-tx_dropped": u.Stat.Wifi0TxDropped.Val, - "stat_wifi0-tx_errors": u.Stat.Wifi0TxErrors.Val, - "stat_wifi0-tx_packets": u.Stat.Wifi0TxPackets.Val, - "stat_wifi0-tx_retries": u.Stat.Wifi0TxRetries.Val, - "stat_wifi1-rx_bytes": u.Stat.Wifi1RxBytes.Val, - "stat_wifi1-rx_crypts": u.Stat.Wifi1RxCrypts.Val, - "stat_wifi1-rx_dropped": u.Stat.Wifi1RxDropped.Val, - "stat_wifi1-rx_errors": u.Stat.Wifi1RxErrors.Val, - "stat_wifi1-rx_frags": u.Stat.Wifi1RxFrags.Val, - "stat_wifi1-rx_packets": u.Stat.Wifi1RxPackets.Val, - "stat_wifi1-tx_bytes": u.Stat.Wifi1TxBytes.Val, - "stat_wifi1-tx_dropped": u.Stat.Wifi1TxDropped.Val, - "stat_wifi1-tx_errors": u.Stat.Wifi1TxErrors.Val, - "stat_wifi1-tx_packets": u.Stat.Wifi1TxPackets.Val, - "stat_wifi1-tx_retries": u.Stat.Wifi1TxRetries.Val, + "ip": u.IP, + "bytes": u.Bytes.Val, + "bytes_d": u.BytesD.Val, + "bytes_r": u.BytesR.Val, + "last_seen": u.LastSeen.Val, + "rx_bytes": u.RxBytes.Val, + "rx_bytes-d": u.RxBytesD.Val, + "tx_bytes": u.TxBytes.Val, + "tx_bytes-d": u.TxBytesD.Val, + "uptime": u.Uptime.Val, + "scanning": u.Scanning.Val, + "spectrum_scanning": u.SpectrumScanning.Val, + "roll_upgrade": u.Rollupgrade.Val, + "state": u.State, + "upgradable": u.Upgradable.Val, + "user-num_sta": u.UserNumSta, + "guest-num_sta": u.GuestNumSta, + "version": u.Version, + "loadavg_1": u.SysStats.Loadavg1, + "loadavg_5": u.SysStats.Loadavg5, + "loadavg_15": u.SysStats.Loadavg15, + "mem_buffer": u.SysStats.MemBuffer.Val, + "mem_total": u.SysStats.MemTotal.Val, + "mem_used": u.SysStats.MemUsed.Val, + "cpu": u.SystemStats.CPU, + "mem": u.SystemStats.Mem, + "system_uptime": u.SystemStats.Uptime, + "guest-wifi0-rx_packets": u.Stat.GuestWifi0RxPackets.Val, + "guest-wifi1-rx_packets": u.Stat.GuestWifi1RxPackets.Val, + "user-wifi1-rx_packets": u.Stat.UserWifi1RxPackets.Val, + "user-wifi0-rx_packets": u.Stat.UserWifi0RxPackets.Val, + "user-rx_packets": u.Stat.UserRxPackets.Val, + "guest-rx_packets": u.Stat.GuestRxPackets.Val, + "wifi0-rx_packets": u.Stat.Wifi0RxPackets.Val, + "wifi1-rx_packets": u.Stat.Wifi1RxPackets.Val, + "rx_packets": u.Stat.RxPackets.Val, + "guest-wifi0-rx_bytes": u.Stat.GuestWifi0RxBytes.Val, + "guest-wifi1-rx_bytes": u.Stat.GuestWifi1RxBytes.Val, + "user-wifi1-rx_bytes": u.Stat.UserWifi1RxBytes.Val, + "user-wifi0-rx_bytes": u.Stat.UserWifi0RxBytes.Val, + "user-rx_bytes": u.Stat.UserRxBytes.Val, + "guest-rx_bytes": u.Stat.GuestRxBytes.Val, + "wifi0-rx_bytes": u.Stat.Wifi0RxBytes.Val, + "wifi1-rx_bytes": u.Stat.Wifi1RxBytes.Val, + "stat_rx_bytes": u.Stat.RxBytes.Val, + "guest-wifi0-rx_errors": u.Stat.GuestWifi0RxErrors.Val, + "guest-wifi1-rx_errors": u.Stat.GuestWifi1RxErrors.Val, + "user-wifi1-rx_errors": u.Stat.UserWifi1RxErrors.Val, + "user-wifi0-rx_errors": u.Stat.UserWifi0RxErrors.Val, + "user-rx_errors": u.Stat.UserRxErrors.Val, + "guest-rx_errors": u.Stat.GuestRxErrors.Val, + "wifi0-rx_errors": u.Stat.Wifi0RxErrors.Val, + "wifi1-rx_errors": u.Stat.Wifi1RxErrors.Val, + "rx_errors": u.Stat.RxErrors.Val, + "guest-wifi0-rx_dropped": u.Stat.GuestWifi0RxDropped.Val, + "guest-wifi1-rx_dropped": u.Stat.GuestWifi1RxDropped.Val, + "user-wifi1-rx_dropped": u.Stat.UserWifi1RxDropped.Val, + "user-wifi0-rx_dropped": u.Stat.UserWifi0RxDropped.Val, + "user-rx_dropped": u.Stat.UserRxDropped.Val, + "guest-rx_dropped": u.Stat.GuestRxDropped.Val, + "wifi0-rx_dropped": u.Stat.Wifi0RxDropped.Val, + "wifi1-rx_dropped": u.Stat.Wifi1RxDropped.Val, + "rx_dropped": u.Stat.RxDropped.Val, + "guest-wifi0-rx_crypts": u.Stat.GuestWifi0RxCrypts.Val, + "guest-wifi1-rx_crypts": u.Stat.GuestWifi1RxCrypts.Val, + "user-wifi1-rx_crypts": u.Stat.UserWifi1RxCrypts.Val, + "user-wifi0-rx_crypts": u.Stat.UserWifi0RxCrypts.Val, + "user-rx_crypts": u.Stat.UserRxCrypts.Val, + "guest-rx_crypts": u.Stat.GuestRxCrypts.Val, + "wifi0-rx_crypts": u.Stat.Wifi0RxCrypts.Val, + "wifi1-rx_crypts": u.Stat.Wifi1RxCrypts.Val, + "rx_crypts": u.Stat.RxCrypts.Val, + "guest-wifi0-rx_frags": u.Stat.GuestWifi0RxFrags.Val, + "guest-wifi1-rx_frags": u.Stat.GuestWifi1RxFrags.Val, + "user-wifi1-rx_frags": u.Stat.UserWifi1RxFrags.Val, + "user-wifi0-rx_frags": u.Stat.UserWifi0RxFrags.Val, + "user-rx_frags": u.Stat.UserRxFrags.Val, + "guest-rx_frags": u.Stat.GuestRxFrags.Val, + "wifi0-rx_frags": u.Stat.Wifi0RxFrags.Val, + "wifi1-rx_frags": u.Stat.Wifi1RxFrags.Val, + "rx_frags": u.Stat.RxFrags.Val, + "guest-wifi0-tx_packets": u.Stat.GuestWifi0TxPackets.Val, + "guest-wifi1-tx_packets": u.Stat.GuestWifi1TxPackets.Val, + "user-wifi1-tx_packets": u.Stat.UserWifi1TxPackets.Val, + "user-wifi0-tx_packets": u.Stat.UserWifi0TxPackets.Val, + "user-tx_packets": u.Stat.UserTxPackets.Val, + "guest-tx_packets": u.Stat.GuestTxPackets.Val, + "wifi0-tx_packets": u.Stat.Wifi0TxPackets.Val, + "wifi1-tx_packets": u.Stat.Wifi1TxPackets.Val, + "tx_packets": u.Stat.TxPackets.Val, + "guest-wifi0-tx_bytes": u.Stat.GuestWifi0TxBytes.Val, + "guest-wifi1-tx_bytes": u.Stat.GuestWifi1TxBytes.Val, + "user-wifi1-tx_bytes": u.Stat.UserWifi1TxBytes.Val, + "user-wifi0-tx_bytes": u.Stat.UserWifi0TxBytes.Val, + "user-tx_bytes": u.Stat.UserTxBytes.Val, + "guest-tx_bytes": u.Stat.GuestTxBytes.Val, + "wifi0-tx_bytes": u.Stat.Wifi0TxBytes.Val, + "wifi1-tx_bytes": u.Stat.Wifi1TxBytes.Val, + "stat_tx_bytes": u.Stat.TxBytes.Val, + "guest-wifi0-tx_errors": u.Stat.GuestWifi0TxErrors.Val, + "guest-wifi1-tx_errors": u.Stat.GuestWifi1TxErrors.Val, + "user-wifi1-tx_errors": u.Stat.UserWifi1TxErrors.Val, + "user-wifi0-tx_errors": u.Stat.UserWifi0TxErrors.Val, + "user-tx_errors": u.Stat.UserTxErrors.Val, + "guest-tx_errors": u.Stat.GuestTxErrors.Val, + "wifi0-tx_errors": u.Stat.Wifi0TxErrors.Val, + "wifi1-tx_errors": u.Stat.Wifi1TxErrors.Val, + "tx_errors": u.Stat.TxErrors.Val, + "guest-wifi0-tx_dropped": u.Stat.GuestWifi0TxDropped.Val, + "guest-wifi1-tx_dropped": u.Stat.GuestWifi1TxDropped.Val, + "user-wifi1-tx_dropped": u.Stat.UserWifi1TxDropped.Val, + "user-wifi0-tx_dropped": u.Stat.UserWifi0TxDropped.Val, + "user-tx_dropped": u.Stat.UserTxDropped.Val, + "guest-tx_dropped": u.Stat.GuestTxDropped.Val, + "wifi0-tx_dropped": u.Stat.Wifi0TxDropped.Val, + "wifi1-tx_dropped": u.Stat.Wifi1TxDropped.Val, + "tx_dropped": u.Stat.TxDropped.Val, + "guest-wifi0-tx_retries": u.Stat.GuestWifi0TxRetries.Val, + "guest-wifi1-tx_retries": u.Stat.GuestWifi1TxRetries.Val, + "user-wifi1-tx_retries": u.Stat.UserWifi1TxRetries.Val, + "user-wifi0-tx_retries": u.Stat.UserWifi0TxRetries.Val, + "user-tx_retries": u.Stat.UserTxRetries.Val, + "guest-tx_retries": u.Stat.GuestTxRetries.Val, + "wifi0-tx_retries": u.Stat.Wifi0TxRetries.Val, + "wifi1-tx_retries": u.Stat.Wifi1TxRetries.Val, } pt, err := influx.NewPoint("uap", tags, fields, time.Now()) if err != nil { @@ -163,12 +181,15 @@ func (u UAP) Points() ([]*influx.Point, error) { tags["name"] = s.Name tags["radio_name"] = s.RadioName tags["wlanconf_id"] = s.WlanconfID + tags["essid"] = s.Essid tags["site_id"] = s.SiteID + tags["usage"] = s.Usage + tags["state"] = s.State + tags["is_guest"] = s.IsGuest.Txt + tags["is_wep"] = s.IsWep.Txt + fields["ccq"] = s.Ccq - fields["essid"] = s.Essid fields["extchannel"] = s.Extchannel - fields["is_guest"] = s.IsGuest.Val - fields["is_wep"] = s.IsWep.Val fields["mac_filter_rejections"] = s.MacFilterRejections fields["num_satisfaction_sta"] = s.NumSatisfactionSta.Val fields["avg_client_signal"] = s.AvgClientSignal.Val @@ -205,8 +226,6 @@ func (u UAP) Points() ([]*influx.Point, error) { fields["wifi_tx_latency_mov_min"] = s.WifiTxLatencyMov.Min.Val fields["wifi_tx_latency_mov_total"] = s.WifiTxLatencyMov.Total.Val fields["wifi_tx_latency_mov_cuont"] = s.WifiTxLatencyMov.TotalCount.Val - - fields["usage"] = s.Usage for _, p := range u.RadioTable { if p.Name != s.RadioName { continue diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index bb357736..56a0c4af 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -198,7 +198,7 @@ func (u USG) Points() ([]*influx.Point, error) { "tx_bytes": p.TxBytes.Val, "tx_packets": p.TxPackets, "up": p.Up.Txt, - "vlan": p.Vlan.Val, + "vlan": p.Vlan.Txt, "dhcpd_ntp_1": p.DhcpdNtp1, "dhcpd_unifi_controller": p.DhcpdUnifiController, "ipv6_interface_type": p.Ipv6InterfaceType, From 2f320047a243498c60cd0748458b638305c8e852 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Thu, 4 Jul 2019 20:53:16 -0700 Subject: [PATCH 070/194] add the prefix back --- core/unifi/uap_influx.go | 250 +++++++++++++++++++-------------------- 1 file changed, 125 insertions(+), 125 deletions(-) diff --git a/core/unifi/uap_influx.go b/core/unifi/uap_influx.go index 54328b99..a5731e19 100644 --- a/core/unifi/uap_influx.go +++ b/core/unifi/uap_influx.go @@ -35,131 +35,131 @@ func (u UAP) Points() ([]*influx.Point, error) { "vwireEnabled": u.VwireEnabled.Txt, } fields := map[string]interface{}{ - "ip": u.IP, - "bytes": u.Bytes.Val, - "bytes_d": u.BytesD.Val, - "bytes_r": u.BytesR.Val, - "last_seen": u.LastSeen.Val, - "rx_bytes": u.RxBytes.Val, - "rx_bytes-d": u.RxBytesD.Val, - "tx_bytes": u.TxBytes.Val, - "tx_bytes-d": u.TxBytesD.Val, - "uptime": u.Uptime.Val, - "scanning": u.Scanning.Val, - "spectrum_scanning": u.SpectrumScanning.Val, - "roll_upgrade": u.Rollupgrade.Val, - "state": u.State, - "upgradable": u.Upgradable.Val, - "user-num_sta": u.UserNumSta, - "guest-num_sta": u.GuestNumSta, - "version": u.Version, - "loadavg_1": u.SysStats.Loadavg1, - "loadavg_5": u.SysStats.Loadavg5, - "loadavg_15": u.SysStats.Loadavg15, - "mem_buffer": u.SysStats.MemBuffer.Val, - "mem_total": u.SysStats.MemTotal.Val, - "mem_used": u.SysStats.MemUsed.Val, - "cpu": u.SystemStats.CPU, - "mem": u.SystemStats.Mem, - "system_uptime": u.SystemStats.Uptime, - "guest-wifi0-rx_packets": u.Stat.GuestWifi0RxPackets.Val, - "guest-wifi1-rx_packets": u.Stat.GuestWifi1RxPackets.Val, - "user-wifi1-rx_packets": u.Stat.UserWifi1RxPackets.Val, - "user-wifi0-rx_packets": u.Stat.UserWifi0RxPackets.Val, - "user-rx_packets": u.Stat.UserRxPackets.Val, - "guest-rx_packets": u.Stat.GuestRxPackets.Val, - "wifi0-rx_packets": u.Stat.Wifi0RxPackets.Val, - "wifi1-rx_packets": u.Stat.Wifi1RxPackets.Val, - "rx_packets": u.Stat.RxPackets.Val, - "guest-wifi0-rx_bytes": u.Stat.GuestWifi0RxBytes.Val, - "guest-wifi1-rx_bytes": u.Stat.GuestWifi1RxBytes.Val, - "user-wifi1-rx_bytes": u.Stat.UserWifi1RxBytes.Val, - "user-wifi0-rx_bytes": u.Stat.UserWifi0RxBytes.Val, - "user-rx_bytes": u.Stat.UserRxBytes.Val, - "guest-rx_bytes": u.Stat.GuestRxBytes.Val, - "wifi0-rx_bytes": u.Stat.Wifi0RxBytes.Val, - "wifi1-rx_bytes": u.Stat.Wifi1RxBytes.Val, - "stat_rx_bytes": u.Stat.RxBytes.Val, - "guest-wifi0-rx_errors": u.Stat.GuestWifi0RxErrors.Val, - "guest-wifi1-rx_errors": u.Stat.GuestWifi1RxErrors.Val, - "user-wifi1-rx_errors": u.Stat.UserWifi1RxErrors.Val, - "user-wifi0-rx_errors": u.Stat.UserWifi0RxErrors.Val, - "user-rx_errors": u.Stat.UserRxErrors.Val, - "guest-rx_errors": u.Stat.GuestRxErrors.Val, - "wifi0-rx_errors": u.Stat.Wifi0RxErrors.Val, - "wifi1-rx_errors": u.Stat.Wifi1RxErrors.Val, - "rx_errors": u.Stat.RxErrors.Val, - "guest-wifi0-rx_dropped": u.Stat.GuestWifi0RxDropped.Val, - "guest-wifi1-rx_dropped": u.Stat.GuestWifi1RxDropped.Val, - "user-wifi1-rx_dropped": u.Stat.UserWifi1RxDropped.Val, - "user-wifi0-rx_dropped": u.Stat.UserWifi0RxDropped.Val, - "user-rx_dropped": u.Stat.UserRxDropped.Val, - "guest-rx_dropped": u.Stat.GuestRxDropped.Val, - "wifi0-rx_dropped": u.Stat.Wifi0RxDropped.Val, - "wifi1-rx_dropped": u.Stat.Wifi1RxDropped.Val, - "rx_dropped": u.Stat.RxDropped.Val, - "guest-wifi0-rx_crypts": u.Stat.GuestWifi0RxCrypts.Val, - "guest-wifi1-rx_crypts": u.Stat.GuestWifi1RxCrypts.Val, - "user-wifi1-rx_crypts": u.Stat.UserWifi1RxCrypts.Val, - "user-wifi0-rx_crypts": u.Stat.UserWifi0RxCrypts.Val, - "user-rx_crypts": u.Stat.UserRxCrypts.Val, - "guest-rx_crypts": u.Stat.GuestRxCrypts.Val, - "wifi0-rx_crypts": u.Stat.Wifi0RxCrypts.Val, - "wifi1-rx_crypts": u.Stat.Wifi1RxCrypts.Val, - "rx_crypts": u.Stat.RxCrypts.Val, - "guest-wifi0-rx_frags": u.Stat.GuestWifi0RxFrags.Val, - "guest-wifi1-rx_frags": u.Stat.GuestWifi1RxFrags.Val, - "user-wifi1-rx_frags": u.Stat.UserWifi1RxFrags.Val, - "user-wifi0-rx_frags": u.Stat.UserWifi0RxFrags.Val, - "user-rx_frags": u.Stat.UserRxFrags.Val, - "guest-rx_frags": u.Stat.GuestRxFrags.Val, - "wifi0-rx_frags": u.Stat.Wifi0RxFrags.Val, - "wifi1-rx_frags": u.Stat.Wifi1RxFrags.Val, - "rx_frags": u.Stat.RxFrags.Val, - "guest-wifi0-tx_packets": u.Stat.GuestWifi0TxPackets.Val, - "guest-wifi1-tx_packets": u.Stat.GuestWifi1TxPackets.Val, - "user-wifi1-tx_packets": u.Stat.UserWifi1TxPackets.Val, - "user-wifi0-tx_packets": u.Stat.UserWifi0TxPackets.Val, - "user-tx_packets": u.Stat.UserTxPackets.Val, - "guest-tx_packets": u.Stat.GuestTxPackets.Val, - "wifi0-tx_packets": u.Stat.Wifi0TxPackets.Val, - "wifi1-tx_packets": u.Stat.Wifi1TxPackets.Val, - "tx_packets": u.Stat.TxPackets.Val, - "guest-wifi0-tx_bytes": u.Stat.GuestWifi0TxBytes.Val, - "guest-wifi1-tx_bytes": u.Stat.GuestWifi1TxBytes.Val, - "user-wifi1-tx_bytes": u.Stat.UserWifi1TxBytes.Val, - "user-wifi0-tx_bytes": u.Stat.UserWifi0TxBytes.Val, - "user-tx_bytes": u.Stat.UserTxBytes.Val, - "guest-tx_bytes": u.Stat.GuestTxBytes.Val, - "wifi0-tx_bytes": u.Stat.Wifi0TxBytes.Val, - "wifi1-tx_bytes": u.Stat.Wifi1TxBytes.Val, - "stat_tx_bytes": u.Stat.TxBytes.Val, - "guest-wifi0-tx_errors": u.Stat.GuestWifi0TxErrors.Val, - "guest-wifi1-tx_errors": u.Stat.GuestWifi1TxErrors.Val, - "user-wifi1-tx_errors": u.Stat.UserWifi1TxErrors.Val, - "user-wifi0-tx_errors": u.Stat.UserWifi0TxErrors.Val, - "user-tx_errors": u.Stat.UserTxErrors.Val, - "guest-tx_errors": u.Stat.GuestTxErrors.Val, - "wifi0-tx_errors": u.Stat.Wifi0TxErrors.Val, - "wifi1-tx_errors": u.Stat.Wifi1TxErrors.Val, - "tx_errors": u.Stat.TxErrors.Val, - "guest-wifi0-tx_dropped": u.Stat.GuestWifi0TxDropped.Val, - "guest-wifi1-tx_dropped": u.Stat.GuestWifi1TxDropped.Val, - "user-wifi1-tx_dropped": u.Stat.UserWifi1TxDropped.Val, - "user-wifi0-tx_dropped": u.Stat.UserWifi0TxDropped.Val, - "user-tx_dropped": u.Stat.UserTxDropped.Val, - "guest-tx_dropped": u.Stat.GuestTxDropped.Val, - "wifi0-tx_dropped": u.Stat.Wifi0TxDropped.Val, - "wifi1-tx_dropped": u.Stat.Wifi1TxDropped.Val, - "tx_dropped": u.Stat.TxDropped.Val, - "guest-wifi0-tx_retries": u.Stat.GuestWifi0TxRetries.Val, - "guest-wifi1-tx_retries": u.Stat.GuestWifi1TxRetries.Val, - "user-wifi1-tx_retries": u.Stat.UserWifi1TxRetries.Val, - "user-wifi0-tx_retries": u.Stat.UserWifi0TxRetries.Val, - "user-tx_retries": u.Stat.UserTxRetries.Val, - "guest-tx_retries": u.Stat.GuestTxRetries.Val, - "wifi0-tx_retries": u.Stat.Wifi0TxRetries.Val, - "wifi1-tx_retries": u.Stat.Wifi1TxRetries.Val, + "ip": u.IP, + "bytes": u.Bytes.Val, + "bytes_d": u.BytesD.Val, + "bytes_r": u.BytesR.Val, + "last_seen": u.LastSeen.Val, + "rx_bytes": u.RxBytes.Val, + "rx_bytes-d": u.RxBytesD.Val, + "tx_bytes": u.TxBytes.Val, + "tx_bytes-d": u.TxBytesD.Val, + "uptime": u.Uptime.Val, + "scanning": u.Scanning.Val, + "spectrum_scanning": u.SpectrumScanning.Val, + "roll_upgrade": u.Rollupgrade.Val, + "state": u.State, + "upgradable": u.Upgradable.Val, + "user-num_sta": u.UserNumSta, + "guest-num_sta": u.GuestNumSta, + "version": u.Version, + "loadavg_1": u.SysStats.Loadavg1, + "loadavg_5": u.SysStats.Loadavg5, + "loadavg_15": u.SysStats.Loadavg15, + "mem_buffer": u.SysStats.MemBuffer.Val, + "mem_total": u.SysStats.MemTotal.Val, + "mem_used": u.SysStats.MemUsed.Val, + "cpu": u.SystemStats.CPU, + "mem": u.SystemStats.Mem, + "system_uptime": u.SystemStats.Uptime, + "stat_guest-wifi0-rx_packets": u.Stat.GuestWifi0RxPackets.Val, + "stat_guest-wifi1-rx_packets": u.Stat.GuestWifi1RxPackets.Val, + "stat_user-wifi1-rx_packets": u.Stat.UserWifi1RxPackets.Val, + "stat_user-wifi0-rx_packets": u.Stat.UserWifi0RxPackets.Val, + "stat_user-rx_packets": u.Stat.UserRxPackets.Val, + "stat_guest-rx_packets": u.Stat.GuestRxPackets.Val, + "stat_wifi0-rx_packets": u.Stat.Wifi0RxPackets.Val, + "stat_wifi1-rx_packets": u.Stat.Wifi1RxPackets.Val, + "stat_rx_packets": u.Stat.RxPackets.Val, + "stat_guest-wifi0-rx_bytes": u.Stat.GuestWifi0RxBytes.Val, + "stat_guest-wifi1-rx_bytes": u.Stat.GuestWifi1RxBytes.Val, + "stat_user-wifi1-rx_bytes": u.Stat.UserWifi1RxBytes.Val, + "stat_user-wifi0-rx_bytes": u.Stat.UserWifi0RxBytes.Val, + "stat_user-rx_bytes": u.Stat.UserRxBytes.Val, + "stat_guest-rx_bytes": u.Stat.GuestRxBytes.Val, + "stat_wifi0-rx_bytes": u.Stat.Wifi0RxBytes.Val, + "stat_wifi1-rx_bytes": u.Stat.Wifi1RxBytes.Val, + "stat_rx_bytes": u.Stat.RxBytes.Val, + "stat_guest-wifi0-rx_errors": u.Stat.GuestWifi0RxErrors.Val, + "stat_guest-wifi1-rx_errors": u.Stat.GuestWifi1RxErrors.Val, + "stat_user-wifi1-rx_errors": u.Stat.UserWifi1RxErrors.Val, + "stat_user-wifi0-rx_errors": u.Stat.UserWifi0RxErrors.Val, + "stat_user-rx_errors": u.Stat.UserRxErrors.Val, + "stat_guest-rx_errors": u.Stat.GuestRxErrors.Val, + "stat_wifi0-rx_errors": u.Stat.Wifi0RxErrors.Val, + "stat_wifi1-rx_errors": u.Stat.Wifi1RxErrors.Val, + "stat_rx_errors": u.Stat.RxErrors.Val, + "stat_guest-wifi0-rx_dropped": u.Stat.GuestWifi0RxDropped.Val, + "stat_guest-wifi1-rx_dropped": u.Stat.GuestWifi1RxDropped.Val, + "stat_user-wifi1-rx_dropped": u.Stat.UserWifi1RxDropped.Val, + "stat_user-wifi0-rx_dropped": u.Stat.UserWifi0RxDropped.Val, + "stat_user-rx_dropped": u.Stat.UserRxDropped.Val, + "stat_guest-rx_dropped": u.Stat.GuestRxDropped.Val, + "stat_wifi0-rx_dropped": u.Stat.Wifi0RxDropped.Val, + "stat_wifi1-rx_dropped": u.Stat.Wifi1RxDropped.Val, + "stat_rx_dropped": u.Stat.RxDropped.Val, + "stat_guest-wifi0-rx_crypts": u.Stat.GuestWifi0RxCrypts.Val, + "stat_guest-wifi1-rx_crypts": u.Stat.GuestWifi1RxCrypts.Val, + "stat_user-wifi1-rx_crypts": u.Stat.UserWifi1RxCrypts.Val, + "stat_user-wifi0-rx_crypts": u.Stat.UserWifi0RxCrypts.Val, + "stat_user-rx_crypts": u.Stat.UserRxCrypts.Val, + "stat_guest-rx_crypts": u.Stat.GuestRxCrypts.Val, + "stat_wifi0-rx_crypts": u.Stat.Wifi0RxCrypts.Val, + "stat_wifi1-rx_crypts": u.Stat.Wifi1RxCrypts.Val, + "stat_rx_crypts": u.Stat.RxCrypts.Val, + "stat_guest-wifi0-rx_frags": u.Stat.GuestWifi0RxFrags.Val, + "stat_guest-wifi1-rx_frags": u.Stat.GuestWifi1RxFrags.Val, + "stat_user-wifi1-rx_frags": u.Stat.UserWifi1RxFrags.Val, + "stat_user-wifi0-rx_frags": u.Stat.UserWifi0RxFrags.Val, + "stat_user-rx_frags": u.Stat.UserRxFrags.Val, + "stat_guest-rx_frags": u.Stat.GuestRxFrags.Val, + "stat_wifi0-rx_frags": u.Stat.Wifi0RxFrags.Val, + "stat_wifi1-rx_frags": u.Stat.Wifi1RxFrags.Val, + "stat_rx_frags": u.Stat.RxFrags.Val, + "stat_guest-wifi0-tx_packets": u.Stat.GuestWifi0TxPackets.Val, + "stat_guest-wifi1-tx_packets": u.Stat.GuestWifi1TxPackets.Val, + "stat_user-wifi1-tx_packets": u.Stat.UserWifi1TxPackets.Val, + "stat_user-wifi0-tx_packets": u.Stat.UserWifi0TxPackets.Val, + "stat_user-tx_packets": u.Stat.UserTxPackets.Val, + "stat_guest-tx_packets": u.Stat.GuestTxPackets.Val, + "stat_wifi0-tx_packets": u.Stat.Wifi0TxPackets.Val, + "stat_wifi1-tx_packets": u.Stat.Wifi1TxPackets.Val, + "stat_tx_packets": u.Stat.TxPackets.Val, + "stat_guest-wifi0-tx_bytes": u.Stat.GuestWifi0TxBytes.Val, + "stat_guest-wifi1-tx_bytes": u.Stat.GuestWifi1TxBytes.Val, + "stat_user-wifi1-tx_bytes": u.Stat.UserWifi1TxBytes.Val, + "stat_user-wifi0-tx_bytes": u.Stat.UserWifi0TxBytes.Val, + "stat_user-tx_bytes": u.Stat.UserTxBytes.Val, + "stat_guest-tx_bytes": u.Stat.GuestTxBytes.Val, + "stat_wifi0-tx_bytes": u.Stat.Wifi0TxBytes.Val, + "stat_wifi1-tx_bytes": u.Stat.Wifi1TxBytes.Val, + "stat_tx_bytes": u.Stat.TxBytes.Val, + "stat_guest-wifi0-tx_errors": u.Stat.GuestWifi0TxErrors.Val, + "stat_guest-wifi1-tx_errors": u.Stat.GuestWifi1TxErrors.Val, + "stat_user-wifi1-tx_errors": u.Stat.UserWifi1TxErrors.Val, + "stat_user-wifi0-tx_errors": u.Stat.UserWifi0TxErrors.Val, + "stat_user-tx_errors": u.Stat.UserTxErrors.Val, + "stat_guest-tx_errors": u.Stat.GuestTxErrors.Val, + "stat_wifi0-tx_errors": u.Stat.Wifi0TxErrors.Val, + "stat_wifi1-tx_errors": u.Stat.Wifi1TxErrors.Val, + "stat_tx_errors": u.Stat.TxErrors.Val, + "stat_guest-wifi0-tx_dropped": u.Stat.GuestWifi0TxDropped.Val, + "stat_guest-wifi1-tx_dropped": u.Stat.GuestWifi1TxDropped.Val, + "stat_user-wifi1-tx_dropped": u.Stat.UserWifi1TxDropped.Val, + "stat_user-wifi0-tx_dropped": u.Stat.UserWifi0TxDropped.Val, + "stat_user-tx_dropped": u.Stat.UserTxDropped.Val, + "stat_guest-tx_dropped": u.Stat.GuestTxDropped.Val, + "stat_wifi0-tx_dropped": u.Stat.Wifi0TxDropped.Val, + "stat_wifi1-tx_dropped": u.Stat.Wifi1TxDropped.Val, + "stat_tx_dropped": u.Stat.TxDropped.Val, + "stat_guest-wifi0-tx_retries": u.Stat.GuestWifi0TxRetries.Val, + "stat_guest-wifi1-tx_retries": u.Stat.GuestWifi1TxRetries.Val, + "stat_user-wifi1-tx_retries": u.Stat.UserWifi1TxRetries.Val, + "stat_user-wifi0-tx_retries": u.Stat.UserWifi0TxRetries.Val, + "stat_user-tx_retries": u.Stat.UserTxRetries.Val, + "stat_guest-tx_retries": u.Stat.GuestTxRetries.Val, + "stat_wifi0-tx_retries": u.Stat.Wifi0TxRetries.Val, + "stat_wifi1-tx_retries": u.Stat.Wifi1TxRetries.Val, } pt, err := influx.NewPoint("uap", tags, fields, time.Now()) if err != nil { From 565367d958a54ccb87072bb310180a7cdddba813 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Fri, 5 Jul 2019 01:27:28 -0700 Subject: [PATCH 071/194] Make USW better. --- core/unifi/uap_influx.go | 8 +- core/unifi/usw_influx.go | 97 +++--- core/unifi/usw_type.go | 708 ++++++++++++++++++--------------------- 3 files changed, 379 insertions(+), 434 deletions(-) diff --git a/core/unifi/uap_influx.go b/core/unifi/uap_influx.go index a5731e19..d5b3bf63 100644 --- a/core/unifi/uap_influx.go +++ b/core/unifi/uap_influx.go @@ -169,7 +169,8 @@ func (u UAP) Points() ([]*influx.Point, error) { tags = make(map[string]string) fields = make(map[string]interface{}) - // Loop each virtual AP (ESSID) and extract data for it from radio_tables and radio_table_stats. + // Loop each virtual AP (ESSID) and extract data for it + // from radio_tables and radio_table_stats. for _, s := range u.VapTable { tags["device_name"] = u.Name tags["device_id"] = u.ID @@ -226,6 +227,7 @@ func (u UAP) Points() ([]*influx.Point, error) { fields["wifi_tx_latency_mov_min"] = s.WifiTxLatencyMov.Min.Val fields["wifi_tx_latency_mov_total"] = s.WifiTxLatencyMov.Total.Val fields["wifi_tx_latency_mov_cuont"] = s.WifiTxLatencyMov.TotalCount.Val + for _, p := range u.RadioTable { if p.Name != s.RadioName { continue @@ -242,9 +244,8 @@ func (u UAP) Points() ([]*influx.Point, error) { fields["radio_caps"] = p.RadioCaps.Val fields["tx_power"] = p.TxPower.Val } + for _, p := range u.RadioTableStats { - // This may be a tad slower but it allows putting - // all the radio stats into one table. if p.Name != s.RadioName { continue } @@ -263,6 +264,7 @@ func (u UAP) Points() ([]*influx.Point, error) { fields["tx_retries"] = p.TxRetries.Val fields["user-num_sta"] = p.UserNumSta.Val } + pt, err := influx.NewPoint("uap_vaps", tags, fields, time.Now()) if err != nil { return points, err diff --git a/core/unifi/usw_influx.go b/core/unifi/usw_influx.go index 505812ee..a48a8e3e 100644 --- a/core/unifi/usw_influx.go +++ b/core/unifi/usw_influx.go @@ -18,16 +18,10 @@ func (u USW) Points() ([]*influx.Point, error) { "site_name": u.SiteName, "name": u.Name, "adopted": u.Adopted.Txt, - "adopt_ip": u.AdoptIP, - "adopt_url": u.AdoptURL, "cfgversion": u.Cfgversion, "config_network_ip": u.ConfigNetwork.IP, "config_network_type": u.ConfigNetwork.Type, - "connect_request_ip": u.ConnectRequestIP, - "connect_request_port": u.ConnectRequestPort, - "default": u.Default.Txt, "device_id": u.DeviceID, - "discovered_via": u.DiscoveredVia, "inform_ip": u.InformIP, "last_uplink_mac": u.LastUplink.UplinkMac, "known_cfgversion": u.KnownCfgversion, @@ -37,7 +31,6 @@ func (u USW) Points() ([]*influx.Point, error) { "outdoor_mode_override": u.OutdoorModeOverride, "serial": u.Serial, "type": u.Type, - "version_incompatible": u.VersionIncompatible.Txt, "dot1x_portctrl_enabled": u.Dot1XPortctrlEnabled.Txt, "flowctrl_enabled": u.FlowctrlEnabled.Txt, "has_fan": u.HasFan.Txt, @@ -47,58 +40,56 @@ func (u USW) Points() ([]*influx.Point, error) { "stp_version": u.StpVersion, } fields := map[string]interface{}{ - "fw_caps": u.FwCaps, - "guest-num_sta": u.GuestNumSta, + "fw_caps": u.FwCaps.Val, + "guest-num_sta": u.GuestNumSta.Val, "ip": u.IP, - "bytes": u.Bytes, - "fan_level": u.FanLevel, - "general_temperature": u.GeneralTemperature, - "last_seen": u.LastSeen, + "bytes": u.Bytes.Val, + "fan_level": u.FanLevel.Val, + "general_temperature": u.GeneralTemperature.Val, + "last_seen": u.LastSeen.Val, "license_state": u.LicenseState, "overheating": u.Overheating.Val, - "rx_bytes": u.RxBytes, - "tx_bytes": u.TxBytes, - "uptime": u.Uptime, - "considered_lost_at": u.ConsideredLostAt, - "next_heartbeat_at": u.NextHeartbeatAt, + "rx_bytes": u.RxBytes.Val, + "tx_bytes": u.TxBytes.Val, + "uptime": u.Uptime.Val, "roll_upgrade": u.Rollupgrade.Val, - "state": u.State, + "state": u.State.Val, "upgradable": u.Upgradable.Val, - "user-num_sta": u.UserNumSta, + "user-num_sta": u.UserNumSta.Val, "version": u.Version, - "loadavg_1": u.SysStats.Loadavg1, - "loadavg_5": u.SysStats.Loadavg5, - "loadavg_15": u.SysStats.Loadavg15, - "mem_buffer": u.SysStats.MemBuffer, - "mem_used": u.SysStats.MemUsed, - "mem_total": u.SysStats.MemTotal, - "cpu": u.SystemStats.CPU, - "mem": u.SystemStats.Mem, - "system_uptime": u.SystemStats.Uptime, - "stat_bytes": u.Stat.Bytes, - "stat_duration": u.Stat.Duration, - "stat_guest-rx_bytes": u.Stat.RxBytes, - "stat_guest-rx_crypts": u.Stat.RxCrypts, - "stat_guest-rx_dropped": u.Stat.RxDropped, - "stat_guest-rx_errors": u.Stat.RxErrors, - "stat_guest-rx_frags": u.Stat.RxFrags, - "stat_guest-rx_packets": u.Stat.RxPackets, - "stat_guest-tx_bytes": u.Stat.TxBytes, - "stat_guest-tx_dropped": u.Stat.TxDropped, - "stat_guest-tx_errors": u.Stat.TxErrors, - "stat_guest-tx_packets": u.Stat.TxPackets, - "stat_guest-tx_retries": u.Stat.TxRetries, - "stat_rx_bytes": u.Stat.RxBytes, - "stat_rx_crypts": u.Stat.RxCrypts, - "stat_rx_dropped": u.Stat.RxDropped, - "stat_rx_errors": u.Stat.RxErrors, - "stat_rx_frags": u.Stat.RxFrags, - "stat_rx_packets": u.Stat.TxPackets, - "stat_tx_bytes": u.Stat.TxBytes, - "stat_tx_dropped": u.Stat.TxDropped, - "stat_tx_errors": u.Stat.TxErrors, - "stat_tx_packets": u.Stat.TxPackets, - "stat_tx_retries": u.Stat.TxRetries, + "loadavg_1": u.SysStats.Loadavg1.Val, + "loadavg_5": u.SysStats.Loadavg5.Val, + "loadavg_15": u.SysStats.Loadavg15.Val, + "mem_buffer": u.SysStats.MemBuffer.Val, + "mem_used": u.SysStats.MemUsed.Val, + "mem_total": u.SysStats.MemTotal.Val, + "cpu": u.SystemStats.CPU.Val, + "mem": u.SystemStats.Mem.Val, + "system_uptime": u.SystemStats.Uptime.Val, + "stat_bytes": u.Stat.Bytes.Val, + "stat_duration": u.Stat.Duration.Val, + "stat_guest-rx_bytes": u.Stat.RxBytes.Val, + "stat_guest-rx_crypts": u.Stat.RxCrypts.Val, + "stat_guest-rx_dropped": u.Stat.RxDropped.Val, + "stat_guest-rx_errors": u.Stat.RxErrors.Val, + "stat_guest-rx_frags": u.Stat.RxFrags.Val, + "stat_guest-rx_packets": u.Stat.RxPackets.Val, + "stat_guest-tx_bytes": u.Stat.TxBytes.Val, + "stat_guest-tx_dropped": u.Stat.TxDropped.Val, + "stat_guest-tx_errors": u.Stat.TxErrors.Val, + "stat_guest-tx_packets": u.Stat.TxPackets.Val, + "stat_guest-tx_retries": u.Stat.TxRetries.Val, + "stat_rx_bytes": u.Stat.RxBytes.Val, + "stat_rx_crypts": u.Stat.RxCrypts.Val, + "stat_rx_dropped": u.Stat.RxDropped.Val, + "stat_rx_errors": u.Stat.RxErrors.Val, + "stat_rx_frags": u.Stat.RxFrags.Val, + "stat_rx_packets": u.Stat.TxPackets.Val, + "stat_tx_bytes": u.Stat.TxBytes.Val, + "stat_tx_dropped": u.Stat.TxDropped.Val, + "stat_tx_errors": u.Stat.TxErrors.Val, + "stat_tx_packets": u.Stat.TxPackets.Val, + "stat_tx_retries": u.Stat.TxRetries.Val, "uplink_depth": u.UplinkDepth.Txt, // Add the port stats too. } diff --git a/core/unifi/usw_type.go b/core/unifi/usw_type.go index c912f5d2..c2dc14ad 100644 --- a/core/unifi/usw_type.go +++ b/core/unifi/usw_type.go @@ -1,416 +1,368 @@ package unifi +import "time" + // USW represents all the data from the Ubiquiti Controller for a Unifi Switch. type USW struct { + SiteName string `json:"-"` ID string `json:"_id"` - UUptime float64 `json:"_uptime"` - AdoptIP string `json:"adopt_ip"` - AdoptURL string `json:"adopt_url"` Adopted FlexBool `json:"adopted"` - BoardRev float64 `json:"board_rev"` - Bytes float64 `json:"bytes"` + BoardRev FlexInt `json:"board_rev"` Cfgversion string `json:"cfgversion"` ConfigNetwork struct { - IP string `json:"ip"` Type string `json:"type"` + IP string `json:"ip"` } `json:"config_network"` - ConnectRequestIP string `json:"connect_request_ip"` - ConnectRequestPort string `json:"connect_request_port"` - ConsideredLostAt float64 `json:"considered_lost_at"` - Default FlexBool `json:"default"` - DeviceID string `json:"device_id"` - DhcpServerTable []interface{} `json:"dhcp_server_table"` - DiscoveredVia string `json:"discovered_via"` - Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"` - DownlinkTable []struct { - FullDuplex FlexBool `json:"full_duplex"` - Mac string `json:"mac"` - PortIdx float64 `json:"port_idx"` - Speed float64 `json:"speed"` - } `json:"downlink_table"` - EthernetTable []struct { + Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"` + EthernetTable []struct { Mac string `json:"mac"` + NumPort FlexInt `json:"num_port,omitempty"` Name string `json:"name"` - NumPort float64 `json:"num_port,omitempty"` } `json:"ethernet_table"` - FanLevel float64 `json:"fan_level"` - FlowctrlEnabled FlexBool `json:"flowctrl_enabled"` - FwCaps float64 `json:"fw_caps"` - GeneralTemperature float64 `json:"general_temperature"` - GuestNumSta float64 `json:"guest-num_sta"` - HasFan FlexBool `json:"has_fan"` - HasTemperature FlexBool `json:"has_temperature"` - InformIP string `json:"inform_ip"` - InformURL string `json:"inform_url"` - IP string `json:"ip"` - JumboframeEnabled FlexBool `json:"jumboframe_enabled"` - KnownCfgversion string `json:"known_cfgversion"` - LastSeen float64 `json:"last_seen"` - LastUplink struct { - UplinkMac string `json:"uplink_mac"` - } `json:"last_uplink"` + FlowctrlEnabled FlexBool `json:"flowctrl_enabled"` + FwCaps FlexInt `json:"fw_caps"` + HasFan FlexBool `json:"has_fan"` + HasTemperature FlexBool `json:"has_temperature"` + InformIP string `json:"inform_ip"` + InformURL string `json:"inform_url"` + IP string `json:"ip"` + JumboframeEnabled FlexBool `json:"jumboframe_enabled"` LedOverride string `json:"led_override"` LicenseState string `json:"license_state"` - Locating FlexBool `json:"locating"` Mac string `json:"mac"` Model string `json:"model"` Name string `json:"name"` - NextHeartbeatAt float64 `json:"next_heartbeat_at"` - NumSta float64 `json:"num_sta"` OutdoorModeOverride string `json:"outdoor_mode_override"` - Overheating FlexBool `json:"overheating"` PortOverrides []struct { Name string `json:"name,omitempty"` PoeMode string `json:"poe_mode,omitempty"` - PortIdx float64 `json:"port_idx"` + PortIdx FlexInt `json:"port_idx"` PortconfID string `json:"portconf_id"` } `json:"port_overrides"` PortTable []struct { - AggregatedBy FlexBool `json:"aggregated_by"` - Autoneg FlexBool `json:"autoneg"` - BytesR FlexInt `json:"bytes-r"` - Dot1XMode string `json:"dot1x_mode"` - Dot1XStatus string `json:"dot1x_status"` - Enable FlexBool `json:"enable"` - FlowctrlRx FlexBool `json:"flowctrl_rx"` - FlowctrlTx FlexBool `json:"flowctrl_tx"` - FullDuplex FlexBool `json:"full_duplex"` - IsUplink FlexBool `json:"is_uplink"` - Jumbo FlexBool `json:"jumbo"` - LldpTable []interface{} `json:"lldp_table"` - Masked FlexBool `json:"masked"` - Media string `json:"media"` - Name string `json:"name"` - OpMode string `json:"op_mode"` - PoeCaps FlexInt `json:"poe_caps"` - PoeClass string `json:"poe_class,omitempty"` - PoeCurrent FlexInt `json:"poe_current,omitempty"` - PoeEnable FlexBool `json:"poe_enable,omitempty"` - PoeGood FlexBool `json:"poe_good,omitempty"` - PoeMode string `json:"poe_mode,omitempty"` - PoePower FlexInt `json:"poe_power,omitempty"` - PoeVoltage FlexInt `json:"poe_voltage,omitempty"` - PortIdx FlexInt `json:"port_idx"` - PortPoe FlexBool `json:"port_poe"` - PortconfID string `json:"portconf_id"` - RxBroadcast FlexInt `json:"rx_broadcast"` - RxBytes FlexInt `json:"rx_bytes"` - RxBytesR FlexInt `json:"rx_bytes-r"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxMulticast FlexInt `json:"rx_multicast"` - RxPackets FlexInt `json:"rx_packets"` - Speed FlexInt `json:"speed"` - StpPathcost FlexInt `json:"stp_pathcost"` - StpState string `json:"stp_state"` - TxBroadcast FlexInt `json:"tx_broadcast"` - TxBytes FlexInt `json:"tx_bytes"` - TxBytesR FlexInt `json:"tx_bytes-r"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxMulticast FlexInt `json:"tx_multicast"` - TxPackets FlexInt `json:"tx_packets"` - Up FlexBool `json:"up"` - SfpFound FlexBool `json:"sfp_found,omitempty"` + PortIdx FlexInt `json:"port_idx"` + Media string `json:"media"` + PortPoe FlexBool `json:"port_poe"` + PoeCaps FlexInt `json:"poe_caps"` + SpeedCaps FlexInt `json:"speed_caps"` + OpMode string `json:"op_mode"` + PortconfID string `json:"portconf_id"` + PoeMode string `json:"poe_mode,omitempty"` + Autoneg FlexBool `json:"autoneg"` + Dot1XMode string `json:"dot1x_mode"` + Dot1XStatus string `json:"dot1x_status"` + Enable FlexBool `json:"enable"` + FlowctrlRx FlexBool `json:"flowctrl_rx"` + FlowctrlTx FlexBool `json:"flowctrl_tx"` + FullDuplex FlexBool `json:"full_duplex"` + IsUplink FlexBool `json:"is_uplink"` + Jumbo FlexBool `json:"jumbo"` + PoeClass string `json:"poe_class,omitempty"` + PoeCurrent FlexInt `json:"poe_current,omitempty"` + PoeEnable FlexBool `json:"poe_enable,omitempty"` + PoeGood FlexBool `json:"poe_good,omitempty"` + PoePower FlexInt `json:"poe_power,omitempty"` + PoeVoltage FlexInt `json:"poe_voltage,omitempty"` + RxBroadcast FlexInt `json:"rx_broadcast"` + RxBytes FlexInt `json:"rx_bytes"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxMulticast FlexInt `json:"rx_multicast"` + RxPackets FlexInt `json:"rx_packets"` + Satisfaction FlexInt `json:"satisfaction"` + Speed FlexInt `json:"speed"` + StpPathcost FlexInt `json:"stp_pathcost"` + StpState string `json:"stp_state"` + TxBroadcast FlexInt `json:"tx_broadcast"` + TxBytes FlexInt `json:"tx_bytes"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxMulticast FlexInt `json:"tx_multicast"` + TxPackets FlexInt `json:"tx_packets"` + Up FlexBool `json:"up"` + TxBytesR FlexInt `json:"tx_bytes-r"` + RxBytesR FlexInt `json:"rx_bytes-r"` + BytesR FlexInt `json:"bytes-r"` + Name string `json:"name"` + Masked FlexBool `json:"masked"` + AggregatedBy FlexBool `json:"aggregated_by"` + SfpFound FlexBool `json:"sfp_found,omitempty"` } `json:"port_table"` - Rollupgrade FlexBool `json:"rollupgrade"` - RxBytes float64 `json:"rx_bytes"` - Serial string `json:"serial"` - SiteID string `json:"site_id"` - SiteName string `json:"-"` - SSHSessionTable []interface{} `json:"ssh_session_table"` - - Stat struct { - Bytes float64 `json:"bytes"` - Datetime string `json:"datetime"` - Duration float64 `json:"duration"` - O string `json:"o"` - Oid string `json:"oid"` - Port1RxBroadcast float64 `json:"port_1-rx_broadcast"` - Port1RxBytes float64 `json:"port_1-rx_bytes"` - Port1RxDropped float64 `json:"port_1-rx_dropped"` - Port1RxMulticast float64 `json:"port_1-rx_multicast"` - Port1RxPackets float64 `json:"port_1-rx_packets"` - Port1TxBroadcast float64 `json:"port_1-tx_broadcast"` - Port1TxBytes float64 `json:"port_1-tx_bytes"` - Port1TxMulticast float64 `json:"port_1-tx_multicast"` - Port1TxPackets float64 `json:"port_1-tx_packets"` - Port2RxBroadcast float64 `json:"port_2-rx_broadcast"` - Port2RxBytes float64 `json:"port_2-rx_bytes"` - Port2RxDropped float64 `json:"port_2-rx_dropped"` - Port2RxMulticast float64 `json:"port_2-rx_multicast"` - Port2RxPackets float64 `json:"port_2-rx_packets"` - Port2TxBroadcast float64 `json:"port_2-tx_broadcast"` - Port2TxBytes float64 `json:"port_2-tx_bytes"` - Port2TxMulticast float64 `json:"port_2-tx_multicast"` - Port2TxPackets float64 `json:"port_2-tx_packets"` - Port3RxBroadcast float64 `json:"port_3-rx_broadcast"` - Port3RxBytes float64 `json:"port_3-rx_bytes"` - Port3RxDropped float64 `json:"port_3-rx_dropped"` - Port3RxMulticast float64 `json:"port_3-rx_multicast"` - Port3RxPackets float64 `json:"port_3-rx_packets"` - Port3TxBroadcast float64 `json:"port_3-tx_broadcast"` - Port3TxBytes float64 `json:"port_3-tx_bytes"` - Port3TxMulticast float64 `json:"port_3-tx_multicast"` - Port3TxPackets float64 `json:"port_3-tx_packets"` - Port4RxBroadcast float64 `json:"port_4-rx_broadcast"` - Port4RxBytes float64 `json:"port_4-rx_bytes"` - Port4RxDropped float64 `json:"port_4-rx_dropped"` - Port4RxMulticast float64 `json:"port_4-rx_multicast"` - Port4RxPackets float64 `json:"port_4-rx_packets"` - Port4TxBroadcast float64 `json:"port_4-tx_broadcast"` - Port4TxBytes float64 `json:"port_4-tx_bytes"` - Port4TxMulticast float64 `json:"port_4-tx_multicast"` - Port4TxPackets float64 `json:"port_4-tx_packets"` - Port5RxBroadcast float64 `json:"port_5-rx_broadcast"` - Port5RxBytes float64 `json:"port_5-rx_bytes"` - Port5RxDropped float64 `json:"port_5-rx_dropped"` - Port5RxMulticast float64 `json:"port_5-rx_multicast"` - Port5RxPackets float64 `json:"port_5-rx_packets"` - Port5TxBroadcast float64 `json:"port_5-tx_broadcast"` - Port5TxBytes float64 `json:"port_5-tx_bytes"` - Port5TxMulticast float64 `json:"port_5-tx_multicast"` - Port5TxPackets float64 `json:"port_5-tx_packets"` - Port6RxBroadcast float64 `json:"port_6-rx_broadcast"` - Port6RxBytes float64 `json:"port_6-rx_bytes"` - Port6RxDropped float64 `json:"port_6-rx_dropped"` - Port6RxMulticast float64 `json:"port_6-rx_multicast"` - Port6RxPackets float64 `json:"port_6-rx_packets"` - Port6TxBroadcast float64 `json:"port_6-tx_broadcast"` - Port6TxBytes float64 `json:"port_6-tx_bytes"` - Port6TxMulticast float64 `json:"port_6-tx_multicast"` - Port6TxPackets float64 `json:"port_6-tx_packets"` - Port7RxBroadcast float64 `json:"port_7-rx_broadcast"` - Port7RxBytes float64 `json:"port_7-rx_bytes"` - Port7RxDropped float64 `json:"port_7-rx_dropped"` - Port7RxMulticast float64 `json:"port_7-rx_multicast"` - Port7RxPackets float64 `json:"port_7-rx_packets"` - Port7TxBroadcast float64 `json:"port_7-tx_broadcast"` - Port7TxBytes float64 `json:"port_7-tx_bytes"` - Port7TxMulticast float64 `json:"port_7-tx_multicast"` - Port7TxPackets float64 `json:"port_7-tx_packets"` - Port8RxBroadcast float64 `json:"port_8-rx_broadcast"` - Port8RxBytes float64 `json:"port_8-rx_bytes"` - Port8RxDropped float64 `json:"port_8-rx_dropped"` - Port8RxMulticast float64 `json:"port_8-rx_multicast"` - Port8RxPackets float64 `json:"port_8-rx_packets"` - Port8TxBroadcast float64 `json:"port_8-tx_broadcast"` - Port8TxBytes float64 `json:"port_8-tx_bytes"` - Port8TxMulticast float64 `json:"port_8-tx_multicast"` - Port8TxPackets float64 `json:"port_8-tx_packets"` - Port9RxBroadcast float64 `json:"port_9-rx_broadcast"` - Port9RxBytes float64 `json:"port_9-rx_bytes"` - Port9RxDropped float64 `json:"port_9-rx_dropped"` - Port9RxMulticast float64 `json:"port_9-rx_multicast"` - Port9RxPackets float64 `json:"port_9-rx_packets"` - Port9TxBroadcast float64 `json:"port_9-tx_broadcast"` - Port9TxBytes float64 `json:"port_9-tx_bytes"` - Port9TxMulticast float64 `json:"port_9-tx_multicast"` - Port9TxPackets float64 `json:"port_9-tx_packets"` - Port10RxBroadcast float64 `json:"port_10-rx_broadcast"` - Port10RxBytes float64 `json:"port_10-rx_bytes"` - Port10RxDropped float64 `json:"port_10-rx_dropped"` - Port10RxMulticast float64 `json:"port_10-rx_multicast"` - Port10RxPackets float64 `json:"port_10-rx_packets"` - Port10TxBroadcast float64 `json:"port_10-tx_broadcast"` - Port10TxBytes float64 `json:"port_10-tx_bytes"` - Port10TxMulticast float64 `json:"port_10-tx_multicast"` - Port10TxPackets float64 `json:"port_10-tx_packets"` - Port11RxBroadcast float64 `json:"port_11-rx_broadcast"` - Port11RxBytes float64 `json:"port_11-rx_bytes"` - Port11RxDropped float64 `json:"port_11-rx_dropped"` - Port11RxMulticast float64 `json:"port_11-rx_multicast"` - Port11RxPackets float64 `json:"port_11-rx_packets"` - Port11TxBroadcast float64 `json:"port_11-tx_broadcast"` - Port11TxBytes float64 `json:"port_11-tx_bytes"` - Port11TxMulticast float64 `json:"port_11-tx_multicast"` - Port11TxPackets float64 `json:"port_11-tx_packets"` - Port12RxBroadcast float64 `json:"port_12-rx_broadcast"` - Port12RxBytes float64 `json:"port_12-rx_bytes"` - Port12RxDropped float64 `json:"port_12-rx_dropped"` - Port12RxMulticast float64 `json:"port_12-rx_multicast"` - Port12RxPackets float64 `json:"port_12-rx_packets"` - Port12TxBroadcast float64 `json:"port_12-tx_broadcast"` - Port12TxBytes float64 `json:"port_12-tx_bytes"` - Port12TxMulticast float64 `json:"port_12-tx_multicast"` - Port12TxPackets float64 `json:"port_12-tx_packets"` - Port13RxBroadcast float64 `json:"port_13-rx_broadcast"` - Port13RxBytes float64 `json:"port_13-rx_bytes"` - Port13RxDropped float64 `json:"port_13-rx_dropped"` - Port13RxMulticast float64 `json:"port_13-rx_multicast"` - Port13RxPackets float64 `json:"port_13-rx_packets"` - Port13TxBroadcast float64 `json:"port_13-tx_broadcast"` - Port13TxBytes float64 `json:"port_13-tx_bytes"` - Port13TxMulticast float64 `json:"port_13-tx_multicast"` - Port13TxPackets float64 `json:"port_13-tx_packets"` - Port14RxBroadcast float64 `json:"port_14-rx_broadcast"` - Port14RxBytes float64 `json:"port_14-rx_bytes"` - Port14RxDropped float64 `json:"port_14-rx_dropped"` - Port14RxMulticast float64 `json:"port_14-rx_multicast"` - Port14RxPackets float64 `json:"port_14-rx_packets"` - Port14TxBroadcast float64 `json:"port_14-tx_broadcast"` - Port14TxBytes float64 `json:"port_14-tx_bytes"` - Port14TxMulticast float64 `json:"port_14-tx_multicast"` - Port14TxPackets float64 `json:"port_14-tx_packets"` - Port15RxBroadcast float64 `json:"port_15-rx_broadcast"` - Port15RxBytes float64 `json:"port_15-rx_bytes"` - Port15RxDropped float64 `json:"port_15-rx_dropped"` - Port15RxMulticast float64 `json:"port_15-rx_multicast"` - Port15RxPackets float64 `json:"port_15-rx_packets"` - Port15TxBroadcast float64 `json:"port_15-tx_broadcast"` - Port15TxBytes float64 `json:"port_15-tx_bytes"` - Port15TxMulticast float64 `json:"port_15-tx_multicast"` - Port15TxPackets float64 `json:"port_15-tx_packets"` - Port16RxBroadcast float64 `json:"port_16-rx_broadcast"` - Port16RxBytes float64 `json:"port_16-rx_bytes"` - Port16RxDropped float64 `json:"port_16-rx_dropped"` - Port16RxMulticast float64 `json:"port_16-rx_multicast"` - Port16RxPackets float64 `json:"port_16-rx_packets"` - Port16TxBroadcast float64 `json:"port_16-tx_broadcast"` - Port16TxBytes float64 `json:"port_16-tx_bytes"` - Port16TxMulticast float64 `json:"port_16-tx_multicast"` - Port16TxPackets float64 `json:"port_16-tx_packets"` - Port17RxBroadcast float64 `json:"port_17-rx_broadcast"` - Port17RxBytes float64 `json:"port_17-rx_bytes"` - Port17RxDropped float64 `json:"port_17-rx_dropped"` - Port17RxMulticast float64 `json:"port_17-rx_multicast"` - Port17RxPackets float64 `json:"port_17-rx_packets"` - Port17TxBroadcast float64 `json:"port_17-tx_broadcast"` - Port17TxBytes float64 `json:"port_17-tx_bytes"` - Port17TxMulticast float64 `json:"port_17-tx_multicast"` - Port17TxPackets float64 `json:"port_17-tx_packets"` - Port18RxBroadcast float64 `json:"port_18-rx_broadcast"` - Port18RxBytes float64 `json:"port_18-rx_bytes"` - Port18RxDropped float64 `json:"port_18-rx_dropped"` - Port18RxMulticast float64 `json:"port_18-rx_multicast"` - Port18RxPackets float64 `json:"port_18-rx_packets"` - Port18TxBroadcast float64 `json:"port_18-tx_broadcast"` - Port18TxBytes float64 `json:"port_18-tx_bytes"` - Port18TxMulticast float64 `json:"port_18-tx_multicast"` - Port18TxPackets float64 `json:"port_18-tx_packets"` - Port19RxBroadcast float64 `json:"port_19-rx_broadcast"` - Port19RxBytes float64 `json:"port_19-rx_bytes"` - Port19RxDropped float64 `json:"port_19-rx_dropped"` - Port19RxMulticast float64 `json:"port_19-rx_multicast"` - Port19RxPackets float64 `json:"port_19-rx_packets"` - Port19TxBroadcast float64 `json:"port_19-tx_broadcast"` - Port19TxBytes float64 `json:"port_19-tx_bytes"` - Port19TxMulticast float64 `json:"port_19-tx_multicast"` - Port19TxPackets float64 `json:"port_19-tx_packets"` - Port20RxBroadcast float64 `json:"port_20-rx_broadcast"` - Port20RxBytes float64 `json:"port_20-rx_bytes"` - Port20RxDropped float64 `json:"port_20-rx_dropped"` - Port20RxMulticast float64 `json:"port_20-rx_multicast"` - Port20RxPackets float64 `json:"port_20-rx_packets"` - Port20TxBroadcast float64 `json:"port_20-tx_broadcast"` - Port20TxBytes float64 `json:"port_20-tx_bytes"` - Port20TxMulticast float64 `json:"port_20-tx_multicast"` - Port20TxPackets float64 `json:"port_20-tx_packets"` - Port21RxBroadcast float64 `json:"port_21-rx_broadcast"` - Port21RxBytes float64 `json:"port_21-rx_bytes"` - Port21RxDropped float64 `json:"port_21-rx_dropped"` - Port21RxMulticast float64 `json:"port_21-rx_multicast"` - Port21RxPackets float64 `json:"port_21-rx_packets"` - Port21TxBroadcast float64 `json:"port_21-tx_broadcast"` - Port21TxBytes float64 `json:"port_21-tx_bytes"` - Port21TxMulticast float64 `json:"port_21-tx_multicast"` - Port21TxPackets float64 `json:"port_21-tx_packets"` - Port22RxBroadcast float64 `json:"port_22-rx_broadcast"` - Port22RxBytes float64 `json:"port_22-rx_bytes"` - Port22RxDropped float64 `json:"port_22-rx_dropped"` - Port22RxMulticast float64 `json:"port_22-rx_multicast"` - Port22RxPackets float64 `json:"port_22-rx_packets"` - Port22TxBroadcast float64 `json:"port_22-tx_broadcast"` - Port22TxBytes float64 `json:"port_22-tx_bytes"` - Port22TxMulticast float64 `json:"port_22-tx_multicast"` - Port22TxPackets float64 `json:"port_22-tx_packets"` - Port23RxBroadcast float64 `json:"port_23-rx_broadcast"` - Port23RxBytes float64 `json:"port_23-rx_bytes"` - Port23RxDropped float64 `json:"port_23-rx_dropped"` - Port23RxMulticast float64 `json:"port_23-rx_multicast"` - Port23RxPackets float64 `json:"port_23-rx_packets"` - Port23TxBroadcast float64 `json:"port_23-tx_broadcast"` - Port23TxBytes float64 `json:"port_23-tx_bytes"` - Port23TxMulticast float64 `json:"port_23-tx_multicast"` - Port23TxPackets float64 `json:"port_23-tx_packets"` - Port24RxBroadcast float64 `json:"port_24-rx_broadcast"` - Port24RxBytes float64 `json:"port_24-rx_bytes"` - Port24RxDropped float64 `json:"port_24-rx_dropped"` - Port24RxMulticast float64 `json:"port_24-rx_multicast"` - Port24RxPackets float64 `json:"port_24-rx_packets"` - Port24TxBroadcast float64 `json:"port_24-tx_broadcast"` - Port24TxBytes float64 `json:"port_24-tx_bytes"` - Port24TxMulticast float64 `json:"port_24-tx_multicast"` - Port24TxPackets float64 `json:"port_24-tx_packets"` - // Have a 48 port switch? How 'bout a pull request. :D - RxBroadcast float64 `json:"rx_broadcast"` - RxBytes float64 `json:"rx_bytes"` - RxCrypts float64 `json:"rx_crypts"` - RxDropped float64 `json:"rx_dropped"` - RxErrors float64 `json:"rx_errors"` - RxFrags float64 `json:"rx_frags"` - RxMulticast float64 `json:"rx_multicast"` - RxPackets float64 `json:"rx_packets"` - SiteID string `json:"site_id"` - Sw string `json:"sw"` - Time float64 `json:"time"` - TxBroadcast float64 `json:"tx_broadcast"` - TxBytes float64 `json:"tx_bytes"` - TxDropped float64 `json:"tx_dropped"` - TxErrors float64 `json:"tx_errors"` - TxMulticast float64 `json:"tx_multicast"` - TxPackets float64 `json:"tx_packets"` - TxRetries float64 `json:"tx_retries"` - } `json:"stat"` - - State float64 `json:"state"` - StpPriority string `json:"stp_priority"` - StpVersion string `json:"stp_version"` - SysStats struct { - Loadavg1 float64 `json:"loadavg_1,string"` - Loadavg15 float64 `json:"loadavg_15,string"` - Loadavg5 float64 `json:"loadavg_5,string"` - MemBuffer float64 `json:"mem_buffer"` - MemTotal float64 `json:"mem_total"` - MemUsed float64 `json:"mem_used"` + Serial string `json:"serial"` + SiteID string `json:"site_id"` + StpPriority string `json:"stp_priority"` + StpVersion string `json:"stp_version"` + Type string `json:"type"` + Version string `json:"version"` + RequiredVersion string `json:"required_version"` + SwitchCaps struct { + FeatureCaps FlexInt `json:"feature_caps"` + MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` + MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` + } `json:"switch_caps"` + HwCaps FlexInt `json:"hw_caps"` + Unsupported FlexBool `json:"unsupported"` + UnsupportedReason FlexInt `json:"unsupported_reason"` + SysErrorCaps FlexInt `json:"sys_error_caps"` + DeviceID string `json:"device_id"` + State FlexInt `json:"state"` + LastSeen FlexInt `json:"last_seen"` + Upgradable FlexBool `json:"upgradable"` + AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` + Rollupgrade FlexBool `json:"rollupgrade"` + KnownCfgversion string `json:"known_cfgversion"` + Uptime FlexInt `json:"uptime"` + Locating FlexBool `json:"locating"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + SysStats struct { + Loadavg1 FlexInt `json:"loadavg_1"` + Loadavg15 FlexInt `json:"loadavg_15"` + Loadavg5 FlexInt `json:"loadavg_5"` + MemBuffer FlexInt `json:"mem_buffer"` + MemTotal FlexInt `json:"mem_total"` + MemUsed FlexInt `json:"mem_used"` } `json:"sys_stats"` SystemStats struct { - CPU float64 `json:"cpu,string"` - Mem float64 `json:"mem,string"` - Uptime float64 `json:"uptime,string"` + CPU FlexInt `json:"cpu"` + Mem FlexInt `json:"mem"` + Uptime FlexInt `json:"uptime"` } `json:"system-stats"` - TxBytes float64 `json:"tx_bytes"` - Type string `json:"type"` - Upgradable FlexBool `json:"upgradable"` - Uplink struct { + FanLevel FlexInt `json:"fan_level"` + GeneralTemperature FlexInt `json:"general_temperature"` + Overheating FlexBool `json:"overheating"` + TotalMaxPower FlexInt `json:"total_max_power"` + DownlinkTable []struct { + PortIdx FlexInt `json:"port_idx"` + Speed FlexInt `json:"speed"` + FullDuplex FlexBool `json:"full_duplex"` + Mac string `json:"mac"` + } `json:"downlink_table"` + Uplink struct { FullDuplex FlexBool `json:"full_duplex"` IP string `json:"ip"` Mac string `json:"mac"` - MaxSpeed float64 `json:"max_speed"` - Media string `json:"media"` Name string `json:"name"` Netmask string `json:"netmask"` - NumPort float64 `json:"num_port"` - PortIdx float64 `json:"port_idx"` - RxBytes float64 `json:"rx_bytes"` - RxBytesR float64 `json:"rx_bytes-r"` - RxDropped float64 `json:"rx_dropped"` - RxErrors float64 `json:"rx_errors"` - RxMulticast float64 `json:"rx_multicast"` - RxPackets float64 `json:"rx_packets"` - Speed float64 `json:"speed"` - TxBytes float64 `json:"tx_bytes"` - TxBytesR float64 `json:"tx_bytes-r"` - TxDropped float64 `json:"tx_dropped"` - TxErrors float64 `json:"tx_errors"` - TxPackets float64 `json:"tx_packets"` - Type string `json:"type"` + NumPort FlexInt `json:"num_port"` + RxBytes FlexInt `json:"rx_bytes"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxMulticast FlexInt `json:"rx_multicast"` + RxPackets FlexInt `json:"rx_packets"` + Speed FlexInt `json:"speed"` + TxBytes FlexInt `json:"tx_bytes"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxPackets FlexInt `json:"tx_packets"` Up FlexBool `json:"up"` + PortIdx FlexInt `json:"port_idx"` + Media string `json:"media"` + MaxSpeed FlexInt `json:"max_speed"` UplinkMac string `json:"uplink_mac"` + Type string `json:"type"` + TxBytesR FlexInt `json:"tx_bytes-r"` + RxBytesR FlexInt `json:"rx_bytes-r"` } `json:"uplink"` - UplinkDepth FlexInt `json:"uplink_depth"` - Uptime float64 `json:"uptime"` - UserNumSta float64 `json:"user-num_sta"` - Version string `json:"version"` - VersionIncompatible FlexBool `json:"version_incompatible"` + LastUplink struct { + UplinkMac string `json:"uplink_mac"` + } `json:"last_uplink"` + UplinkDepth FlexInt `json:"uplink_depth"` + Stat struct { + SiteID string `json:"site_id"` + O string `json:"o"` + Oid string `json:"oid"` + Sw string `json:"sw"` + Time FlexInt `json:"time"` + Datetime time.Time `json:"datetime"` + RxPackets FlexInt `json:"rx_packets"` + RxBytes FlexInt `json:"rx_bytes"` + RxErrors FlexInt `json:"rx_errors"` + RxDropped FlexInt `json:"rx_dropped"` + RxCrypts FlexInt `json:"rx_crypts"` + RxFrags FlexInt `json:"rx_frags"` + TxPackets FlexInt `json:"tx_packets"` + TxBytes FlexInt `json:"tx_bytes"` + TxErrors FlexInt `json:"tx_errors"` + TxDropped FlexInt `json:"tx_dropped"` + TxRetries FlexInt `json:"tx_retries"` + RxMulticast FlexInt `json:"rx_multicast"` + RxBroadcast FlexInt `json:"rx_broadcast"` + TxMulticast FlexInt `json:"tx_multicast"` + TxBroadcast FlexInt `json:"tx_broadcast"` + Bytes FlexInt `json:"bytes"` + Duration FlexInt `json:"duration"` + Port1RxPackets FlexInt `json:"port_1-rx_packets"` + Port1RxBytes FlexInt `json:"port_1-rx_bytes"` + Port1TxPackets FlexInt `json:"port_1-tx_packets"` + Port1TxBytes FlexInt `json:"port_1-tx_bytes"` + Port1TxMulticast FlexInt `json:"port_1-tx_multicast"` + Port1TxBroadcast FlexInt `json:"port_1-tx_broadcast"` + Port3RxPackets FlexInt `json:"port_3-rx_packets"` + Port3RxBytes FlexInt `json:"port_3-rx_bytes"` + Port3TxPackets FlexInt `json:"port_3-tx_packets"` + Port3TxBytes FlexInt `json:"port_3-tx_bytes"` + Port3RxBroadcast FlexInt `json:"port_3-rx_broadcast"` + Port3TxMulticast FlexInt `json:"port_3-tx_multicast"` + Port3TxBroadcast FlexInt `json:"port_3-tx_broadcast"` + Port6RxPackets FlexInt `json:"port_6-rx_packets"` + Port6RxBytes FlexInt `json:"port_6-rx_bytes"` + Port6TxPackets FlexInt `json:"port_6-tx_packets"` + Port6TxBytes FlexInt `json:"port_6-tx_bytes"` + Port6RxMulticast FlexInt `json:"port_6-rx_multicast"` + Port6TxMulticast FlexInt `json:"port_6-tx_multicast"` + Port6TxBroadcast FlexInt `json:"port_6-tx_broadcast"` + Port7RxPackets FlexInt `json:"port_7-rx_packets"` + Port7RxBytes FlexInt `json:"port_7-rx_bytes"` + Port7TxPackets FlexInt `json:"port_7-tx_packets"` + Port7TxBytes FlexInt `json:"port_7-tx_bytes"` + Port7TxMulticast FlexInt `json:"port_7-tx_multicast"` + Port7TxBroadcast FlexInt `json:"port_7-tx_broadcast"` + Port9RxPackets FlexInt `json:"port_9-rx_packets"` + Port9RxBytes FlexInt `json:"port_9-rx_bytes"` + Port9TxPackets FlexInt `json:"port_9-tx_packets"` + Port9TxBytes FlexInt `json:"port_9-tx_bytes"` + Port9TxMulticast FlexInt `json:"port_9-tx_multicast"` + Port9TxBroadcast FlexInt `json:"port_9-tx_broadcast"` + Port10RxPackets FlexInt `json:"port_10-rx_packets"` + Port10RxBytes FlexInt `json:"port_10-rx_bytes"` + Port10TxPackets FlexInt `json:"port_10-tx_packets"` + Port10TxBytes FlexInt `json:"port_10-tx_bytes"` + Port10RxMulticast FlexInt `json:"port_10-rx_multicast"` + Port10TxMulticast FlexInt `json:"port_10-tx_multicast"` + Port10TxBroadcast FlexInt `json:"port_10-tx_broadcast"` + Port11RxPackets FlexInt `json:"port_11-rx_packets"` + Port11RxBytes FlexInt `json:"port_11-rx_bytes"` + Port11TxPackets FlexInt `json:"port_11-tx_packets"` + Port11TxBytes FlexInt `json:"port_11-tx_bytes"` + Port11TxMulticast FlexInt `json:"port_11-tx_multicast"` + Port11TxBroadcast FlexInt `json:"port_11-tx_broadcast"` + Port12RxPackets FlexInt `json:"port_12-rx_packets"` + Port12RxBytes FlexInt `json:"port_12-rx_bytes"` + Port12TxPackets FlexInt `json:"port_12-tx_packets"` + Port12TxBytes FlexInt `json:"port_12-tx_bytes"` + Port12TxMulticast FlexInt `json:"port_12-tx_multicast"` + Port12TxBroadcast FlexInt `json:"port_12-tx_broadcast"` + Port13RxPackets FlexInt `json:"port_13-rx_packets"` + Port13RxBytes FlexInt `json:"port_13-rx_bytes"` + Port13TxPackets FlexInt `json:"port_13-tx_packets"` + Port13TxBytes FlexInt `json:"port_13-tx_bytes"` + Port13RxMulticast FlexInt `json:"port_13-rx_multicast"` + Port13RxBroadcast FlexInt `json:"port_13-rx_broadcast"` + Port13TxMulticast FlexInt `json:"port_13-tx_multicast"` + Port13TxBroadcast FlexInt `json:"port_13-tx_broadcast"` + Port15RxPackets FlexInt `json:"port_15-rx_packets"` + Port15RxBytes FlexInt `json:"port_15-rx_bytes"` + Port15TxPackets FlexInt `json:"port_15-tx_packets"` + Port15TxBytes FlexInt `json:"port_15-tx_bytes"` + Port15RxBroadcast FlexInt `json:"port_15-rx_broadcast"` + Port15TxMulticast FlexInt `json:"port_15-tx_multicast"` + Port15TxBroadcast FlexInt `json:"port_15-tx_broadcast"` + Port16RxPackets FlexInt `json:"port_16-rx_packets"` + Port16RxBytes FlexInt `json:"port_16-rx_bytes"` + Port16TxPackets FlexInt `json:"port_16-tx_packets"` + Port16TxBytes FlexInt `json:"port_16-tx_bytes"` + Port16TxMulticast FlexInt `json:"port_16-tx_multicast"` + Port16TxBroadcast FlexInt `json:"port_16-tx_broadcast"` + Port17RxPackets FlexInt `json:"port_17-rx_packets"` + Port17RxBytes FlexInt `json:"port_17-rx_bytes"` + Port17TxPackets FlexInt `json:"port_17-tx_packets"` + Port17TxBytes FlexInt `json:"port_17-tx_bytes"` + Port17TxMulticast FlexInt `json:"port_17-tx_multicast"` + Port17TxBroadcast FlexInt `json:"port_17-tx_broadcast"` + Port18RxPackets FlexInt `json:"port_18-rx_packets"` + Port18RxBytes FlexInt `json:"port_18-rx_bytes"` + Port18TxPackets FlexInt `json:"port_18-tx_packets"` + Port18TxBytes FlexInt `json:"port_18-tx_bytes"` + Port18RxMulticast FlexInt `json:"port_18-rx_multicast"` + Port18TxMulticast FlexInt `json:"port_18-tx_multicast"` + Port18TxBroadcast FlexInt `json:"port_18-tx_broadcast"` + Port19RxPackets FlexInt `json:"port_19-rx_packets"` + Port19RxBytes FlexInt `json:"port_19-rx_bytes"` + Port19TxPackets FlexInt `json:"port_19-tx_packets"` + Port19TxBytes FlexInt `json:"port_19-tx_bytes"` + Port19TxMulticast FlexInt `json:"port_19-tx_multicast"` + Port19TxBroadcast FlexInt `json:"port_19-tx_broadcast"` + Port21RxPackets FlexInt `json:"port_21-rx_packets"` + Port21RxBytes FlexInt `json:"port_21-rx_bytes"` + Port21TxPackets FlexInt `json:"port_21-tx_packets"` + Port21TxBytes FlexInt `json:"port_21-tx_bytes"` + Port21RxBroadcast FlexInt `json:"port_21-rx_broadcast"` + Port21TxMulticast FlexInt `json:"port_21-tx_multicast"` + Port21TxBroadcast FlexInt `json:"port_21-tx_broadcast"` + Port22RxPackets FlexInt `json:"port_22-rx_packets"` + Port22RxBytes FlexInt `json:"port_22-rx_bytes"` + Port22TxPackets FlexInt `json:"port_22-tx_packets"` + Port22TxBytes FlexInt `json:"port_22-tx_bytes"` + Port22RxMulticast FlexInt `json:"port_22-rx_multicast"` + Port22TxMulticast FlexInt `json:"port_22-tx_multicast"` + Port22TxBroadcast FlexInt `json:"port_22-tx_broadcast"` + Port23RxPackets FlexInt `json:"port_23-rx_packets"` + Port23RxBytes FlexInt `json:"port_23-rx_bytes"` + Port23RxDropped FlexInt `json:"port_23-rx_dropped"` + Port23TxPackets FlexInt `json:"port_23-tx_packets"` + Port23TxBytes FlexInt `json:"port_23-tx_bytes"` + Port23RxMulticast FlexInt `json:"port_23-rx_multicast"` + Port23RxBroadcast FlexInt `json:"port_23-rx_broadcast"` + Port23TxMulticast FlexInt `json:"port_23-tx_multicast"` + Port23TxBroadcast FlexInt `json:"port_23-tx_broadcast"` + Port24RxPackets FlexInt `json:"port_24-rx_packets"` + Port24RxBytes FlexInt `json:"port_24-rx_bytes"` + Port24TxPackets FlexInt `json:"port_24-tx_packets"` + Port24TxBytes FlexInt `json:"port_24-tx_bytes"` + Port24RxMulticast FlexInt `json:"port_24-rx_multicast"` + Port24TxMulticast FlexInt `json:"port_24-tx_multicast"` + Port24TxBroadcast FlexInt `json:"port_24-tx_broadcast"` + Port1RxMulticast FlexInt `json:"port_1-rx_multicast"` + Port3RxDropped FlexInt `json:"port_3-rx_dropped"` + Port3RxMulticast FlexInt `json:"port_3-rx_multicast"` + Port6RxDropped FlexInt `json:"port_6-rx_dropped"` + Port7RxDropped FlexInt `json:"port_7-rx_dropped"` + Port7RxMulticast FlexInt `json:"port_7-rx_multicast"` + Port9RxDropped FlexInt `json:"port_9-rx_dropped"` + Port9RxMulticast FlexInt `json:"port_9-rx_multicast"` + Port9RxBroadcast FlexInt `json:"port_9-rx_broadcast"` + Port10RxBroadcast FlexInt `json:"port_10-rx_broadcast"` + Port12RxDropped FlexInt `json:"port_12-rx_dropped"` + Port12RxMulticast FlexInt `json:"port_12-rx_multicast"` + Port13RxDropped FlexInt `json:"port_13-rx_dropped"` + Port17RxDropped FlexInt `json:"port_17-rx_dropped"` + Port17RxMulticast FlexInt `json:"port_17-rx_multicast"` + Port17RxBroadcast FlexInt `json:"port_17-rx_broadcast"` + Port19RxDropped FlexInt `json:"port_19-rx_dropped"` + Port19RxMulticast FlexInt `json:"port_19-rx_multicast"` + Port19RxBroadcast FlexInt `json:"port_19-rx_broadcast"` + Port21RxDropped FlexInt `json:"port_21-rx_dropped"` + Port21RxMulticast FlexInt `json:"port_21-rx_multicast"` + Port7RxBroadcast FlexInt `json:"port_7-rx_broadcast"` + Port18RxBroadcast FlexInt `json:"port_18-rx_broadcast"` + Port16RxMulticast FlexInt `json:"port_16-rx_multicast"` + Port15RxDropped FlexInt `json:"port_15-rx_dropped"` + Port15RxMulticast FlexInt `json:"port_15-rx_multicast"` + Port16RxBroadcast FlexInt `json:"port_16-rx_broadcast"` + Port11RxBroadcast FlexInt `json:"port_11-rx_broadcast"` + Port12RxBroadcast FlexInt `json:"port_12-rx_broadcast"` + Port6RxBroadcast FlexInt `json:"port_6-rx_broadcast"` + Port24RxBroadcast FlexInt `json:"port_24-rx_broadcast"` + Port22RxBroadcast FlexInt `json:"port_22-rx_broadcast"` + Port10TxDropped FlexInt `json:"port_10-tx_dropped"` + Port16TxDropped FlexInt `json:"port_16-tx_dropped"` + Port1RxBroadcast FlexInt `json:"port_1-rx_broadcast"` + Port4RxPackets FlexInt `json:"port_4-rx_packets"` + Port4RxBytes FlexInt `json:"port_4-rx_bytes"` + Port4RxDropped FlexInt `json:"port_4-rx_dropped"` + Port4TxPackets FlexInt `json:"port_4-tx_packets"` + Port4TxBytes FlexInt `json:"port_4-tx_bytes"` + Port4TxDropped FlexInt `json:"port_4-tx_dropped"` + Port4RxMulticast FlexInt `json:"port_4-rx_multicast"` + Port4RxBroadcast FlexInt `json:"port_4-rx_broadcast"` + Port4TxMulticast FlexInt `json:"port_4-tx_multicast"` + Port4TxBroadcast FlexInt `json:"port_4-tx_broadcast"` + } `json:"stat"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + NumSta FlexInt `json:"num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` } From 2f16177afc569ea0e74a165b109dd119d59b9ab6 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Fri, 5 Jul 2019 01:58:06 -0700 Subject: [PATCH 072/194] Add usg port_table data. --- core/unifi/uap_type.go | 1 - core/unifi/unifi.go | 6 - core/unifi/usg_influx.go | 146 ++++++++----- core/unifi/usg_type.go | 459 +++++++++++++++++++-------------------- 4 files changed, 316 insertions(+), 296 deletions(-) diff --git a/core/unifi/uap_type.go b/core/unifi/uap_type.go index 43136882..842a022a 100644 --- a/core/unifi/uap_type.go +++ b/core/unifi/uap_type.go @@ -176,7 +176,6 @@ type UAP struct { UplinkRemotePort int `json:"uplink_remote_port"` } `json:"uplink"` VapTable []struct { - SiteName string `json:"-"` AnomaliesBarChart struct { HighTCPLatency FlexInt `json:"high_tcp_latency"` HighTCPPacketLoss FlexInt `json:"high_tcp_packet_loss"` diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index ccf9e36b..93d28de9 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -105,15 +105,9 @@ func (u *Unifi) GetDevices(sites []Site) (*Devices, error) { // Add SiteName to each device asset. for i := range loopDevices.UAPs { loopDevices.UAPs[i].SiteName = site.Desc + " (" + site.Name + ")" - for j := range loopDevices.UAPs[i].VapTable { - loopDevices.UAPs[i].VapTable[j].SiteName = site.Desc + " (" + site.Name + ")" - } } for i := range loopDevices.USGs { loopDevices.USGs[i].SiteName = site.Desc + " (" + site.Name + ")" - for j := range loopDevices.USGs[i].NetworkTable { - loopDevices.USGs[i].NetworkTable[j].SiteName = site.Desc + " (" + site.Name + ")" - } } for i := range loopDevices.USWs { loopDevices.USWs[i].SiteName = site.Desc + " (" + site.Name + ")" diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index 56a0c4af..896b6bf9 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -1,7 +1,7 @@ package unifi import ( - "strconv" + "strings" "time" influx "github.com/influxdata/influxdb1-client/v2" @@ -10,6 +10,7 @@ import ( // Points generates Unifi Gateway datapoints for InfluxDB. // These points can be passed directly to influx. func (u USG) Points() ([]*influx.Point, error) { + now := time.Now() tags := map[string]string{ "id": u.ID, "mac": u.Mac, @@ -19,16 +20,12 @@ func (u USG) Points() ([]*influx.Point, error) { "site_name": u.SiteName, "adopted": u.Adopted.Txt, "name": u.Name, - "adopt_ip": u.AdoptIP, - "adopt_url": u.AdoptURL, "cfgversion": u.Cfgversion, "config_network_ip": u.ConfigNetwork.IP, "config_network_type": u.ConfigNetwork.Type, "connect_request_ip": u.ConnectRequestIP, "connect_request_port": u.ConnectRequestPort, - "default": u.Default.Txt, "device_id": u.DeviceID, - "discovered_via": u.DiscoveredVia, "guest_token": u.GuestToken, "inform_ip": u.InformIP, "known_cfgversion": u.KnownCfgversion, @@ -38,42 +35,39 @@ func (u USG) Points() ([]*influx.Point, error) { "outdoor_mode_override": u.OutdoorModeOverride, "serial": u.Serial, "type": u.Type, - "version_incompatible": u.VersionIncompatible.Txt, - "usg_caps": strconv.FormatFloat(u.UsgCaps, 'f', 6, 64), + "usg_caps": u.UsgCaps.Txt, "speedtest-status-saved": u.SpeedtestStatusSaved.Txt, "wan1_up": u.Wan1.Up.Txt, "wan2_up": u.Wan2.Up.Txt, } fields := map[string]interface{}{ "ip": u.IP, - "bytes": u.Bytes, - "last_seen": u.LastSeen, + "bytes": u.Bytes.Val, + "last_seen": u.LastSeen.Val, "license_state": u.LicenseState, - "fw_caps": u.FwCaps, - "guest-num_sta": u.GuestNumSta, + "fw_caps": u.FwCaps.Val, + "guest-num_sta": u.GuestNumSta.Val, "rx_bytes": u.RxBytes.Val, "tx_bytes": u.TxBytes.Val, - "uptime": u.Uptime, - "considered_lost_at": u.ConsideredLostAt, - "next_heartbeat_at": u.NextHeartbeatAt, + "uptime": u.Uptime.Val, "roll_upgrade": u.Rollupgrade.Val, - "state": u.State, + "state": u.State.Val, "upgradable": u.Upgradable.Val, - "user-num_sta": u.UserNumSta, + "user-num_sta": u.UserNumSta.Val, "version": u.Version, - "num_desktop": u.NumDesktop, - "num_handheld": u.NumHandheld, - "num_mobile": u.NumMobile, - "speedtest-status_latency": u.SpeedtestStatus.Latency, - "speedtest-status_rundate": u.SpeedtestStatus.Rundate, - "speedtest-status_runtime": u.SpeedtestStatus.Runtime, - "speedtest-status_download": u.SpeedtestStatus.StatusDownload, - "speedtest-status_ping": u.SpeedtestStatus.StatusPing, - "speedtest-status_summary": u.SpeedtestStatus.StatusSummary, - "speedtest-status_upload": u.SpeedtestStatus.StatusUpload, - "speedtest-status_xput_download": u.SpeedtestStatus.XputDownload, - "speedtest-status_xput_upload": u.SpeedtestStatus.XputUpload, - "config_network_wan_type": u.ConfigNetworkWan.Type, + "num_desktop": u.NumDesktop.Val, + "num_handheld": u.NumHandheld.Val, + "num_mobile": u.NumMobile.Val, + "speedtest-status_latency": u.SpeedtestStatus.Latency.Val, + "speedtest-status_rundate": u.SpeedtestStatus.Rundate.Val, + "speedtest-status_runtime": u.SpeedtestStatus.Runtime.Val, + "speedtest-status_download": u.SpeedtestStatus.StatusDownload.Val, + "speedtest-status_ping": u.SpeedtestStatus.StatusPing.Val, + "speedtest-status_summary": u.SpeedtestStatus.StatusSummary.Val, + "speedtest-status_upload": u.SpeedtestStatus.StatusUpload.Val, + "speedtest-status_xput_download": u.SpeedtestStatus.XputDownload.Val, + "speedtest-status_xput_upload": u.SpeedtestStatus.XputUpload.Val, + "config_network_wan_type": u.ConfigNetwork.Type, "wan1_bytes-r": u.Wan1.BytesR.Val, "wan1_enable": u.Wan1.Enable.Val, "wan1_full_duplex": u.Wan1.FullDuplex.Val, @@ -124,35 +118,35 @@ func (u USG) Points() ([]*influx.Point, error) { "wan2_tx_dropped": u.Wan2.TxDropped.Val, "wan2_tx_errors": u.Wan2.TxErrors.Val, "wan2_tx_packets": u.Wan2.TxPackets.Val, - "loadavg_1": u.SysStats.Loadavg1, - "loadavg_5": u.SysStats.Loadavg5, - "loadavg_15": u.SysStats.Loadavg15, - "mem_used": u.SysStats.MemUsed, - "mem_buffer": u.SysStats.MemBuffer, - "mem_total": u.SysStats.MemTotal, - "cpu": u.SystemStats.CPU, - "mem": u.SystemStats.Mem, - "system_uptime": u.SystemStats.Uptime, - "stat_duration": u.Stat.Duration, + "loadavg_1": u.SysStats.Loadavg1.Val, + "loadavg_5": u.SysStats.Loadavg5.Val, + "loadavg_15": u.SysStats.Loadavg15.Val, + "mem_used": u.SysStats.MemUsed.Val, + "mem_buffer": u.SysStats.MemBuffer.Val, + "mem_total": u.SysStats.MemTotal.Val, + "cpu": u.SystemStats.CPU.Val, + "mem": u.SystemStats.Mem.Val, + "system_uptime": u.SystemStats.Uptime.Val, + "stat_duration": u.Stat.Duration.Val, "stat_datetime": u.Stat.Datetime, "gw": u.Stat.Gw, "false": "false", // to fill holes in graphs. - "lan-rx_bytes": u.Stat.LanRxBytes, - "lan-rx_packets": u.Stat.LanRxPackets, - "lan-tx_bytes": u.Stat.LanTxBytes, - "lan-tx_packets": u.Stat.LanTxPackets, - "wan-rx_bytes": u.Stat.WanRxBytes, - "wan-rx_dropped": u.Stat.WanRxDropped, - "wan-rx_packets": u.Stat.WanRxPackets, - "wan-tx_bytes": u.Stat.WanTxBytes, - "wan-tx_packets": u.Stat.WanTxPackets, + "lan-rx_bytes": u.Stat.LanRxBytes.Val, + "lan-rx_packets": u.Stat.LanRxPackets.Val, + "lan-tx_bytes": u.Stat.LanTxBytes.Val, + "lan-tx_packets": u.Stat.LanTxPackets.Val, + "wan-rx_bytes": u.Stat.WanRxBytes.Val, + "wan-rx_dropped": u.Stat.WanRxDropped.Val, + "wan-rx_packets": u.Stat.WanRxPackets.Val, + "wan-tx_bytes": u.Stat.WanTxBytes.Val, + "wan-tx_packets": u.Stat.WanTxPackets.Val, "uplink_name": u.Uplink.Name, - "uplink_latency": u.Uplink.Latency, - "uplink_speed": u.Uplink.Speed, - "uplink_num_ports": u.Uplink.NumPort, - "uplink_max_speed": u.Uplink.MaxSpeed, + "uplink_latency": u.Uplink.Latency.Val, + "uplink_speed": u.Uplink.Speed.Val, + "uplink_num_ports": u.Uplink.NumPort.Val, + "uplink_max_speed": u.Uplink.MaxSpeed.Val, } - pt, err := influx.NewPoint("usg", tags, fields, time.Now()) + pt, err := influx.NewPoint("usg", tags, fields, now) if err != nil { return nil, err } @@ -162,6 +156,7 @@ func (u USG) Points() ([]*influx.Point, error) { "device_name": u.Name, "device_id": u.ID, "device_mac": u.Mac, + "site_name": u.SiteName, "name": p.Name, "dhcpd_dns_enabled": p.DhcpdDNSEnabled.Txt, "dhcpd_enabled": p.DhcpdEnabled.Txt, @@ -180,7 +175,6 @@ func (u USG) Points() ([]*influx.Point, error) { "is_nat": p.IsNat.Txt, "networkgroup": p.Networkgroup, "site_id": p.SiteID, - "site_name": p.SiteName, } fields := map[string]interface{}{ "dhcpd_ip_1": p.DhcpdIP1, @@ -191,20 +185,54 @@ func (u USG) Points() ([]*influx.Point, error) { "ip_subnet": p.IPSubnet, "mac": p.Mac, "name": p.Name, - "num_sta": p.NumSta, + "num_sta": p.NumSta.Val, "purpose": p.Purpose, "rx_bytes": p.RxBytes.Val, - "rx_packets": p.RxPackets, + "rx_packets": p.RxPackets.Val, "tx_bytes": p.TxBytes.Val, - "tx_packets": p.TxPackets, - "up": p.Up.Txt, + "tx_packets": p.TxPackets.Val, "vlan": p.Vlan.Txt, "dhcpd_ntp_1": p.DhcpdNtp1, "dhcpd_unifi_controller": p.DhcpdUnifiController, "ipv6_interface_type": p.Ipv6InterfaceType, "attr_hidden_id": p.AttrHiddenID, } - pt, err = influx.NewPoint("usg_networks", tags, fields, time.Now()) + pt, err = influx.NewPoint("usg_networks", tags, fields, now) + if err != nil { + return points, err + } + points = append(points, pt) + } + for _, p := range u.PortTable { + tags := map[string]string{ + "device_name": u.Name, + "device_id": u.ID, + "device_mac": u.Mac, + "site_name": u.SiteName, + "name": p.Name, + "ifname": p.Ifname, + "ip": p.IP, + "netmask": p.Netmask, + "mac": p.Mac, + "up": p.Up.Txt, + "speed": p.Speed.Txt, + "full_duplex": p.FullDuplex.Txt, + "enable": p.Enable.Txt, + "gateway": p.Gateway, + } + fields := map[string]interface{}{ + "rx_bytes": p.RxBytes.Val, + "rx_dropped": p.RxDropped.Val, + "rx_errors": p.RxErrors.Val, + "rx_packets": p.RxBytes.Val, + "tx_bytes": p.TxBytes.Val, + "tx_dropped": p.TxDropped.Val, + "tx_errors": p.TxErrors.Val, + "tx_packets": p.TxPackets.Val, + "rx_multicast": p.RxMulticast.Val, + "dns_servers": strings.Join(p.DNS, ","), + } + pt, err = influx.NewPoint("usg_ports", tags, fields, now) if err != nil { return points, err } diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index be751f1d..5ba8bc21 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -1,262 +1,261 @@ package unifi -import "encoding/json" +import "time" // USG represents all the data from the Ubiquiti Controller for a Unifi Security Gateway. type USG struct { ID string `json:"_id"` - UUptime float64 `json:"_uptime"` - AdoptIP string `json:"adopt_ip"` - AdoptURL string `json:"adopt_url"` Adopted FlexBool `json:"adopted"` - Bytes float64 `json:"bytes"` Cfgversion string `json:"cfgversion"` ConfigNetwork struct { + Type string `json:"type"` IP string `json:"ip"` - Type string `json:"type"` } `json:"config_network"` - ConfigNetworkWan struct { - Type string `json:"type"` - } `json:"config_network_wan"` - ConnectRequestIP string `json:"connect_request_ip"` - ConnectRequestPort string `json:"connect_request_port"` - ConsideredLostAt float64 `json:"considered_lost_at"` - Default FlexBool `json:"default"` - DeviceID string `json:"device_id"` - DiscoveredVia string `json:"discovered_via"` - EthernetTable []struct { + EthernetTable []struct { Mac string `json:"mac"` + NumPort FlexInt `json:"num_port"` Name string `json:"name"` - NumPort float64 `json:"num_port"` } `json:"ethernet_table"` - FwCaps float64 `json:"fw_caps"` - GuestNumSta float64 `json:"guest-num_sta"` - GuestToken string `json:"guest_token"` - InformIP string `json:"inform_ip"` - InformURL string `json:"inform_url"` - IP string `json:"ip"` - KnownCfgversion string `json:"known_cfgversion"` - LastSeen float64 `json:"last_seen"` - LedOverride string `json:"led_override"` - LicenseState string `json:"license_state"` - Locating FlexBool `json:"locating"` - Mac string `json:"mac"` - Model string `json:"model"` - Name string `json:"name"` - NetworkTable []struct { - ID string `json:"_id"` - DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"` - DhcpdEnabled FlexBool `json:"dhcpd_enabled"` - DhcpdIP1 string `json:"dhcpd_ip_1,omitempty"` - DhcpdLeasetime json.Number `json:"dhcpd_leasetime,Number"` - DhcpdStart string `json:"dhcpd_start"` - DhcpdStop string `json:"dhcpd_stop"` - DhcpdWinsEnabled FlexBool `json:"dhcpd_wins_enabled,omitempty"` - DhcpguardEnabled FlexBool `json:"dhcpguard_enabled,omitempty"` - DomainName string `json:"domain_name"` - Enabled FlexBool `json:"enabled"` - IgmpSnooping FlexBool `json:"igmp_snooping,omitempty"` - IP string `json:"ip"` - IPSubnet string `json:"ip_subnet"` - IsGuest FlexBool `json:"is_guest"` - IsNat FlexBool `json:"is_nat"` - Mac string `json:"mac"` - Name string `json:"name"` - Networkgroup string `json:"networkgroup"` - NumSta float64 `json:"num_sta"` - Purpose string `json:"purpose"` - RxBytes FlexInt `json:"rx_bytes"` - RxPackets float64 `json:"rx_packets"` - SiteID string `json:"site_id"` - SiteName string `json:"-"` - TxBytes FlexInt `json:"tx_bytes"` - TxPackets float64 `json:"tx_packets"` - Up FlexBool `json:"up"` - Vlan FlexInt `json:"vlan,omitempty"` - VlanEnabled FlexBool `json:"vlan_enabled"` - DhcpRelayEnabled FlexBool `json:"dhcp_relay_enabled,omitempty"` - DhcpdGatewayEnabled FlexBool `json:"dhcpd_gateway_enabled,omitempty"` - DhcpdNtp1 string `json:"dhcpd_ntp_1,omitempty"` - DhcpdNtpEnabled FlexBool `json:"dhcpd_ntp_enabled,omitempty"` - DhcpdTimeOffsetEnabled FlexBool `json:"dhcpd_time_offset_enabled,omitempty"` - DhcpdUnifiController string `json:"dhcpd_unifi_controller,omitempty"` - Ipv6InterfaceType string `json:"ipv6_interface_type,omitempty"` - AttrHiddenID string `json:"attr_hidden_id,omitempty"` - AttrNoDelete FlexBool `json:"attr_no_delete,omitempty"` - UpnpLanEnabled FlexBool `json:"upnp_lan_enabled,omitempty"` - } `json:"network_table"` - NextHeartbeatAt float64 `json:"next_heartbeat_at"` - NumDesktop float64 `json:"num_desktop"` - NumHandheld float64 `json:"num_handheld"` - NumMobile float64 `json:"num_mobile"` - NumSta float64 `json:"num_sta"` + FwCaps FlexInt `json:"fw_caps"` + InformIP string `json:"inform_ip"` + InformURL string `json:"inform_url"` + IP string `json:"ip"` + LedOverride string `json:"led_override"` + LicenseState string `json:"license_state"` + Mac string `json:"mac"` + Model string `json:"model"` + Name string `json:"name"` OutdoorModeOverride string `json:"outdoor_mode_override"` - PortTable []struct { - DNS []string `json:"dns,omitempty"` - Enable FlexBool `json:"enable"` - FullDuplex FlexBool `json:"full_duplex"` - Gateway string `json:"gateway,omitempty"` - Ifname string `json:"ifname"` - IP string `json:"ip"` - Mac string `json:"mac"` - Name string `json:"name"` - Netmask string `json:"netmask"` - RxBytes FlexInt `json:"rx_bytes"` - RxDropped float64 `json:"rx_dropped"` - RxErrors float64 `json:"rx_errors"` - RxMulticast float64 `json:"rx_multicast"` - RxPackets float64 `json:"rx_packets"` - Speed float64 `json:"speed"` - TxBytes FlexInt `json:"tx_bytes"` - TxDropped float64 `json:"tx_dropped"` - TxErrors float64 `json:"tx_errors"` - TxPackets float64 `json:"tx_packets"` - Up FlexBool `json:"up"` - } `json:"port_table"` - Rollupgrade FlexBool `json:"rollupgrade"` - RxBytes FlexInt `json:"rx_bytes"` - Serial string `json:"serial"` - SiteID string `json:"site_id"` - SiteName string `json:"-"` - SpeedtestStatus struct { - Latency float64 `json:"latency"` - Rundate float64 `json:"rundate"` - Runtime float64 `json:"runtime"` - StatusDownload float64 `json:"status_download"` - StatusPing float64 `json:"status_ping"` - StatusSummary float64 `json:"status_summary"` - StatusUpload float64 `json:"status_upload"` - XputDownload float64 `json:"xput_download"` - XputUpload float64 `json:"xput_upload"` - } `json:"speedtest-status"` - SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"` - Stat struct { - Datetime string `json:"datetime"` - Duration float64 `json:"duration"` - Gw string `json:"gw"` - LanRxBytes float64 `json:"lan-rx_bytes"` - LanRxPackets float64 `json:"lan-rx_packets"` - LanTxBytes float64 `json:"lan-tx_bytes"` - LanTxPackets float64 `json:"lan-tx_packets"` - O string `json:"o"` - Oid string `json:"oid"` - SiteID string `json:"site_id"` - Time float64 `json:"time"` - WanRxBytes float64 `json:"wan-rx_bytes"` - WanRxDropped float64 `json:"wan-rx_dropped"` - WanRxPackets float64 `json:"wan-rx_packets"` - WanTxBytes float64 `json:"wan-tx_bytes"` - WanTxPackets float64 `json:"wan-tx_packets"` - } `json:"stat"` - State float64 `json:"state"` - SysStats struct { - Loadavg1 float64 `json:"loadavg_1,string"` - Loadavg15 float64 `json:"loadavg_15,string"` - Loadavg5 float64 `json:"loadavg_5,string"` - MemBuffer float64 `json:"mem_buffer"` - MemTotal float64 `json:"mem_total"` - MemUsed float64 `json:"mem_used"` + Serial string `json:"serial"` + SiteID string `json:"site_id"` + SiteName string `json:"-"` + Type string `json:"type"` + UsgCaps FlexInt `json:"usg_caps"` + Version string `json:"version"` + RequiredVersion string `json:"required_version"` + EthernetOverrides []struct { + Ifname string `json:"ifname"` + Networkgroup string `json:"networkgroup"` + } `json:"ethernet_overrides"` + HwCaps FlexInt `json:"hw_caps"` + BoardRev FlexInt `json:"board_rev"` + Unsupported FlexBool `json:"unsupported"` + UnsupportedReason FlexInt `json:"unsupported_reason"` + DeviceID string `json:"device_id"` + State FlexInt `json:"state"` + LastSeen FlexInt `json:"last_seen"` + Upgradable FlexBool `json:"upgradable"` + AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` + Rollupgrade FlexBool `json:"rollupgrade"` + KnownCfgversion string `json:"known_cfgversion"` + Uptime FlexInt `json:"uptime"` + Locating FlexBool `json:"locating"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + SysStats struct { + Loadavg1 FlexInt `json:"loadavg_1"` + Loadavg15 FlexInt `json:"loadavg_15"` + Loadavg5 FlexInt `json:"loadavg_5"` + MemBuffer FlexInt `json:"mem_buffer"` + MemTotal FlexInt `json:"mem_total"` + MemUsed FlexInt `json:"mem_used"` } `json:"sys_stats"` SystemStats struct { - CPU float64 `json:"cpu,string"` - Mem float64 `json:"mem,string"` - Uptime float64 `json:"uptime,string"` + CPU FlexInt `json:"cpu"` + Mem FlexInt `json:"mem"` + Uptime FlexInt `json:"uptime"` } `json:"system-stats"` - TxBytes FlexInt `json:"tx_bytes"` - Type string `json:"type"` - Upgradable FlexBool `json:"upgradable"` - Uplink struct { - BytesR float64 `json:"bytes-r"` - Drops float64 `json:"drops"` + GuestToken string `json:"guest_token"` + SpeedtestStatus struct { + Latency FlexInt `json:"latency"` + Rundate FlexInt `json:"rundate"` + Runtime FlexInt `json:"runtime"` + StatusDownload FlexInt `json:"status_download"` + StatusPing FlexInt `json:"status_ping"` + StatusSummary FlexInt `json:"status_summary"` + StatusUpload FlexInt `json:"status_upload"` + XputDownload FlexInt `json:"xput_download"` + XputUpload FlexInt `json:"xput_upload"` + } `json:"speedtest-status"` + SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"` + Wan1 struct { + TxBytesR FlexInt `json:"tx_bytes-r"` + RxBytesR FlexInt `json:"rx_bytes-r"` + BytesR FlexInt `json:"bytes-r"` + MaxSpeed FlexInt `json:"max_speed"` + Type string `json:"type"` + Name string `json:"name"` + Ifname string `json:"ifname"` + IP string `json:"ip"` + Netmask string `json:"netmask"` + Mac string `json:"mac"` + Up FlexBool `json:"up"` + Speed FlexInt `json:"speed"` + FullDuplex FlexBool `json:"full_duplex"` + RxBytes FlexInt `json:"rx_bytes"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxPackets FlexInt `json:"rx_packets"` + TxBytes FlexInt `json:"tx_bytes"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxPackets FlexInt `json:"tx_packets"` + RxMulticast FlexInt `json:"rx_multicast"` + Enable FlexBool `json:"enable"` + DNS []string `json:"dns"` + Gateway string `json:"gateway"` + } `json:"wan1"` + Wan2 struct { + TxBytesR FlexInt `json:"tx_bytes-r"` + RxBytesR FlexInt `json:"rx_bytes-r"` + BytesR FlexInt `json:"bytes-r"` + MaxSpeed FlexInt `json:"max_speed"` + Type string `json:"type"` + Name string `json:"name"` + Ifname string `json:"ifname"` + IP string `json:"ip"` + Netmask string `json:"netmask"` + Mac string `json:"mac"` + Up FlexBool `json:"up"` + Speed FlexInt `json:"speed"` + FullDuplex FlexBool `json:"full_duplex"` + RxBytes FlexInt `json:"rx_bytes"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxPackets FlexInt `json:"rx_packets"` + TxBytes FlexInt `json:"tx_bytes"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxPackets FlexInt `json:"tx_packets"` + RxMulticast FlexInt `json:"rx_multicast"` + Enable FlexBool `json:"enable"` + DNS []string `json:"dns"` + Gateway string `json:"gateway"` + } `json:"wan2"` + PortTable []struct { + Name string `json:"name"` + Ifname string `json:"ifname"` + IP string `json:"ip"` + Netmask string `json:"netmask"` + Mac string `json:"mac"` + Up FlexBool `json:"up"` + Speed FlexInt `json:"speed"` + FullDuplex FlexBool `json:"full_duplex"` + RxBytes FlexInt `json:"rx_bytes"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxPackets FlexInt `json:"rx_packets"` + TxBytes FlexInt `json:"tx_bytes"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxPackets FlexInt `json:"tx_packets"` + RxMulticast FlexInt `json:"rx_multicast"` + Enable FlexBool `json:"enable"` + DNS []string `json:"dns,omitempty"` + Gateway string `json:"gateway,omitempty"` + } `json:"port_table"` + NetworkTable []struct { + ID string `json:"_id"` + IsNat FlexBool `json:"is_nat"` + DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"` + Purpose string `json:"purpose"` + DhcpdLeasetime FlexInt `json:"dhcpd_leasetime"` + IgmpSnooping FlexBool `json:"igmp_snooping"` + DhcpguardEnabled FlexBool `json:"dhcpguard_enabled,omitempty"` + DhcpdStart string `json:"dhcpd_start"` + Enabled FlexBool `json:"enabled"` + DhcpdStop string `json:"dhcpd_stop"` + DhcpdWinsEnabled FlexBool `json:"dhcpd_wins_enabled,omitempty"` + DomainName string `json:"domain_name"` + DhcpdEnabled FlexBool `json:"dhcpd_enabled"` + IPSubnet string `json:"ip_subnet"` + Vlan FlexInt `json:"vlan,omitempty"` + Networkgroup string `json:"networkgroup"` + Name string `json:"name"` + SiteID string `json:"site_id"` + DhcpdIP1 string `json:"dhcpd_ip_1,omitempty"` + VlanEnabled FlexBool `json:"vlan_enabled"` + DhcpdGatewayEnabled FlexBool `json:"dhcpd_gateway_enabled"` + DhcpdTimeOffsetEnabled FlexBool `json:"dhcpd_time_offset_enabled"` + Ipv6InterfaceType string `json:"ipv6_interface_type"` + DhcpRelayEnabled FlexBool `json:"dhcp_relay_enabled"` + Mac string `json:"mac"` + IsGuest FlexBool `json:"is_guest"` + IP string `json:"ip"` + Up string `json:"up"` + NumSta FlexInt `json:"num_sta"` + RxBytes FlexInt `json:"rx_bytes"` + RxPackets FlexInt `json:"rx_packets"` + TxBytes FlexInt `json:"tx_bytes"` + TxPackets FlexInt `json:"tx_packets"` + DhcpdNtp1 string `json:"dhcpd_ntp_1,omitempty"` + DhcpdNtpEnabled FlexBool `json:"dhcpd_ntp_enabled,omitempty"` + DhcpdUnifiController string `json:"dhcpd_unifi_controller,omitempty"` + UpnpLanEnabled FlexBool `json:"upnp_lan_enabled,omitempty"` + AttrNoDelete FlexBool `json:"attr_no_delete,omitempty"` + AttrHiddenID string `json:"attr_hidden_id,omitempty"` + } `json:"network_table"` + Uplink struct { + Drops FlexInt `json:"drops"` Enable FlexBool `json:"enable"` FullDuplex FlexBool `json:"full_duplex"` Gateways []string `json:"gateways"` IP string `json:"ip"` - Latency float64 `json:"latency"` + Latency FlexInt `json:"latency"` Mac string `json:"mac"` - MaxSpeed float64 `json:"max_speed"` Name string `json:"name"` Nameservers []string `json:"nameservers"` Netmask string `json:"netmask"` - NumPort float64 `json:"num_port"` + NumPort FlexInt `json:"num_port"` RxBytes FlexInt `json:"rx_bytes"` - RxBytesR float64 `json:"rx_bytes-r"` - RxDropped float64 `json:"rx_dropped"` - RxErrors float64 `json:"rx_errors"` - RxMulticast float64 `json:"rx_multicast"` - RxPackets float64 `json:"rx_packets"` - Speed float64 `json:"speed"` - SpeedtestLastrun float64 `json:"speedtest_lastrun"` - SpeedtestPing float64 `json:"speedtest_ping"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxMulticast FlexInt `json:"rx_multicast"` + RxPackets FlexInt `json:"rx_packets"` + Speed FlexInt `json:"speed"` + SpeedtestLastrun FlexInt `json:"speedtest_lastrun"` + SpeedtestPing FlexInt `json:"speedtest_ping"` SpeedtestStatus string `json:"speedtest_status"` TxBytes FlexInt `json:"tx_bytes"` - TxBytesR float64 `json:"tx_bytes-r"` - TxDropped float64 `json:"tx_dropped"` - TxErrors float64 `json:"tx_errors"` - TxPackets float64 `json:"tx_packets"` - Type string `json:"type"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxPackets FlexInt `json:"tx_packets"` Up FlexBool `json:"up"` - Uptime float64 `json:"uptime"` - XputDown float64 `json:"xput_down"` - XputUp float64 `json:"xput_up"` + Uptime FlexInt `json:"uptime"` + XputDown FlexInt `json:"xput_down"` + XputUp FlexInt `json:"xput_up"` + TxBytesR FlexInt `json:"tx_bytes-r"` + RxBytesR FlexInt `json:"rx_bytes-r"` + BytesR FlexInt `json:"bytes-r"` + MaxSpeed FlexInt `json:"max_speed"` + Type string `json:"type"` } `json:"uplink"` - Uptime float64 `json:"uptime"` - UserNumSta float64 `json:"user-num_sta"` - UsgCaps float64 `json:"usg_caps"` - Version string `json:"version"` - VersionIncompatible FlexBool `json:"version_incompatible"` - Wan1 struct { - BytesR FlexInt `json:"bytes-r"` - DNS []string `json:"dns"` - Enable FlexBool `json:"enable"` - FullDuplex FlexBool `json:"full_duplex"` - Gateway string `json:"gateway"` - Ifname string `json:"ifname"` - IP string `json:"ip"` - Mac string `json:"mac"` - MaxSpeed FlexInt `json:"max_speed"` - Name string `json:"name"` - Netmask string `json:"netmask"` - RxBytes FlexInt `json:"rx_bytes"` - RxBytesR FlexInt `json:"rx_bytes-r"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxMulticast FlexInt `json:"rx_multicast"` - RxPackets FlexInt `json:"rx_packets"` - Speed FlexInt `json:"speed"` - TxBytes FlexInt `json:"tx_bytes"` - TxBytesR FlexInt `json:"tx_bytes-r"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxPackets FlexInt `json:"tx_packets"` - Type string `json:"type"` - Up FlexBool `json:"up"` - } `json:"wan1"` - Wan2 struct { - BytesR FlexInt `json:"bytes-r"` - DNS []string `json:"dns"` - Enable FlexBool `json:"enable"` - FullDuplex FlexBool `json:"full_duplex"` - Gateway string `json:"gateway"` - Ifname string `json:"ifname"` - IP string `json:"ip"` - Mac string `json:"mac"` - MaxSpeed FlexInt `json:"max_speed"` - Name string `json:"name"` - Netmask string `json:"netmask"` - RxBytes FlexInt `json:"rx_bytes"` - RxBytesR FlexInt `json:"rx_bytes-r"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxMulticast FlexInt `json:"rx_multicast"` - RxPackets FlexInt `json:"rx_packets"` - Speed FlexInt `json:"speed"` - TxBytes FlexInt `json:"tx_bytes"` - TxBytesR FlexInt `json:"tx_bytes-r"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxPackets FlexInt `json:"tx_packets"` - Type string `json:"type"` - Up FlexBool `json:"up"` - } `json:"wan2"` + Stat struct { + SiteID string `json:"site_id"` + O string `json:"o"` + Oid string `json:"oid"` + Gw string `json:"gw"` + Time FlexInt `json:"time"` + Datetime time.Time `json:"datetime"` + Duration FlexInt `json:"duration"` + WanRxPackets FlexInt `json:"wan-rx_packets"` + WanRxBytes FlexInt `json:"wan-rx_bytes"` + WanTxPackets FlexInt `json:"wan-tx_packets"` + WanTxBytes FlexInt `json:"wan-tx_bytes"` + LanRxPackets FlexInt `json:"lan-rx_packets"` + LanRxBytes FlexInt `json:"lan-rx_bytes"` + LanTxPackets FlexInt `json:"lan-tx_packets"` + LanTxBytes FlexInt `json:"lan-tx_bytes"` + WanRxDropped FlexInt `json:"wan-rx_dropped"` + LanRxDropped FlexInt `json:"lan-rx_dropped"` + } `json:"stat"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + NumSta FlexInt `json:"num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` + NumDesktop FlexInt `json:"num_desktop"` + NumMobile FlexInt `json:"num_mobile"` + NumHandheld FlexInt `json:"num_handheld"` } From 3fc017f1b55f314ee4217e7642a02a9008ab58a9 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Fri, 5 Jul 2019 02:13:28 -0700 Subject: [PATCH 073/194] add examples --- core/unifi/examples/convert.sh | 20 + core/unifi/examples/uap.json | 738 ++++++++++++++ core/unifi/examples/ugw.json | 371 +++++++ core/unifi/examples/usw.json | 1720 ++++++++++++++++++++++++++++++++ 4 files changed, 2849 insertions(+) create mode 100755 core/unifi/examples/convert.sh create mode 100644 core/unifi/examples/uap.json create mode 100644 core/unifi/examples/ugw.json create mode 100644 core/unifi/examples/usw.json diff --git a/core/unifi/examples/convert.sh b/core/unifi/examples/convert.sh new file mode 100755 index 00000000..91de843d --- /dev/null +++ b/core/unifi/examples/convert.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Usage: +# ./convert.sh [prefix] +# should contain a go struct, like uap_type.go +# It converts the go struct to an influx thing, like you see in uap_influx.go. +# [prefix] is optional. I used it to do all the stat_ uap metrics. +# Very crude, just helps skip a lot of copy/paste. +path=$1 +pre=$2 +while IFS='' read -r line; do + name=$(echo "${line}" | awk '{print $1}') + type=$(echo "${line}" | awk '{print $2}') + json=$(echo "${line}" | awk '{print $3}') + json=$(echo "${json}" | cut -d\" -f2) + + if [ "$json" != "" ] && [ "$name" != "" ]; then + [[ "$type" = Flex* ]] && suf=.Val + echo "\"${pre}${json}\": u.Stat.${name}${suf}," + fi +done < ${path} diff --git a/core/unifi/examples/uap.json b/core/unifi/examples/uap.json new file mode 100644 index 00000000..dbc6c4ae --- /dev/null +++ b/core/unifi/examples/uap.json @@ -0,0 +1,738 @@ +{ + "_id": "574e8bde4566ffb914a26853", + "adopted": true, + "antenna_table": [ + { + "default": true, + "id": 4, + "name": "Combined", + "wifi0_gain": 3, + "wifi1_gain": 3 + } + ], + "bandsteering_mode": "prefer_5g", + "board_rev": 18, + "cfgversion": "08cd8d6b71ebe82f", + "config_network": { + "type": "dhcp", + "ip": "10.1.10.67" + }, + "countrycode_table": [ + 840, + 124, + 630 + ], + "ethernet_table": [ + { + "mac": "80:22:a8:22:ae:22", + "num_port": 2, + "name": "eth0" + } + ], + "fw_caps": 4128063, + "has_eth1": false, + "has_speaker": false, + "inform_ip": "192.168.3.1", + "inform_url": "http://unifi:8080/inform", + "ip": "192.168.1.8", + "led_override": "default", + "mac": "80:22:22:22:22:22", + "mesh_sta_vap_enabled": true, + "model": "U7PG2", + "name": "wap-lower", + "outdoor_mode_override": "default", + "port_table": [ + { + "port_idx": 1, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "attr_no_edit": true, + "media": "GE", + "name": "Main", + "poe_caps": 0, + "port_poe": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "port_delta": { + "time_delta": 21 + }, + "enable": true, + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 2, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "media": "GE", + "name": "Secondary", + "poe_caps": 0, + "port_poe": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "port_delta": { + "time_delta": 21 + }, + "enable": true, + "masked": false, + "aggregated_by": false + } + ], + "radio_table": [ + { + "radio": "ng", + "name": "wifi0", + "channel": "auto", + "ht": "40", + "tx_power_mode": "auto", + "tx_power": "0", + "max_txpower": 22, + "min_txpower": 6, + "nss": 3, + "min_rssi_enabled": false, + "builtin_antenna": true, + "builtin_ant_gain": 3, + "current_antenna_gain": 0, + "radio_caps": 16420, + "wlangroup_id": "574e869d4566ffb914a26843" + }, + { + "radio": "na", + "name": "wifi1", + "channel": "auto", + "ht": "80", + "tx_power_mode": "high", + "tx_power": "0", + "max_txpower": 22, + "min_txpower": 6, + "nss": 3, + "min_rssi_enabled": false, + "is_11ac": true, + "has_dfs": true, + "has_fccdfs": true, + "builtin_antenna": true, + "builtin_ant_gain": 3, + "current_antenna_gain": 0, + "radio_caps": 50479140, + "wlangroup_id": "574e869d4566ffb914a26843" + } + ], + "scan_radio_table": [], + "serial": "xxxyyyzzz", + "site_id": "574e86994566ffb914a2683c", + "type": "uap", + "version": "4.0.42.10433", + "vwire_table": [], + "wifi_caps": 49141, + "wlangroup_id_na": "574e869d4566ffb914a26843", + "wlangroup_id_ng": "574e869d4566ffb914a26843", + "required_version": "3.4.1", + "hw_caps": 0, + "unsupported": false, + "unsupported_reason": 0, + "sys_error_caps": 0, + "has_fan": false, + "has_temperature": false, + "device_id": "574e8bde4566ffb914a26853", + "state": 1, + "last_seen": 1562225381, + "upgradable": false, + "adoptable_when_upgraded": false, + "rollupgrade": false, + "known_cfgversion": "08cd8d6b71ebe82f", + "uptime": 3105845, + "_uptime": 3105845, + "locating": false, + "connect_request_ip": "192.168.1.8", + "connect_request_port": "43913", + "sys_stats": { + "loadavg_1": "0.04", + "loadavg_15": "0.14", + "loadavg_5": "0.10", + "mem_buffer": 0, + "mem_total": 128622592, + "mem_used": 67178496 + }, + "system-stats": { + "cpu": "24.7", + "mem": "52.2", + "uptime": "3105845" + }, + "ssh_session_table": [], + "scanning": false, + "spectrum_scanning": false, + "guest_token": "4D630D2A1AF84771FCBB8EEB4C47E030", + "meshv3_peer_mac": "", + "satisfaction": 95, + "isolated": false, + "radio_table_stats": [ + { + "name": "wifi0", + "channel": 6, + "radio": "ng", + "ast_txto": null, + "ast_cst": null, + "ast_be_xmit": 398, + "cu_total": 20, + "cu_self_rx": 14, + "cu_self_tx": 4, + "gain": 3, + "state": "RUN", + "extchannel": 1, + "tx_power": 22, + "tx_packets": 183, + "tx_retries": 108, + "num_sta": 2, + "guest-num_sta": 0, + "user-num_sta": 2 + }, + { + "name": "wifi1", + "channel": 36, + "radio": "na", + "ast_txto": null, + "ast_cst": null, + "ast_be_xmit": 398, + "cu_total": 12, + "cu_self_rx": 10, + "cu_self_tx": 2, + "gain": 3, + "state": "RUN", + "extchannel": 1, + "tx_power": 22, + "tx_packets": 22466, + "tx_retries": 858, + "num_sta": 4, + "guest-num_sta": 0, + "user-num_sta": 4 + } + ], + "uplink": { + "full_duplex": true, + "ip": "0.0.0.0", + "mac": "80:22:22:22:22:22", + "max_vlan": 96, + "name": "eth0", + "netmask": "0.0.0.0", + "num_port": 2, + "rx_bytes": 3752803309, + "rx_dropped": 102338, + "rx_errors": 0, + "rx_multicast": 0, + "rx_packets": 245302304, + "speed": 1000, + "tx_bytes": 1604707458, + "tx_dropped": 341, + "tx_errors": 0, + "tx_packets": 194278357, + "up": true, + "max_speed": 1000, + "type": "wire", + "tx_bytes-r": 9693222, + "rx_bytes-r": 92418, + "uplink_mac": "f0:22:22:22:22:22", + "uplink_remote_port": 15 + }, + "vap_table": [ + { + "avg_client_signal": 0, + "bssid": "82:22:22:22:22:22", + "ccq": 0, + "channel": 36, + "essid": "Extra Free", + "extchannel": 1, + "id": "574e96834566ffb914a26875", + "mac_filter_rejections": 0, + "name": "ath3", + "num_satisfaction_sta": 0, + "num_sta": 0, + "radio": "na", + "radio_name": "wifi1", + "rx_bytes": 61253, + "rx_crypts": 0, + "rx_dropped": 0, + "rx_errors": 0, + "rx_frags": 0, + "rx_nwids": 47658, + "rx_packets": 576, + "rx_tcp_stats": { + "goodbytes": 0, + "lat_avg": 0, + "lat_max": 0, + "lat_min": 4294967295, + "stalls": 0 + }, + "satisfaction": -1, + "satisfaction_now": -1, + "state": "RUN", + "tx_bytes": 922841, + "tx_combined_retries": 0, + "tx_data_mpdu_bytes": 0, + "tx_dropped": 18128, + "tx_errors": 7, + "tx_packets": 736, + "tx_power": 22, + "tx_retries": 0, + "tx_rts_retries": 0, + "tx_success": 0, + "tx_tcp_stats": { + "goodbytes": 0, + "lat_avg": 0, + "lat_max": 0, + "lat_min": 4294967295, + "stalls": 0 + }, + "tx_total": 0, + "up": true, + "usage": "guest", + "wifi_tx_attempts": 0, + "wifi_tx_dropped": 0, + "wifi_tx_latency_mov": { + "avg": 0, + "max": 0, + "min": 4294967295, + "total": 0, + "total_count": 0 + }, + "t": "vap", + "wlanconf_id": "574e96834566ffb914a26875", + "is_guest": true, + "is_wep": false, + "ap_mac": "80:22:a8:22:22:22", + "map_id": null, + "site_id": "574e86994566ffb914a2683c" + }, + { + "avg_client_signal": -65, + "bssid": "80:22:a8:22:22:22", + "ccq": 333, + "channel": 36, + "essid": "Extra Fast", + "extchannel": 1, + "id": "574e96614566ffb914a26874", + "mac_filter_rejections": 0, + "name": "ath2", + "num_satisfaction_sta": 4, + "num_sta": 4, + "radio": "na", + "radio_name": "wifi1", + "rx_bytes": 3358763522, + "rx_crypts": 161639, + "rx_dropped": 161639, + "rx_errors": 161639, + "rx_frags": 0, + "rx_nwids": 37605, + "rx_packets": 99128603, + "rx_tcp_stats": { + "goodbytes": 16243150352, + "lat_avg": 7, + "lat_max": 100, + "lat_min": 10, + "stalls": 0 + }, + "satisfaction": 96, + "satisfaction_now": 97, + "state": "RUN", + "tx_bytes": 834859686, + "tx_combined_retries": 9067488, + "tx_data_mpdu_bytes": 48117828355, + "tx_dropped": 109, + "tx_errors": 4076905, + "tx_packets": 111980588, + "tx_power": 22, + "tx_retries": 9067488, + "tx_rts_retries": 0, + "tx_success": 62855481, + "tx_tcp_stats": { + "goodbytes": 2154118473, + "lat_avg": 18, + "lat_max": 120, + "lat_min": 10, + "stalls": 0 + }, + "tx_total": 62855552, + "up": true, + "usage": "user", + "wifi_tx_attempts": 71923040, + "wifi_tx_dropped": 71, + "wifi_tx_latency_mov": { + "avg": 565, + "max": 31757, + "min": 98, + "total": 10183098, + "total_count": 18019 + }, + "t": "vap", + "wlanconf_id": "574e96614566ffb914a26874", + "is_guest": false, + "is_wep": false, + "ap_mac": "80:22:22:22:22:22", + "map_id": null, + "site_id": "574e86994566ffb914a2683c" + }, + { + "avg_client_signal": 0, + "bssid": "82:22:a8:22:22:22", + "ccq": 0, + "channel": 6, + "essid": "Extra Free", + "extchannel": 1, + "id": "574e96834566ffb914a26875", + "mac_filter_rejections": 0, + "name": "ath1", + "num_satisfaction_sta": 0, + "num_sta": 0, + "radio": "ng", + "radio_name": "wifi0", + "reasons_bar_chart": { + "phy_rate": 0, + "signal": 0, + "sleepy_client": 0, + "sta_arp_timeout": 0, + "sta_dns_timeout": 0, + "sta_ip_timeout": 0, + "stream_eff": 0, + "tcp_latency": 0, + "tcp_packet_loss": 0, + "wifi_latency": 0, + "wifi_retries": 0 + }, + "reasons_bar_chart_now": { + "phy_rate": 0, + "signal": 0, + "sleepy_client": 0, + "sta_arp_timeout": 0, + "sta_dns_timeout": 0, + "sta_ip_timeout": 0, + "stream_eff": 0, + "tcp_latency": 0, + "tcp_packet_loss": 0, + "wifi_latency": 0, + "wifi_retries": 0 + }, + "rx_bytes": 0, + "rx_crypts": 0, + "rx_dropped": 0, + "rx_errors": 0, + "rx_frags": 0, + "rx_nwids": 120385, + "rx_packets": 0, + "rx_tcp_stats": { + "goodbytes": 0, + "lat_avg": 0, + "lat_max": 0, + "lat_min": 4294967295, + "stalls": 0 + }, + "satisfaction": -1, + "satisfaction_now": -1, + "state": "RUN", + "tx_bytes": 0, + "tx_combined_retries": 0, + "tx_data_mpdu_bytes": 0, + "tx_dropped": 20262, + "tx_errors": 0, + "tx_packets": 0, + "tx_power": 22, + "tx_retries": 0, + "tx_rts_retries": 0, + "tx_success": 0, + "tx_tcp_stats": { + "goodbytes": 0, + "lat_avg": 0, + "lat_max": 0, + "lat_min": 4294967295, + "stalls": 0 + }, + "tx_total": 0, + "up": true, + "usage": "guest", + "wifi_tx_attempts": 0, + "wifi_tx_dropped": 0, + "wifi_tx_latency_mov": { + "avg": 0, + "max": 0, + "min": 4294967295, + "total": 0, + "total_count": 0 + }, + "t": "vap", + "wlanconf_id": "574e96834566ffb914a26875", + "is_guest": true, + "is_wep": false, + "ap_mac": "80:22:a8:22:22:22", + "map_id": null, + "site_id": "574e86994566ffb914a2683c" + }, + { + "avg_client_signal": -68, + "bssid": "80:22:22:22:22:22", + "ccq": 966, + "channel": 6, + "essid": "Extra Fast", + "extchannel": 1, + "id": "574e96614566ffb914a26874", + "mac_filter_rejections": 0, + "name": "ath0", + "num_satisfaction_sta": 2, + "num_sta": 2, + "radio": "ng", + "radio_name": "wifi0", + "reasons_bar_chart": { + "phy_rate": 0, + "signal": 0, + "sleepy_client": 0, + "sta_arp_timeout": 0, + "sta_dns_timeout": 0, + "sta_ip_timeout": 0, + "stream_eff": 0, + "tcp_latency": 0, + "tcp_packet_loss": 0, + "wifi_latency": 0, + "wifi_retries": 1 + }, + "reasons_bar_chart_now": { + "phy_rate": 0, + "signal": 0, + "sleepy_client": 0, + "sta_arp_timeout": 0, + "sta_dns_timeout": 0, + "sta_ip_timeout": 0, + "stream_eff": 0, + "tcp_latency": 0, + "tcp_packet_loss": 0, + "wifi_latency": 0, + "wifi_retries": 1 + }, + "rx_bytes": 1017366419, + "rx_crypts": 11013, + "rx_dropped": 12764, + "rx_errors": 12764, + "rx_frags": 0, + "rx_nwids": 177145, + "rx_packets": 22542668, + "rx_tcp_stats": { + "goodbytes": 114220296, + "lat_avg": 5, + "lat_max": 10, + "lat_min": 10, + "stalls": 0 + }, + "satisfaction": 93, + "satisfaction_now": 94, + "state": "RUN", + "tx_bytes": 965488630, + "tx_combined_retries": 8202639, + "tx_data_mpdu_bytes": 1145631754, + "tx_dropped": 43, + "tx_errors": 0, + "tx_packets": 22623798, + "tx_power": 22, + "tx_retries": 7194267, + "tx_rts_retries": 1008372, + "tx_success": 9545999, + "tx_tcp_stats": { + "goodbytes": 182912739, + "lat_avg": 5, + "lat_max": 10, + "lat_min": 10, + "stalls": 0 + }, + "tx_total": 9547096, + "up": true, + "usage": "user", + "wifi_tx_attempts": 16740276, + "wifi_tx_dropped": 1095, + "wifi_tx_latency_mov": { + "avg": 673, + "max": 13612, + "min": 0, + "total": 263176, + "total_count": 391 + }, + "t": "vap", + "wlanconf_id": "574e96614566ffb914a26874", + "is_guest": false, + "is_wep": false, + "ap_mac": "80:22:22:22:22:22", + "map_id": null, + "site_id": "574e86994566ffb914a2683c" + } + ], + "downlink_table": [], + "vwire_vap_table": [], + "bytes-d": 204913232, + "tx_bytes-d": 1921569, + "rx_bytes-d": 202991663, + "bytes-r": 9757772, + "last_uplink": { + "uplink_mac": "f0:22:22:22:22:22", + "uplink_remote_port": 15 + }, + "stat": { + "site_id": "574e86994566ffb914a2683c", + "o": "ap", + "oid": "80:22:a8:22:22:22", + "ap": "80:22:a8:22:22:22", + "time": 1562207100000, + "datetime": "2019-07-04T02:25:00Z", + "guest-wifi0-rx_packets": 0, + "guest-wifi1-rx_packets": 0, + "user-wifi1-rx_packets": 31373230, + "user-wifi0-rx_packets": 169790, + "user-rx_packets": 31543020, + "guest-rx_packets": 0, + "wifi0-rx_packets": 169790, + "wifi1-rx_packets": 31373230, + "rx_packets": 31543020, + "guest-wifi0-rx_bytes": 0, + "guest-wifi1-rx_bytes": 0, + "user-wifi1-rx_bytes": 42049645434, + "user-wifi0-rx_bytes": 16755639, + "user-rx_bytes": 42066401073, + "guest-rx_bytes": 0, + "wifi0-rx_bytes": 16755639, + "wifi1-rx_bytes": 42049645434, + "rx_bytes": 42066401073, + "guest-wifi0-rx_errors": 0, + "guest-wifi1-rx_errors": 0, + "user-wifi1-rx_errors": 150651, + "user-wifi0-rx_errors": 0, + "user-rx_errors": 150651, + "guest-rx_errors": 0, + "wifi0-rx_errors": 0, + "wifi1-rx_errors": 150651, + "rx_errors": 150651, + "guest-wifi0-rx_dropped": 0, + "guest-wifi1-rx_dropped": 0, + "user-wifi1-rx_dropped": 150651, + "user-wifi0-rx_dropped": 0, + "user-rx_dropped": 150651, + "guest-rx_dropped": 0, + "wifi0-rx_dropped": 0, + "wifi1-rx_dropped": 150651, + "rx_dropped": 150651, + "guest-wifi0-rx_crypts": 0, + "guest-wifi1-rx_crypts": 0, + "user-wifi1-rx_crypts": 150651, + "user-wifi0-rx_crypts": 0, + "user-rx_crypts": 150651, + "guest-rx_crypts": 0, + "wifi0-rx_crypts": 0, + "wifi1-rx_crypts": 150651, + "rx_crypts": 150651, + "guest-wifi0-rx_frags": 0, + "guest-wifi1-rx_frags": 0, + "user-wifi1-rx_frags": 0, + "user-wifi0-rx_frags": 0, + "user-rx_frags": 0, + "guest-rx_frags": 0, + "wifi0-rx_frags": 0, + "wifi1-rx_frags": 0, + "rx_frags": 0, + "guest-wifi0-tx_packets": 0, + "guest-wifi1-tx_packets": 0, + "user-wifi1-tx_packets": 7125589, + "user-wifi0-tx_packets": 210389, + "user-tx_packets": 7335978, + "guest-tx_packets": 0, + "wifi0-tx_packets": 210389, + "wifi1-tx_packets": 7125589, + "tx_packets": 7335978, + "guest-wifi0-tx_bytes": 0, + "guest-wifi1-tx_bytes": 0, + "user-wifi1-tx_bytes": 3011293823, + "user-wifi0-tx_bytes": 25966558, + "user-tx_bytes": 3037260381, + "guest-tx_bytes": 0, + "wifi0-tx_bytes": 25966558, + "wifi1-tx_bytes": 3011293823, + "tx_bytes": 3037260381, + "guest-wifi0-tx_errors": 0, + "guest-wifi1-tx_errors": 0, + "user-wifi1-tx_errors": 102193, + "user-wifi0-tx_errors": 0, + "user-tx_errors": 102193, + "guest-tx_errors": 0, + "wifi0-tx_errors": 0, + "wifi1-tx_errors": 102193, + "tx_errors": 102193, + "guest-wifi0-tx_dropped": 296, + "guest-wifi1-tx_dropped": 296, + "user-wifi1-tx_dropped": 0, + "user-wifi0-tx_dropped": 0, + "user-tx_dropped": 0, + "guest-tx_dropped": 592, + "wifi0-tx_dropped": 296, + "wifi1-tx_dropped": 296, + "tx_dropped": 592, + "guest-wifi0-tx_retries": 0, + "guest-wifi1-tx_retries": 0, + "user-wifi1-tx_retries": 519734, + "user-wifi0-tx_retries": 90225, + "user-tx_retries": 609959, + "guest-tx_retries": 0, + "wifi0-tx_retries": 90225, + "wifi1-tx_retries": 519734, + "tx_retries": 609959, + "guest-wifi0-mac_filter_rejections": 0, + "guest-wifi1-mac_filter_rejections": 0, + "user-wifi1-mac_filter_rejections": 0, + "user-wifi0-mac_filter_rejections": 0, + "user-mac_filter_rejections": 0, + "guest-mac_filter_rejections": 0, + "wifi0-mac_filter_rejections": 0, + "wifi1-mac_filter_rejections": 0, + "mac_filter_rejections": 0, + "guest-wifi0-wifi_tx_attempts": 0, + "guest-wifi1-wifi_tx_attempts": 0, + "user-wifi1-wifi_tx_attempts": 4419026, + "user-wifi0-wifi_tx_attempts": 255999, + "user-wifi_tx_attempts": 4675025, + "guest-wifi_tx_attempts": 0, + "wifi0-wifi_tx_attempts": 255999, + "wifi1-wifi_tx_attempts": 4419026, + "wifi_tx_attempts": 4675025, + "guest-wifi0-wifi_tx_dropped": 0, + "guest-wifi1-wifi_tx_dropped": 0, + "user-wifi1-wifi_tx_dropped": 25, + "user-wifi0-wifi_tx_dropped": 2, + "user-wifi_tx_dropped": 27, + "guest-wifi_tx_dropped": 0, + "wifi0-wifi_tx_dropped": 2, + "wifi1-wifi_tx_dropped": 25, + "wifi_tx_dropped": 27, + "bytes": 45103661454, + "duration": 17988000, + "user-wifi1-ath2-574e96614566ffb914a26874-rx_packets": 31373230, + "user-wifi1-ath2-574e96614566ffb914a26874-rx_bytes": 42049645434, + "user-wifi1-ath2-574e96614566ffb914a26874-tx_packets": 7125589, + "user-wifi1-ath2-574e96614566ffb914a26874-tx_bytes": 3011293823, + "user-wifi1-ath2-574e96614566ffb914a26874-tx_errors": 102193, + "user-wifi1-ath2-574e96614566ffb914a26874-tx_retries": 519734, + "user-wifi1-ath2-574e96614566ffb914a26874-wifi_tx_attempts": 4419026, + "user-wifi0-ath0-574e96614566ffb914a26874-rx_packets": 169790, + "user-wifi0-ath0-574e96614566ffb914a26874-rx_bytes": 16755639, + "user-wifi0-ath0-574e96614566ffb914a26874-tx_packets": 210389, + "user-wifi0-ath0-574e96614566ffb914a26874-tx_bytes": 25966558, + "user-wifi0-ath0-574e96614566ffb914a26874-tx_retries": 90225, + "user-wifi0-ath0-574e96614566ffb914a26874-wifi_tx_attempts": 255999, + "guest-wifi1-ath3-574e96834566ffb914a26875-tx_dropped": 296, + "guest-wifi0-ath1-574e96834566ffb914a26875-tx_dropped": 296, + "user-wifi1-ath2-574e96614566ffb914a26874-rx_errors": 150651, + "user-wifi1-ath2-574e96614566ffb914a26874-rx_dropped": 150651, + "user-wifi1-ath2-574e96614566ffb914a26874-rx_crypts": 150651, + "user-wifi0-ath0-574e96614566ffb914a26874-wifi_tx_dropped": 2, + "user-wifi1-ath2-574e96614566ffb914a26874-wifi_tx_dropped": 25 + }, + "tx_bytes": 3037260381, + "rx_bytes": 42066401073, + "bytes": 45103661454, + "vwireEnabled": false, + "uplink_table": [], + "num_sta": 6, + "user-num_sta": 6, + "guest-num_sta": 0 +} diff --git a/core/unifi/examples/ugw.json b/core/unifi/examples/ugw.json new file mode 100644 index 00000000..117b14f7 --- /dev/null +++ b/core/unifi/examples/ugw.json @@ -0,0 +1,371 @@ +{ + "_id": "59a35da745663e6cc82600f6", + "adopted": true, + "cfgversion": "bf9f0335063fe6ea", + "config_network": { + "type": "dhcp", + "ip": "192.168.2.0" + }, + "ethernet_table": [ + { + "mac": "22:22:00:22:22:00", + "num_port": 1, + "name": "eth0" + }, + { + "mac": "22:22:00:22:22:00", + "num_port": 1, + "name": "eth1" + }, + { + "mac": "22:22:00:22:22:00", + "num_port": 1, + "name": "eth2" + } + ], + "fw_caps": 184323, + "inform_ip": "192.168.3.1", + "inform_url": "http://security:8080/inform", + "ip": "3.1.33.7", + "led_override": "default", + "license_state": "registered", + "mac": "22:22:00:22:22:00", + "model": "UGW3", + "name": "gateway", + "outdoor_mode_override": "default", + "serial": "xxxyyyzzz", + "site_id": "574e86994566ffb914a2683c", + "type": "ugw", + "usg_caps": 786431, + "version": "4.4.41.5193700", + "required_version": "4.0.0", + "ethernet_overrides": [ + { + "ifname": "eth1", + "networkgroup": "LAN" + }, + { + "ifname": "eth0", + "networkgroup": "WAN" + } + ], + "hw_caps": 0, + "board_rev": 16, + "unsupported": false, + "unsupported_reason": 0, + "device_id": "59a35da745663e6cc82600f6", + "state": 1, + "last_seen": 1562311857, + "upgradable": false, + "adoptable_when_upgraded": false, + "rollupgrade": false, + "known_cfgversion": "bf9f0335063fe6ea", + "uptime": 3191626, + "_uptime": 3191626, + "locating": false, + "connect_request_ip": "192.168.2.1", + "connect_request_port": "35615", + "sys_stats": { + "loadavg_1": "0.01", + "loadavg_15": "0.12", + "loadavg_5": "0.06", + "mem_buffer": 62406656, + "mem_total": 507412480, + "mem_used": 397500416 + }, + "system-stats": { + "cpu": "14", + "mem": "30", + "uptime": "3191066" + }, + "guest_token": "83342830AE9C0641DC39DD2759C122A1", + "speedtest-status": { + "latency": 14, + "rundate": 1562310531, + "runtime": 172, + "status_download": 2, + "status_ping": 2, + "status_summary": 2, + "status_upload": 2, + "xput_download": 157.36776733398438, + "xput_upload": 37.90521240234375 + }, + "speedtest-status-saved": true, + "wan1": { + "tx_bytes-r": 2852355, + "rx_bytes-r": 1224743, + "bytes-r": 4077098, + "max_speed": 1000, + "type": "wire", + "name": "wan", + "ifname": "eth0", + "ip": "3.1.33.7", + "netmask": "255.255.254.0", + "mac": "22:22:00:22:22:00", + "up": true, + "speed": 1000, + "full_duplex": true, + "rx_bytes": 2648236513108, + "rx_dropped": 34030, + "rx_errors": 0, + "rx_packets": 3068347172, + "tx_bytes": 3009601283006, + "tx_dropped": 0, + "tx_errors": 0, + "tx_packets": 2859713220, + "rx_multicast": 939111, + "enable": true, + "dns": [ + "1.1.1.1", + "8.8.8.8" + ], + "gateway": "3.1.33.8" + }, + "port_table": [ + { + "name": "wan", + "ifname": "eth0", + "ip": "3.1.33.7", + "netmask": "255.255.254.0", + "mac": "22:22:00:22:22:00", + "up": true, + "speed": 1000, + "full_duplex": true, + "rx_bytes": 2648236513108, + "rx_dropped": 34030, + "rx_errors": 0, + "rx_packets": 3068347172, + "tx_bytes": 3009601283006, + "tx_dropped": 0, + "tx_errors": 0, + "tx_packets": 2859713220, + "rx_multicast": 939111, + "enable": true, + "dns": [ + "216.146.35.35", + "216.146.36.36" + ], + "gateway": "3.1.33.8" + }, + { + "name": "lan", + "ifname": "eth1", + "ip": "192.168.2.1", + "netmask": "255.255.252.0", + "mac": "22:22:00:22:22:00", + "up": true, + "speed": 1000, + "full_duplex": true, + "rx_bytes": 2911311797255, + "rx_dropped": 3438, + "rx_errors": 0, + "rx_packets": 2659342049, + "tx_bytes": 2140222188895, + "tx_dropped": 0, + "tx_errors": 0, + "tx_packets": 2734245088, + "rx_multicast": 11929365, + "enable": true + }, + { + "name": "lan2", + "ifname": "eth2", + "ip": "0.0.0.0", + "netmask": "0.0.0.0", + "mac": "22:22:00:22:22:00", + "up": false, + "speed": 0, + "full_duplex": false, + "rx_bytes": 0, + "rx_dropped": 0, + "rx_errors": 0, + "rx_packets": 0, + "tx_bytes": 0, + "tx_dropped": 0, + "tx_errors": 0, + "tx_packets": 0, + "rx_multicast": 0, + "enable": false + } + ], + "network_table": [ + { + "_id": "574e8de34566ffb914a26862", + "is_nat": true, + "dhcpd_dns_enabled": false, + "purpose": "guest", + "dhcpd_leasetime": "86400", + "igmp_snooping": true, + "dhcpguard_enabled": false, + "dhcpd_start": "192.168.5.1", + "enabled": true, + "dhcpd_stop": "192.168.5.254", + "dhcpd_wins_enabled": false, + "domain_name": "guest.lan", + "dhcpd_enabled": true, + "ip_subnet": "192.168.5.0/23", + "vlan": "5", + "networkgroup": "LAN", + "name": "Public Wireless", + "site_id": "574e86994566ffb914a2683c", + "dhcpd_ip_1": "", + "vlan_enabled": true, + "dhcpd_gateway_enabled": false, + "dhcpd_time_offset_enabled": false, + "ipv6_interface_type": "none", + "dhcp_relay_enabled": false, + "mac": "22:22:00:22:22:00", + "is_guest": true, + "ip": "192.168.5.0", + "up": "true", + "num_sta": 1, + "rx_bytes": 578602537, + "rx_packets": 471151, + "tx_bytes": 182318948, + "tx_packets": 239651 + }, + { + "_id": "59a362f645663e6cc8260133", + "is_nat": true, + "dhcpd_dns_enabled": false, + "purpose": "corporate", + "dhcpd_leasetime": 86400, + "dhcpd_start": "192.168.68.2", + "dhcpd_stop": "192.168.68.250", + "enabled": true, + "domain_name": "secure.lan", + "dhcpd_enabled": true, + "vlan": "69", + "ip_subnet": "192.168.69.1/23", + "networkgroup": "LAN", + "name": "Security Network", + "site_id": "574e86994566ffb914a2683c", + "vlan_enabled": true, + "dhcpd_ntp_1": "192.168.69.1", + "dhcpd_gateway_enabled": false, + "dhcpd_time_offset_enabled": false, + "dhcp_relay_enabled": false, + "dhcpd_ntp_enabled": true, + "ipv6_interface_type": "none", + "dhcpd_unifi_controller": "192.168.3.1", + "igmp_snooping": true, + "mac": "22:22:00:22:22:00", + "is_guest": false, + "ip": "192.168.69.1", + "up": "true", + "num_sta": 11, + "rx_bytes": 5221725, + "rx_packets": 70663, + "tx_bytes": 0, + "tx_packets": 0 + }, + { + "_id": "574e869d4566ffb914a26841", + "purpose": "corporate", + "dhcpd_leasetime": "86400", + "igmp_snooping": false, + "dhcpd_ntp_1": "192.168.2.1", + "dhcpguard_enabled": false, + "dhcpd_gateway_enabled": false, + "dhcpd_time_offset_enabled": false, + "dhcpd_start": "192.168.1.1", + "dhcpd_unifi_controller": "192.168.3.1", + "dhcpd_stop": "192.168.1.254", + "enabled": true, + "domain_name": "home.lan", + "dhcpd_enabled": true, + "ip_subnet": "192.168.2.1/22", + "networkgroup": "LAN", + "dhcpd_ip_1": "", + "vlan_enabled": false, + "is_nat": true, + "dhcpd_dns_enabled": false, + "dhcp_relay_enabled": false, + "dhcpd_wins_enabled": false, + "upnp_lan_enabled": true, + "dhcpd_ntp_enabled": true, + "name": "Home Network", + "site_id": "574e86994566ffb914a2683c", + "attr_no_delete": true, + "attr_hidden_id": "LAN", + "ipv6_interface_type": "none", + "mac": "22:22:00:22:22:00", + "is_guest": false, + "ip": "192.168.2.1", + "up": "true", + "num_sta": 30, + "rx_bytes": 2099754971983, + "rx_packets": 2689749160, + "tx_bytes": 2877873632166, + "tx_packets": 2579198457 + } + ], + "uplink": { + "drops": 40, + "enable": true, + "full_duplex": true, + "gateways": [ + "3.1.33.8" + ], + "ip": "3.1.33.7", + "latency": 103, + "mac": "22:22:00:22:22:00", + "name": "eth0", + "nameservers": [ + "1.1.1.1", + "8.8.8.8" + ], + "netmask": "255.255.254.0", + "num_port": 1, + "rx_bytes": 2648236513108, + "rx_dropped": 34030, + "rx_errors": 0, + "rx_multicast": 939111, + "rx_packets": 3068347172, + "speed": 1000, + "speedtest_lastrun": 1562310531, + "speedtest_ping": 14, + "speedtest_status": "Success", + "tx_bytes": 3009601283006, + "tx_dropped": 0, + "tx_errors": 0, + "tx_packets": 2859713220, + "up": true, + "uptime": 559088, + "xput_down": 157.368, + "xput_up": 37.905, + "tx_bytes-r": 2852355, + "rx_bytes-r": 1224743, + "bytes-r": 4077098, + "max_speed": 1000, + "type": "wire" + }, + "stat": { + "site_id": "574e86994566ffb914a2683c", + "o": "gw", + "oid": "22:22:00:22:22:00", + "gw": "22:22:00:22:22:00", + "time": 1562207100000, + "datetime": "2019-07-04T02:25:00Z", + "duration": 104466000, + "wan-rx_packets": 151387924, + "wan-rx_bytes": 111251311739, + "wan-tx_packets": 182985900, + "wan-tx_bytes": 230372237709, + "lan-rx_packets": 173953163, + "lan-rx_bytes": 226862410885, + "lan-tx_packets": 137029474, + "lan-tx_bytes": 89478206254, + "wan-rx_dropped": 561, + "lan-rx_dropped": 29 + }, + "tx_bytes": 2648236513108, + "rx_bytes": 3009601283006, + "bytes": 5657837796114, + "num_sta": 41, + "user-num_sta": 41, + "guest-num_sta": 0, + "num_desktop": 7, + "num_mobile": 2, + "num_handheld": 8 +} diff --git a/core/unifi/examples/usw.json b/core/unifi/examples/usw.json new file mode 100644 index 00000000..d70d6ab3 --- /dev/null +++ b/core/unifi/examples/usw.json @@ -0,0 +1,1720 @@ +{ + "_id": "59a35cee45663e6cc82600f0", + "adopted": true, + "board_rev": 7, + "cfgversion": "669564dd04994088", + "config_network": { + "type": "dhcp", + "ip": "192.168.1.6" + }, + "dot1x_portctrl_enabled": false, + "ethernet_table": [ + { + "mac": "22:22:00:22:22:00", + "num_port": 26, + "name": "eth0" + }, + { + "mac": "22:22:00:22:22:00", + "name": "srv0" + } + ], + "flowctrl_enabled": false, + "fw_caps": 712229, + "has_fan": true, + "has_temperature": true, + "inform_ip": "192.168.3.1", + "inform_url": "http://security:8080/inform", + "ip": "192.168.1.7", + "jumboframe_enabled": false, + "led_override": "default", + "license_state": "registered", + "mac": "22:22:00:22:22:00", + "model": "US24P250", + "name": "switch", + "outdoor_mode_override": "default", + "port_overrides": [ + { + "name": "APC UPS", + "poe_mode": "off", + "port_idx": 1, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "poe_mode": "auto", + "port_idx": 2, + "portconf_id": "574e869d4566ffb914a26847" + }, + { + "name": "Camera: Gate", + "poe_mode": "auto", + "port_idx": 3, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Bubba's Desktop", + "poe_mode": "auto", + "port_idx": 4, + "portconf_id": "574e869d4566ffb914a26845" + }, + { + "name": "Lexi's Desktop", + "poe_mode": "off", + "port_idx": 5, + "portconf_id": "574e869d4566ffb914a26845" + }, + { + "name": "Camera: Car", + "poe_mode": "auto", + "port_idx": 6, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Camera: Garage", + "poe_mode": "auto", + "port_idx": 7, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Office Tertiary Desk PD14", + "poe_mode": "off", + "port_idx": 8, + "portconf_id": "574e869d4566ffb914a26847" + }, + { + "name": "Camera: Pool", + "poe_mode": "auto", + "port_idx": 9, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Security: Home Port", + "poe_mode": "off", + "port_idx": 10, + "portconf_id": "574e869d4566ffb914a26847" + }, + { + "name": "8ch Relay Board", + "poe_mode": "auto", + "port_idx": 11, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Security: Secure Port", + "poe_mode": "off", + "port_idx": 12, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Upstairs WAP", + "poe_mode": "auto", + "port_idx": 13, + "portconf_id": "574e869d4566ffb914a26845" + }, + { + "name": "Downstairs WAP", + "poe_mode": "auto", + "port_idx": 15, + "portconf_id": "574e869d4566ffb914a26845" + }, + { + "name": "David's Desk", + "poe_mode": "off", + "port_idx": 16, + "portconf_id": "574e869d4566ffb914a26845" + }, + { + "name": "Camera: Door", + "poe_mode": "auto", + "port_idx": 17, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Camera: Porch", + "poe_mode": "auto", + "port_idx": 19, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Camera: Road", + "port_idx": 21, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Livingroom Stereo", + "poe_mode": "off", + "port_idx": 22, + "portconf_id": "574e869d4566ffb914a26845" + }, + { + "name": "Homerun Prime", + "poe_mode": "off", + "port_idx": 23, + "portconf_id": "574e869d4566ffb914a26845" + }, + { + "name": "gateway", + "poe_mode": "off", + "port_idx": 24, + "portconf_id": "574e869d4566ffb914a26845" + } + ], + "port_table": [ + { + "port_idx": 1, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 1202, + "rx_bytes": 227167212, + "rx_dropped": 0, + "rx_errors": 12, + "rx_multicast": 28260, + "rx_packets": 1153365, + "satisfaction": 85, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 417327, + "tx_bytes": 507571083, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2284158, + "tx_packets": 4465717, + "up": true, + "tx_bytes-r": 45, + "rx_bytes-r": 5, + "bytes-r": 50, + "name": "APC UPS", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 2, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26847", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": false, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 1175, + "rx_bytes": 1068032535, + "rx_dropped": 150, + "rx_errors": 0, + "rx_multicast": 3489, + "rx_packets": 11624994, + "satisfaction": 90, + "speed": 0, + "stp_pathcost": 0, + "stp_state": "disabled", + "tx_broadcast": 62176, + "tx_bytes": 41832520833, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 302928, + "tx_packets": 28160117, + "up": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "name": "Port 2", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 3, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 0", + "poe_current": "91.55", + "poe_enable": true, + "poe_good": true, + "poe_power": "4.84", + "poe_voltage": "52.88", + "rx_broadcast": 65216, + "rx_bytes": 3456851429405, + "rx_dropped": 157638, + "rx_errors": 0, + "rx_multicast": 164814, + "rx_packets": 2410688372, + "satisfaction": 90, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 353417, + "tx_bytes": 40005007443, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2419630, + "tx_packets": 564763412, + "up": true, + "tx_bytes-r": 12085, + "rx_bytes-r": 888603, + "bytes-r": 900689, + "name": "Camera: Gate", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 4, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": false, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 646153, + "rx_bytes": 4581272050, + "rx_dropped": 15683, + "rx_errors": 0, + "rx_multicast": 36698, + "rx_packets": 53602118, + "satisfaction": 90, + "speed": 0, + "stp_pathcost": 0, + "stp_state": "disabled", + "tx_broadcast": 452081, + "tx_bytes": 166341729228, + "tx_dropped": 10704730, + "tx_errors": 0, + "tx_multicast": 3414231, + "tx_packets": 122098881, + "up": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "name": "Bubba's Desktop", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 5, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": false, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 1186, + "rx_bytes": 913565372, + "rx_dropped": 2079, + "rx_errors": 0, + "rx_multicast": 9915, + "rx_packets": 8040327, + "satisfaction": 90, + "speed": 0, + "stp_pathcost": 0, + "stp_state": "disabled", + "tx_broadcast": 99303, + "tx_bytes": 13691997722, + "tx_dropped": 126800, + "tx_errors": 0, + "tx_multicast": 619240, + "tx_packets": 11897488, + "up": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "name": "Lexi's Desktop", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 6, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 2", + "poe_current": "75.07", + "poe_enable": true, + "poe_good": true, + "poe_power": "3.95", + "poe_voltage": "52.63", + "rx_broadcast": 15135, + "rx_bytes": 1683544880532, + "rx_dropped": 105097, + "rx_errors": 0, + "rx_multicast": 140206, + "rx_packets": 1145100603, + "satisfaction": 90, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 403490, + "tx_bytes": 25109031755, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2363833, + "tx_packets": 356126846, + "up": true, + "tx_bytes-r": 7672, + "rx_bytes-r": 504473, + "bytes-r": 512145, + "name": "Camera: Car", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 7, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 0", + "poe_current": "92.28", + "poe_enable": true, + "poe_good": true, + "poe_power": "4.85", + "poe_voltage": "52.56", + "rx_broadcast": 65316, + "rx_bytes": 2610602428826, + "rx_dropped": 157634, + "rx_errors": 0, + "rx_multicast": 164757, + "rx_packets": 1825440143, + "satisfaction": 90, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 353314, + "tx_bytes": 30130225938, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2419669, + "tx_packets": 424070512, + "up": true, + "tx_bytes-r": 9976, + "rx_bytes-r": 786139, + "bytes-r": 796116, + "name": "Camera: Garage", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 8, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26847", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": false, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 1970, + "rx_bytes": 57788865632, + "rx_dropped": 49, + "rx_errors": 1, + "rx_multicast": 5397, + "rx_packets": 81214364, + "satisfaction": 75, + "speed": 0, + "stp_pathcost": 0, + "stp_state": "disabled", + "tx_broadcast": 243126, + "tx_bytes": 106910126818, + "tx_dropped": 343060, + "tx_errors": 0, + "tx_multicast": 1620633, + "tx_packets": 96321547, + "up": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "name": "Office Tertiary Desk PD14", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 9, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 4", + "poe_current": "185.42", + "poe_enable": true, + "poe_good": true, + "poe_power": "9.81", + "poe_voltage": "52.88", + "rx_broadcast": 63647, + "rx_bytes": 2607385367644, + "rx_dropped": 157620, + "rx_errors": 0, + "rx_multicast": 164740, + "rx_packets": 1811240949, + "satisfaction": 90, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 354985, + "tx_bytes": 29502203517, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2419671, + "tx_packets": 414986830, + "up": true, + "tx_bytes-r": 9281, + "rx_bytes-r": 781308, + "bytes-r": 790589, + "name": "Camera: Pool", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 10, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26847", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 133159, + "rx_bytes": 2980426813696, + "rx_dropped": 86, + "rx_errors": 0, + "rx_multicast": 1194903, + "rx_packets": 2315914383, + "satisfaction": 90, + "speed": 1000, + "stp_pathcost": 20000, + "stp_state": "forwarding", + "tx_broadcast": 2154128, + "tx_bytes": 1464180769133, + "tx_dropped": 250473, + "tx_errors": 0, + "tx_multicast": 13471964, + "tx_packets": 2230137488, + "up": true, + "tx_bytes-r": 1250938, + "rx_bytes-r": 2919503, + "bytes-r": 4170441, + "name": "Security: Home Port", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 11, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 0", + "poe_current": "12.93", + "poe_enable": true, + "poe_good": true, + "poe_power": "0.69", + "poe_voltage": "53.01", + "rx_broadcast": 10728, + "rx_bytes": 252244504, + "rx_dropped": 0, + "rx_errors": 2, + "rx_multicast": 0, + "rx_packets": 2540659, + "satisfaction": 85, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 407892, + "tx_bytes": 496402591, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2312237, + "tx_packets": 6542398, + "up": true, + "tx_bytes-r": 120, + "rx_bytes-r": 79, + "bytes-r": 199, + "name": "8ch Relay Board", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 12, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 19342, + "rx_bytes": 190236042211, + "rx_dropped": 174281, + "rx_errors": 0, + "rx_multicast": 649832, + "rx_packets": 2704715442, + "satisfaction": 90, + "speed": 1000, + "stp_pathcost": 20000, + "stp_state": "forwarding", + "tx_broadcast": 395664, + "tx_bytes": 18974306738758, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 1886642, + "tx_packets": 13093826470, + "up": true, + "tx_bytes-r": 5653872, + "rx_bytes-r": 67700, + "bytes-r": 5721573, + "name": "Security: Secure Port", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 13, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 0", + "poe_current": "88.13", + "poe_enable": true, + "poe_good": true, + "poe_power": "4.65", + "poe_voltage": "52.76", + "rx_broadcast": 383577, + "rx_bytes": 550646722109, + "rx_dropped": 116302, + "rx_errors": 0, + "rx_multicast": 2950663, + "rx_packets": 892359442, + "satisfaction": 90, + "speed": 1000, + "stp_pathcost": 20000, + "stp_state": "forwarding", + "tx_broadcast": 2351476, + "tx_bytes": 1374251273399, + "tx_dropped": 614, + "tx_errors": 0, + "tx_multicast": 12430218, + "tx_packets": 1140545051, + "up": true, + "tx_bytes-r": 1098062, + "rx_bytes-r": 81853, + "bytes-r": 1179915, + "name": "Upstairs WAP", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 14, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": false, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 0, + "rx_bytes": 0, + "rx_dropped": 0, + "rx_errors": 0, + "rx_multicast": 0, + "rx_packets": 0, + "satisfaction": 100, + "speed": 0, + "stp_pathcost": 0, + "stp_state": "disabled", + "tx_broadcast": 0, + "tx_bytes": 0, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 0, + "tx_packets": 0, + "up": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "name": "Port 14", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 15, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 0", + "poe_current": "71.65", + "poe_enable": true, + "poe_good": true, + "poe_power": "3.77", + "poe_voltage": "52.63", + "rx_broadcast": 196313, + "rx_bytes": 155746936125, + "rx_dropped": 19700, + "rx_errors": 0, + "rx_multicast": 2064123, + "rx_packets": 254212324, + "satisfaction": 90, + "speed": 1000, + "stp_pathcost": 20000, + "stp_state": "forwarding", + "tx_broadcast": 2538787, + "tx_bytes": 229690921008, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 13311081, + "tx_packets": 260289095, + "up": true, + "tx_bytes-r": 20824, + "rx_bytes-r": 4227, + "bytes-r": 25051, + "name": "Downstairs WAP", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 16, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 11925, + "rx_bytes": 300038087723, + "rx_dropped": 6, + "rx_errors": 0, + "rx_multicast": 105090, + "rx_packets": 487779140, + "satisfaction": 90, + "speed": 1000, + "stp_pathcost": 20000, + "stp_state": "forwarding", + "tx_broadcast": 2698267, + "tx_bytes": 1161896194876, + "tx_dropped": 2542, + "tx_errors": 0, + "tx_multicast": 15097190, + "tx_packets": 936474098, + "up": true, + "tx_bytes-r": 792886, + "rx_bytes-r": 1134268, + "bytes-r": 1927154, + "name": "David's Desk", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 17, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 0", + "poe_current": "52.24", + "poe_enable": true, + "poe_good": true, + "poe_power": "2.75", + "poe_voltage": "52.69", + "rx_broadcast": 57982, + "rx_bytes": 3736764408104, + "rx_dropped": 157644, + "rx_errors": 1, + "rx_multicast": 157809, + "rx_packets": 2553432414, + "satisfaction": 75, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 360666, + "tx_bytes": 37300635720, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2433676, + "tx_packets": 525589037, + "up": true, + "tx_bytes-r": 11826, + "rx_bytes-r": 1204374, + "bytes-r": 1216200, + "name": "Camera: Door", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 18, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 106288, + "rx_bytes": 2133344721406, + "rx_dropped": 25, + "rx_errors": 12, + "rx_multicast": 311666, + "rx_packets": 2159594753, + "satisfaction": 75, + "speed": 1000, + "stp_pathcost": 20000, + "stp_state": "forwarding", + "tx_broadcast": 2629049, + "tx_bytes": 1194122124612, + "tx_dropped": 7147, + "tx_errors": 0, + "tx_multicast": 15063781, + "tx_packets": 1677508931, + "up": true, + "tx_bytes-r": 37435, + "rx_bytes-r": 1009309, + "bytes-r": 1046744, + "name": "Port 18", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 19, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 0", + "poe_current": "84.22", + "poe_enable": true, + "poe_good": true, + "poe_power": "4.43", + "poe_voltage": "52.56", + "rx_broadcast": 59295, + "rx_bytes": 1565104688294, + "rx_dropped": 157648, + "rx_errors": 0, + "rx_multicast": 157775, + "rx_packets": 1148468555, + "satisfaction": 90, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 359378, + "tx_bytes": 1645861732, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2433784, + "tx_packets": 21052239, + "up": true, + "tx_bytes-r": 8133, + "rx_bytes-r": 483735, + "bytes-r": 491868, + "name": "Camera: Porch", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 20, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": false, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 0, + "rx_bytes": 0, + "rx_dropped": 0, + "rx_errors": 0, + "rx_multicast": 0, + "rx_packets": 0, + "satisfaction": 100, + "speed": 0, + "stp_pathcost": 0, + "stp_state": "disabled", + "tx_broadcast": 0, + "tx_bytes": 0, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 0, + "tx_packets": 0, + "up": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "name": "Port 20", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 21, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 0", + "poe_current": "123.90", + "poe_enable": true, + "poe_good": true, + "poe_power": "6.56", + "poe_voltage": "52.95", + "rx_broadcast": 61014, + "rx_bytes": 3317256188719, + "rx_dropped": 157642, + "rx_errors": 0, + "rx_multicast": 157803, + "rx_packets": 2220162515, + "satisfaction": 90, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 357637, + "tx_bytes": 30626674529, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2433710, + "tx_packets": 428205094, + "up": true, + "tx_bytes-r": 9771, + "rx_bytes-r": 1006105, + "bytes-r": 1015877, + "name": "Camera: Road", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 22, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 14465, + "rx_bytes": 794839703, + "rx_dropped": 3, + "rx_errors": 0, + "rx_multicast": 1080600, + "rx_packets": 5377988, + "satisfaction": 90, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 2720299, + "tx_bytes": 9381221794, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 14294088, + "tx_packets": 37961870, + "up": true, + "tx_bytes-r": 4900, + "rx_bytes-r": 536, + "bytes-r": 5436, + "name": "Livingroom Stereo", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 23, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 532640, + "rx_bytes": 331010131889, + "rx_dropped": 35400, + "rx_errors": 0, + "rx_multicast": 576408, + "rx_packets": 261698587, + "satisfaction": 90, + "speed": 1000, + "stp_pathcost": 20000, + "stp_state": "forwarding", + "tx_broadcast": 2202860, + "tx_bytes": 15811798849, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 14799244, + "tx_packets": 184788576, + "up": true, + "tx_bytes-r": 1611, + "rx_bytes-r": 3806, + "bytes-r": 5418, + "name": "Homerun Prime", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 24, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": true, + "jumbo": false, + "lldp_table": [ + { + "lldp_chassis_id": "22:22:00:22:22:00", + "lldp_port_id": "eth1", + "lldp_system_name": "gateway" + } + ], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 186134, + "rx_bytes": 2149399426518, + "rx_dropped": 183, + "rx_errors": 0, + "rx_multicast": 4799002, + "rx_packets": 2730988091, + "satisfaction": 90, + "speed": 1000, + "stp_pathcost": 20000, + "stp_state": "forwarding", + "tx_broadcast": 2549473, + "tx_bytes": 2905955335082, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 11918890, + "tx_packets": 2655236464, + "up": true, + "tx_bytes-r": 2348698, + "rx_bytes-r": 393352, + "bytes-r": 2742050, + "name": "gateway", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 25, + "media": "SFP", + "port_poe": false, + "poe_caps": 0, + "speed_caps": 1048608, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": false, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "rx_broadcast": 0, + "rx_bytes": 0, + "rx_dropped": 0, + "rx_errors": 0, + "rx_multicast": 0, + "rx_packets": 0, + "satisfaction": 100, + "sfp_found": false, + "speed": 0, + "stp_pathcost": 0, + "stp_state": "disabled", + "tx_broadcast": 0, + "tx_bytes": 0, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 0, + "tx_packets": 0, + "up": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "name": "SFP 1", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 26, + "media": "SFP", + "port_poe": false, + "poe_caps": 0, + "speed_caps": 1048608, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": false, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "rx_broadcast": 0, + "rx_bytes": 0, + "rx_dropped": 0, + "rx_errors": 0, + "rx_multicast": 0, + "rx_packets": 0, + "satisfaction": 100, + "sfp_found": false, + "speed": 0, + "stp_pathcost": 0, + "stp_state": "disabled", + "tx_broadcast": 0, + "tx_bytes": 0, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 0, + "tx_packets": 0, + "up": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "name": "SFP 2", + "masked": false, + "aggregated_by": false + } + ], + "serial": "xxxyyyzzz", + "site_id": "574e86994566ffb914a2683c", + "stp_priority": "32768", + "stp_version": "rstp", + "type": "usw", + "version": "4.0.42.10433", + "required_version": "3.3.1", + "switch_caps": { + "feature_caps": 1022, + "max_mirror_sessions": 1, + "max_aggregate_sessions": 6 + }, + "hw_caps": 0, + "unsupported": false, + "unsupported_reason": 0, + "sys_error_caps": 0, + "device_id": "59a35cee45663e6cc82600f0", + "state": 1, + "last_seen": 1562309680, + "upgradable": false, + "adoptable_when_upgraded": false, + "rollupgrade": false, + "known_cfgversion": "669564dd04994088", + "uptime": 3188809, + "_uptime": 3188809, + "locating": false, + "connect_request_ip": "192.168.1.7", + "connect_request_port": "45941", + "sys_stats": { + "loadavg_1": "1.83", + "loadavg_15": "1.72", + "loadavg_5": "1.77", + "mem_buffer": 0, + "mem_total": 262397952, + "mem_used": 131473408 + }, + "system-stats": { + "cpu": "59.3", + "mem": "50.1", + "uptime": "3188809" + }, + "ssh_session_table": [], + "fan_level": 50, + "general_temperature": 43, + "overheating": false, + "total_max_power": 222, + "downlink_table": [ + { + "port_idx": 13, + "speed": 1000, + "full_duplex": true, + "mac": "22:22:00:22:22:00" + }, + { + "port_idx": 15, + "speed": 1000, + "full_duplex": true, + "mac": "22:22:00:22:22:00" + } + ], + "uplink": { + "full_duplex": true, + "ip": "192.168.1.7", + "mac": "22:22:00:22:22:00", + "name": "eth0", + "netmask": "255.255.252.0", + "num_port": 26, + "rx_bytes": 2149399426518, + "rx_dropped": 183, + "rx_errors": 0, + "rx_multicast": 0, + "rx_packets": 2730988091, + "speed": 1000, + "tx_bytes": 2905955335082, + "tx_dropped": 0, + "tx_errors": 0, + "tx_packets": 2655236464, + "up": true, + "port_idx": 24, + "media": "GE", + "max_speed": 1000, + "uplink_mac": "22:22:00:22:22:00", + "type": "wire", + "tx_bytes-r": 2348698, + "rx_bytes-r": 393352 + }, + "last_uplink": { + "uplink_mac": "22:22:00:22:22:00" + }, + "uplink_depth": 1, + "dhcp_server_table": [], + "stat": { + "site_id": "574e86994566ffb914a2683c", + "o": "sw", + "oid": "22:22:00:22:22:00", + "sw": "22:22:00:22:22:00", + "time": 1562207400000, + "datetime": "2019-07-04T02:30:00Z", + "rx_packets": 1521931792, + "rx_bytes": 1640634193054, + "rx_errors": 0, + "rx_dropped": 44998, + "rx_crypts": 0, + "rx_frags": 0, + "tx_packets": 1526591275, + "tx_bytes": 1641404646603, + "tx_errors": 0, + "tx_dropped": 230234, + "tx_retries": 0, + "rx_multicast": 477933, + "rx_broadcast": 134416, + "tx_multicast": 4372775, + "tx_broadcast": 1123817, + "bytes": 3282038839657, + "duration": 102277000, + "port_1-rx_packets": 37407, + "port_1-rx_bytes": 7345154, + "port_1-tx_packets": 142648, + "port_1-tx_bytes": 15425151, + "port_1-tx_multicast": 72854, + "port_1-tx_broadcast": 13075, + "port_3-rx_packets": 88198959, + "port_3-rx_bytes": 127291063971, + "port_3-tx_packets": 20230363, + "port_3-tx_bytes": 1436625813, + "port_3-rx_broadcast": 2037, + "port_3-tx_multicast": 78496, + "port_3-tx_broadcast": 11062, + "port_6-rx_packets": 37102295, + "port_6-rx_bytes": 54565186228, + "port_6-tx_packets": 11561353, + "port_6-tx_bytes": 814818610, + "port_6-rx_multicast": 4504, + "port_6-tx_multicast": 76688, + "port_6-tx_broadcast": 12634, + "port_7-rx_packets": 59149016, + "port_7-rx_bytes": 84615020479, + "port_7-tx_packets": 14033190, + "port_7-tx_bytes": 996438501, + "port_7-tx_multicast": 78496, + "port_7-tx_broadcast": 11058, + "port_9-rx_packets": 58736633, + "port_9-rx_bytes": 84549190443, + "port_9-tx_packets": 14151617, + "port_9-tx_bytes": 1004772261, + "port_9-tx_multicast": 78496, + "port_9-tx_broadcast": 11058, + "port_10-rx_packets": 267372091, + "port_10-rx_bytes": 281500610536, + "port_10-tx_packets": 563250041, + "port_10-tx_bytes": 567769155042, + "port_10-rx_multicast": 43302, + "port_10-tx_multicast": 424255, + "port_10-tx_broadcast": 119711, + "port_11-rx_packets": 81983, + "port_11-rx_bytes": 8144416, + "port_11-tx_packets": 209313, + "port_11-tx_bytes": 15405574, + "port_11-tx_multicast": 73730, + "port_11-tx_broadcast": 12758, + "port_12-rx_packets": 103277309, + "port_12-rx_bytes": 7258199289, + "port_12-tx_packets": 439910260, + "port_12-tx_bytes": 639760721999, + "port_12-tx_multicast": 60704, + "port_12-tx_broadcast": 12565, + "port_13-rx_packets": 246443105, + "port_13-rx_bytes": 198040237192, + "port_13-tx_packets": 78593344, + "port_13-tx_bytes": 57869606583, + "port_13-rx_multicast": 137299, + "port_13-rx_broadcast": 65040, + "port_13-tx_multicast": 355704, + "port_13-tx_broadcast": 72404, + "port_15-rx_packets": 91090086, + "port_15-rx_bytes": 129066815209, + "port_15-tx_packets": 21964312, + "port_15-tx_bytes": 8996022939, + "port_15-rx_broadcast": 6271, + "port_15-tx_multicast": 470685, + "port_15-tx_broadcast": 131171, + "port_16-rx_packets": 186203471, + "port_16-rx_bytes": 238718016683, + "port_16-tx_packets": 111909553, + "port_16-tx_bytes": 116205334442, + "port_16-tx_multicast": 484907, + "port_16-tx_broadcast": 137180, + "port_17-rx_packets": 88192775, + "port_17-rx_bytes": 129333707339, + "port_17-tx_packets": 18059043, + "port_17-tx_bytes": 1280177720, + "port_17-tx_multicast": 78951, + "port_17-tx_broadcast": 11288, + "port_18-rx_packets": 47274835, + "port_18-rx_bytes": 52416730761, + "port_18-tx_packets": 31288433, + "port_18-tx_bytes": 19604228682, + "port_18-rx_multicast": 10027, + "port_18-tx_multicast": 478207, + "port_18-tx_broadcast": 136852, + "port_19-rx_packets": 37113361, + "port_19-rx_bytes": 51866531433, + "port_19-tx_packets": 11858558, + "port_19-tx_bytes": 835844449, + "port_19-tx_multicast": 78952, + "port_19-tx_broadcast": 11216, + "port_21-rx_packets": 72039284, + "port_21-rx_bytes": 107639322810, + "port_21-tx_packets": 14367901, + "port_21-tx_bytes": 1026379138, + "port_21-rx_broadcast": 1926, + "port_21-tx_multicast": 78951, + "port_21-tx_broadcast": 11173, + "port_22-rx_packets": 176103, + "port_22-rx_bytes": 25390561, + "port_22-tx_packets": 1272735, + "port_22-tx_bytes": 294225324, + "port_22-rx_multicast": 35968, + "port_22-tx_multicast": 452266, + "port_22-tx_broadcast": 137038, + "port_23-rx_packets": 4246915, + "port_23-rx_bytes": 4976913808, + "port_23-rx_dropped": 1138, + "port_23-tx_packets": 2141027, + "port_23-tx_bytes": 251388436, + "port_23-rx_multicast": 18478, + "port_23-rx_broadcast": 17522, + "port_23-tx_multicast": 469756, + "port_23-tx_broadcast": 119922, + "port_24-rx_packets": 134576026, + "port_24-rx_bytes": 88659302916, + "port_24-tx_packets": 170136735, + "port_24-tx_bytes": 221668518676, + "port_24-rx_multicast": 153949, + "port_24-tx_multicast": 376773, + "port_24-tx_broadcast": 132998, + "port_1-rx_multicast": 881, + "port_3-rx_dropped": 5055, + "port_3-rx_multicast": 5283, + "port_6-rx_dropped": 3370, + "port_7-rx_dropped": 5052, + "port_7-rx_multicast": 5280, + "port_9-rx_dropped": 5052, + "port_9-rx_multicast": 5280, + "port_9-rx_broadcast": 2041, + "port_10-rx_broadcast": 4628, + "port_12-rx_dropped": 5055, + "port_12-rx_multicast": 19895, + "port_13-rx_dropped": 3759, + "port_17-rx_dropped": 5055, + "port_17-rx_multicast": 5055, + "port_17-rx_broadcast": 1811, + "port_19-rx_dropped": 5055, + "port_19-rx_multicast": 5055, + "port_19-rx_broadcast": 1883, + "port_21-rx_dropped": 5055, + "port_21-rx_multicast": 5055, + "port_7-rx_broadcast": 2041, + "port_18-rx_broadcast": 590, + "port_16-rx_multicast": 3329, + "port_15-rx_dropped": 800, + "port_15-rx_multicast": 17552, + "port_16-rx_broadcast": 262, + "port_11-rx_broadcast": 341, + "port_12-rx_broadcast": 534, + "port_6-rx_broadcast": 465, + "port_24-rx_broadcast": 4447, + "port_22-rx_broadcast": 404, + "port_10-tx_dropped": 195211, + "port_16-tx_dropped": 251, + "port_1-rx_broadcast": 20, + "port_4-rx_packets": 620138, + "port_4-rx_bytes": 96463826, + "port_4-rx_dropped": 552, + "port_4-tx_packets": 1510849, + "port_4-tx_bytes": 1559557263, + "port_4-tx_dropped": 34772, + "port_4-rx_multicast": 1741, + "port_4-rx_broadcast": 22153, + "port_4-tx_multicast": 103904, + "port_4-tx_broadcast": 18654 + }, + "tx_bytes": 2149399426518, + "rx_bytes": 2905955335082, + "bytes": 5055354761600, + "num_sta": 16, + "user-num_sta": 16, + "guest-num_sta": 0 +}, From ad34bf7f1d37a7c72bfab7b3e95c4ac01d69502f Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Fri, 5 Jul 2019 02:16:45 -0700 Subject: [PATCH 074/194] add comments --- core/unifi/examples/convert.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/unifi/examples/convert.sh b/core/unifi/examples/convert.sh index 91de843d..de5b2975 100755 --- a/core/unifi/examples/convert.sh +++ b/core/unifi/examples/convert.sh @@ -5,15 +5,21 @@ # It converts the go struct to an influx thing, like you see in uap_influx.go. # [prefix] is optional. I used it to do all the stat_ uap metrics. # Very crude, just helps skip a lot of copy/paste. +# path=$1 pre=$2 + +# Reads in the file one line at a time. while IFS='' read -r line; do + # Split each piece of the file out. name=$(echo "${line}" | awk '{print $1}') type=$(echo "${line}" | awk '{print $2}') json=$(echo "${line}" | awk '{print $3}') json=$(echo "${json}" | cut -d\" -f2) - if [ "$json" != "" ] && [ "$name" != "" ]; then + # Don't print junk lines. (it still prints some junk lines) + if [ "$json" != "" ]; then + # Add a .Val suffix if this is a FlexInt or FlexBool. [[ "$type" = Flex* ]] && suf=.Val echo "\"${pre}${json}\": u.Stat.${name}${suf}," fi From 9aeb9c4480bb98745405bb090f2e9c59f37dcb60 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Fri, 5 Jul 2019 03:13:24 -0700 Subject: [PATCH 075/194] Update client data. --- core/unifi/clients_influx.go | 25 +++++++------- core/unifi/clients_type.go | 64 +++++++++++++++++++----------------- 2 files changed, 47 insertions(+), 42 deletions(-) diff --git a/core/unifi/clients_influx.go b/core/unifi/clients_influx.go index ce30c7dd..7a4ee00d 100644 --- a/core/unifi/clients_influx.go +++ b/core/unifi/clients_influx.go @@ -1,7 +1,6 @@ package unifi import ( - "strconv" "time" influx "github.com/influxdata/influxdb1-client/v2" @@ -13,8 +12,8 @@ func (c Client) Points() ([]*influx.Point, error) { // Fix name and hostname fields. Sometimes one or the other is blank. switch { case c.Hostname == "" && c.Name == "": - c.Hostname = "-no-name-" - c.Name = "-no-name-" + c.Hostname = c.Mac + c.Name = c.Mac case c.Hostname == "" && c.Name != "": c.Hostname = c.Name case c.Name == "" && c.Hostname != "": @@ -40,13 +39,13 @@ func (c Client) Points() ([]*influx.Point, error) { "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": c.Authorized.Txt, + "sw_port": c.SwPort.Txt, + "os_class": c.OsClass.Txt, + "os_name": c.OsName.Txt, + "dev_cat": c.DevCat.Txt, + "dev_id": c.DevID.Txt, + "dev_vendor": c.DevVendor.Txt, + "dev_family": c.DevFamily.Txt, "is_11r": c.Is11R.Txt, "is_wired": c.IsWired.Txt, "is_guest": c.IsGuest.Txt, @@ -57,10 +56,11 @@ func (c Client) Points() ([]*influx.Point, error) { "powersave_enabled": c.PowersaveEnabled.Txt, "qos_policy_applied": c.QosPolicyApplied.Txt, "use_fixedip": c.UseFixedIP.Txt, - "channel": strconv.Itoa(c.Channel), - "vlan": strconv.Itoa(c.Vlan), + "channel": c.Channel.Txt, + "vlan": c.Vlan.Txt, } fields := map[string]interface{}{ + "anomalies": c.Anomalies, "ip": c.IP, "essid": c.Essid, "bssid": c.Bssid, @@ -95,6 +95,7 @@ func (c Client) Points() ([]*influx.Point, error) { "tx_power": c.TxPower, "tx_rate": c.TxRate, "uptime": c.Uptime, + "wifi_tx_attempts": c.WifiTxAttempts, "wired-rx_bytes": c.WiredRxBytes, "wired-rx_bytes-r": c.WiredRxBytesR, "wired-rx_packets": c.WiredRxPackets, diff --git a/core/unifi/clients_type.go b/core/unifi/clients_type.go index e2566e03..1004f1ce 100644 --- a/core/unifi/clients_type.go +++ b/core/unifi/clients_type.go @@ -5,28 +5,21 @@ type Clients []Client // Client defines all the data a connected-network client contains. type Client struct { - ID string `json:"_id"` - IsGuestByUAP FlexBool `json:"_is_guest_by_uap"` - IsGuestByUGW FlexBool `json:"_is_guest_by_ugw"` - IsGuestByUSW FlexBool `json:"_is_guest_by_usw"` - LastSeenByUAP int64 `json:"_last_seen_by_uap"` - LastSeenByUGW int64 `json:"_last_seen_by_ugw"` - LastSeenByUSW int64 `json:"_last_seen_by_usw"` - UptimeByUAP int64 `json:"_uptime_by_uap"` - UptimeByUGW int64 `json:"_uptime_by_ugw"` - UptimeByUSW int64 `json:"_uptime_by_usw"` - ApMac string `json:"ap_mac"` - ApName string `json:"-"` - AssocTime int64 `json:"assoc_time"` - Authorized FlexBool `json:"authorized"` - Bssid string `json:"bssid"` - BytesR int64 `json:"bytes-r"` - Ccq int64 `json:"ccq"` - Channel int `json:"channel"` - DevCat int `json:"dev_cat"` - DevFamily int `json:"dev_family"` - DevID int `json:"dev_id"` - DpiStats struct { + Anomalies int64 `json:"anomalies,omitempty"` + ApMac string `json:"ap_mac"` + ApName string `json:"-"` + AssocTime int64 `json:"assoc_time"` + Blocked bool `json:"blocked,omitempty"` + Bssid string `json:"bssid"` + BytesR int64 `json:"bytes-r"` + Ccq int64 `json:"ccq"` + Channel FlexInt `json:"channel"` + DevCat FlexInt `json:"dev_cat"` + DevFamily FlexInt `json:"dev_family"` + DevID FlexInt `json:"dev_id"` + DevVendor FlexInt `json:"dev_vendor,omitempty"` + DhcpendTime int `json:"dhcpend_time,omitempty"` + DpiStats struct { App FlexInt Cat FlexInt RxBytes FlexInt @@ -38,15 +31,22 @@ type Client struct { Essid string `json:"essid"` FirstSeen int64 `json:"first_seen"` FixedIP string `json:"fixed_ip"` - Hostname string `json:"hostname"` GwMac string `json:"gw_mac"` GwName string `json:"-"` - IdleTime int64 `json:"idle_time"` + Hostname string `json:"hostname"` + ID string `json:"_id"` IP string `json:"ip"` + IdleTime int64 `json:"idle_time"` Is11R FlexBool `json:"is_11r"` IsGuest FlexBool `json:"is_guest"` + IsGuestByUAP FlexBool `json:"_is_guest_by_uap"` + IsGuestByUGW FlexBool `json:"_is_guest_by_ugw"` + IsGuestByUSW FlexBool `json:"_is_guest_by_usw"` IsWired FlexBool `json:"is_wired"` LastSeen int64 `json:"last_seen"` + LastSeenByUAP int64 `json:"_last_seen_by_uap"` + LastSeenByUGW int64 `json:"_last_seen_by_ugw"` + LastSeenByUSW int64 `json:"_last_seen_by_usw"` LatestAssocTime int64 `json:"latest_assoc_time"` Mac string `json:"mac"` Name string `json:"name"` @@ -55,8 +55,8 @@ type Client struct { Noise int64 `json:"noise"` Note string `json:"note"` Noted FlexBool `json:"noted"` - OsClass int `json:"os_class"` - OsName int `json:"os_name"` + OsClass FlexInt `json:"os_class"` + OsName FlexInt `json:"os_name"` Oui string `json:"oui"` PowersaveEnabled FlexBool `json:"powersave_enabled"` QosPolicyApplied FlexBool `json:"qos_policy_applied"` @@ -75,17 +75,21 @@ type Client struct { SwDepth int `json:"sw_depth"` SwMac string `json:"sw_mac"` SwName string `json:"-"` - SwPort int `json:"sw_port"` + SwPort FlexInt `json:"sw_port"` TxBytes int64 `json:"tx_bytes"` TxBytesR int64 `json:"tx_bytes-r"` TxPackets int64 `json:"tx_packets"` TxPower int64 `json:"tx_power"` TxRate int64 `json:"tx_rate"` Uptime int64 `json:"uptime"` - UserID string `json:"user_id"` - UserGroupID string `json:"usergroup_id"` + UptimeByUAP int64 `json:"_uptime_by_uap"` + UptimeByUGW int64 `json:"_uptime_by_ugw"` + UptimeByUSW int64 `json:"_uptime_by_usw"` UseFixedIP FlexBool `json:"use_fixedip"` - Vlan int `json:"vlan"` + UserGroupID string `json:"usergroup_id"` + UserID string `json:"user_id"` + Vlan FlexInt `json:"vlan"` + WifiTxAttempts int64 `json:"wifi_tx_attempts"` WiredRxBytes int64 `json:"wired-rx_bytes"` WiredRxBytesR int64 `json:"wired-rx_bytes-r"` WiredRxPackets int64 `json:"wired-rx_packets"` From 493a399189f6672efeaabc7e425429351d8f5e59 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 7 Jul 2019 15:23:02 -0700 Subject: [PATCH 076/194] Add controller 5.11 support. --- core/unifi/.travis.yml | 1 + core/unifi/types.go | 5 +- core/unifi/uap_type.go | 297 +++++++++++++------------ core/unifi/uap_type_test.go | 53 +++++ core/unifi/unifi.go | 20 +- core/unifi/usg_type.go | 82 ++++--- core/unifi/usg_type_test.go | 59 +++++ core/unifi/usw_type.go | 422 +++++++++++++++++++----------------- core/unifi/usw_type_test.go | 93 ++++++++ 9 files changed, 658 insertions(+), 374 deletions(-) create mode 100644 core/unifi/uap_type_test.go create mode 100644 core/unifi/usg_type_test.go create mode 100644 core/unifi/usw_type_test.go diff --git a/core/unifi/.travis.yml b/core/unifi/.travis.yml index 24c1ed7e..a05c4c9f 100644 --- a/core/unifi/.travis.yml +++ b/core/unifi/.travis.yml @@ -12,3 +12,4 @@ install: - dep ensure script: - golangci-lint run --enable-all -e G402 +- go test ./... diff --git a/core/unifi/types.go b/core/unifi/types.go index 4c3920f0..46dc652f 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -54,10 +54,11 @@ type Unifi struct { baseURL string ErrorLog Logger DebugLog Logger + *server } -// Server is the /status endpoint from the Unifi controller. -type Server struct { +// server is the /status endpoint from the Unifi controller. +type server struct { Up FlexBool `json:"up"` ServerVersion string `json:"server_version"` UUID string `json:"uuid"` diff --git a/core/unifi/uap_type.go b/core/unifi/uap_type.go index 842a022a..7858a1f8 100644 --- a/core/unifi/uap_type.go +++ b/core/unifi/uap_type.go @@ -1,6 +1,9 @@ package unifi -import "time" +import ( + "encoding/json" + "time" +) // UAP represents all the data from the Ubiquiti Controller for a Unifi Access Point. type UAP struct { @@ -305,142 +308,7 @@ type UAP struct { UplinkMac string `json:"uplink_mac"` UplinkRemotePort int `json:"uplink_remote_port"` } `json:"last_uplink"` - Stat struct { - SiteID string `json:"site_id"` - O string `json:"o"` - Oid string `json:"oid"` - Ap string `json:"ap"` - Time FlexInt `json:"time"` - Datetime time.Time `json:"datetime"` - GuestWifi0RxPackets FlexInt `json:"guest-wifi0-rx_packets"` - GuestWifi1RxPackets FlexInt `json:"guest-wifi1-rx_packets"` - UserWifi1RxPackets FlexInt `json:"user-wifi1-rx_packets"` - UserWifi0RxPackets FlexInt `json:"user-wifi0-rx_packets"` - UserRxPackets FlexInt `json:"user-rx_packets"` - GuestRxPackets FlexInt `json:"guest-rx_packets"` - Wifi0RxPackets FlexInt `json:"wifi0-rx_packets"` - Wifi1RxPackets FlexInt `json:"wifi1-rx_packets"` - RxPackets FlexInt `json:"rx_packets"` - GuestWifi0RxBytes FlexInt `json:"guest-wifi0-rx_bytes"` - GuestWifi1RxBytes FlexInt `json:"guest-wifi1-rx_bytes"` - UserWifi1RxBytes FlexInt `json:"user-wifi1-rx_bytes"` - UserWifi0RxBytes FlexInt `json:"user-wifi0-rx_bytes"` - UserRxBytes FlexInt `json:"user-rx_bytes"` - GuestRxBytes FlexInt `json:"guest-rx_bytes"` - Wifi0RxBytes FlexInt `json:"wifi0-rx_bytes"` - Wifi1RxBytes FlexInt `json:"wifi1-rx_bytes"` - RxBytes FlexInt `json:"rx_bytes"` - GuestWifi0RxErrors FlexInt `json:"guest-wifi0-rx_errors"` - GuestWifi1RxErrors FlexInt `json:"guest-wifi1-rx_errors"` - UserWifi1RxErrors FlexInt `json:"user-wifi1-rx_errors"` - UserWifi0RxErrors FlexInt `json:"user-wifi0-rx_errors"` - UserRxErrors FlexInt `json:"user-rx_errors"` - GuestRxErrors FlexInt `json:"guest-rx_errors"` - Wifi0RxErrors FlexInt `json:"wifi0-rx_errors"` - Wifi1RxErrors FlexInt `json:"wifi1-rx_errors"` - RxErrors FlexInt `json:"rx_errors"` - GuestWifi0RxDropped FlexInt `json:"guest-wifi0-rx_dropped"` - GuestWifi1RxDropped FlexInt `json:"guest-wifi1-rx_dropped"` - UserWifi1RxDropped FlexInt `json:"user-wifi1-rx_dropped"` - UserWifi0RxDropped FlexInt `json:"user-wifi0-rx_dropped"` - UserRxDropped FlexInt `json:"user-rx_dropped"` - GuestRxDropped FlexInt `json:"guest-rx_dropped"` - Wifi0RxDropped FlexInt `json:"wifi0-rx_dropped"` - Wifi1RxDropped FlexInt `json:"wifi1-rx_dropped"` - RxDropped FlexInt `json:"rx_dropped"` - GuestWifi0RxCrypts FlexInt `json:"guest-wifi0-rx_crypts"` - GuestWifi1RxCrypts FlexInt `json:"guest-wifi1-rx_crypts"` - UserWifi1RxCrypts FlexInt `json:"user-wifi1-rx_crypts"` - UserWifi0RxCrypts FlexInt `json:"user-wifi0-rx_crypts"` - UserRxCrypts FlexInt `json:"user-rx_crypts"` - GuestRxCrypts FlexInt `json:"guest-rx_crypts"` - Wifi0RxCrypts FlexInt `json:"wifi0-rx_crypts"` - Wifi1RxCrypts FlexInt `json:"wifi1-rx_crypts"` - RxCrypts FlexInt `json:"rx_crypts"` - GuestWifi0RxFrags FlexInt `json:"guest-wifi0-rx_frags"` - GuestWifi1RxFrags FlexInt `json:"guest-wifi1-rx_frags"` - UserWifi1RxFrags FlexInt `json:"user-wifi1-rx_frags"` - UserWifi0RxFrags FlexInt `json:"user-wifi0-rx_frags"` - UserRxFrags FlexInt `json:"user-rx_frags"` - GuestRxFrags FlexInt `json:"guest-rx_frags"` - Wifi0RxFrags FlexInt `json:"wifi0-rx_frags"` - Wifi1RxFrags FlexInt `json:"wifi1-rx_frags"` - RxFrags FlexInt `json:"rx_frags"` - GuestWifi0TxPackets FlexInt `json:"guest-wifi0-tx_packets"` - GuestWifi1TxPackets FlexInt `json:"guest-wifi1-tx_packets"` - UserWifi1TxPackets FlexInt `json:"user-wifi1-tx_packets"` - UserWifi0TxPackets FlexInt `json:"user-wifi0-tx_packets"` - UserTxPackets FlexInt `json:"user-tx_packets"` - GuestTxPackets FlexInt `json:"guest-tx_packets"` - Wifi0TxPackets FlexInt `json:"wifi0-tx_packets"` - Wifi1TxPackets FlexInt `json:"wifi1-tx_packets"` - TxPackets FlexInt `json:"tx_packets"` - GuestWifi0TxBytes FlexInt `json:"guest-wifi0-tx_bytes"` - GuestWifi1TxBytes FlexInt `json:"guest-wifi1-tx_bytes"` - UserWifi1TxBytes FlexInt `json:"user-wifi1-tx_bytes"` - UserWifi0TxBytes FlexInt `json:"user-wifi0-tx_bytes"` - UserTxBytes FlexInt `json:"user-tx_bytes"` - GuestTxBytes FlexInt `json:"guest-tx_bytes"` - Wifi0TxBytes FlexInt `json:"wifi0-tx_bytes"` - Wifi1TxBytes FlexInt `json:"wifi1-tx_bytes"` - TxBytes FlexInt `json:"tx_bytes"` - GuestWifi0TxErrors FlexInt `json:"guest-wifi0-tx_errors"` - GuestWifi1TxErrors FlexInt `json:"guest-wifi1-tx_errors"` - UserWifi1TxErrors FlexInt `json:"user-wifi1-tx_errors"` - UserWifi0TxErrors FlexInt `json:"user-wifi0-tx_errors"` - UserTxErrors FlexInt `json:"user-tx_errors"` - GuestTxErrors FlexInt `json:"guest-tx_errors"` - Wifi0TxErrors FlexInt `json:"wifi0-tx_errors"` - Wifi1TxErrors FlexInt `json:"wifi1-tx_errors"` - TxErrors FlexInt `json:"tx_errors"` - GuestWifi0TxDropped FlexInt `json:"guest-wifi0-tx_dropped"` - GuestWifi1TxDropped FlexInt `json:"guest-wifi1-tx_dropped"` - UserWifi1TxDropped FlexInt `json:"user-wifi1-tx_dropped"` - UserWifi0TxDropped FlexInt `json:"user-wifi0-tx_dropped"` - UserTxDropped FlexInt `json:"user-tx_dropped"` - GuestTxDropped FlexInt `json:"guest-tx_dropped"` - Wifi0TxDropped FlexInt `json:"wifi0-tx_dropped"` - Wifi1TxDropped FlexInt `json:"wifi1-tx_dropped"` - TxDropped FlexInt `json:"tx_dropped"` - GuestWifi0TxRetries FlexInt `json:"guest-wifi0-tx_retries"` - GuestWifi1TxRetries FlexInt `json:"guest-wifi1-tx_retries"` - UserWifi1TxRetries FlexInt `json:"user-wifi1-tx_retries"` - UserWifi0TxRetries FlexInt `json:"user-wifi0-tx_retries"` - UserTxRetries FlexInt `json:"user-tx_retries"` - GuestTxRetries FlexInt `json:"guest-tx_retries"` - Wifi0TxRetries FlexInt `json:"wifi0-tx_retries"` - Wifi1TxRetries FlexInt `json:"wifi1-tx_retries"` - TxRetries FlexInt `json:"tx_retries"` - GuestWifi0MacFilterRejections FlexInt `json:"guest-wifi0-mac_filter_rejections"` - GuestWifi1MacFilterRejections FlexInt `json:"guest-wifi1-mac_filter_rejections"` - UserWifi1MacFilterRejections FlexInt `json:"user-wifi1-mac_filter_rejections"` - UserWifi0MacFilterRejections FlexInt `json:"user-wifi0-mac_filter_rejections"` - UserMacFilterRejections FlexInt `json:"user-mac_filter_rejections"` - GuestMacFilterRejections FlexInt `json:"guest-mac_filter_rejections"` - Wifi0MacFilterRejections FlexInt `json:"wifi0-mac_filter_rejections"` - Wifi1MacFilterRejections FlexInt `json:"wifi1-mac_filter_rejections"` - MacFilterRejections FlexInt `json:"mac_filter_rejections"` - GuestWifi0WifiTxAttempts FlexInt `json:"guest-wifi0-wifi_tx_attempts"` - GuestWifi1WifiTxAttempts FlexInt `json:"guest-wifi1-wifi_tx_attempts"` - UserWifi1WifiTxAttempts FlexInt `json:"user-wifi1-wifi_tx_attempts"` - UserWifi0WifiTxAttempts FlexInt `json:"user-wifi0-wifi_tx_attempts"` - UserWifiTxAttempts FlexInt `json:"user-wifi_tx_attempts"` - GuestWifiTxAttempts FlexInt `json:"guest-wifi_tx_attempts"` - Wifi0WifiTxAttempts FlexInt `json:"wifi0-wifi_tx_attempts"` - Wifi1WifiTxAttempts FlexInt `json:"wifi1-wifi_tx_attempts"` - WifiTxAttempts FlexInt `json:"wifi_tx_attempts"` - GuestWifi0WifiTxDropped FlexInt `json:"guest-wifi0-wifi_tx_dropped"` - GuestWifi1WifiTxDropped FlexInt `json:"guest-wifi1-wifi_tx_dropped"` - UserWifi1WifiTxDropped FlexInt `json:"user-wifi1-wifi_tx_dropped"` - UserWifi0WifiTxDropped FlexInt `json:"user-wifi0-wifi_tx_dropped"` - UserWifiTxDropped FlexInt `json:"user-wifi_tx_dropped"` - GuestWifiTxDropped FlexInt `json:"guest-wifi_tx_dropped"` - Wifi0WifiTxDropped FlexInt `json:"wifi0-wifi_tx_dropped"` - Wifi1WifiTxDropped FlexInt `json:"wifi1-wifi_tx_dropped"` - WifiTxDropped FlexInt `json:"wifi_tx_dropped"` - Bytes FlexInt `json:"bytes"` - Duration FlexInt `json:"duration"` - } `json:"stat,omitempty"` + Stat *UAPStat `json:"stat"` TxBytes FlexInt `json:"tx_bytes"` RxBytes FlexInt `json:"rx_bytes"` Bytes FlexInt `json:"bytes"` @@ -451,3 +319,158 @@ type UAP struct { GuestNumSta int `json:"guest-num_sta"` TwoPhaseAdopt FlexBool `json:"two_phase_adopt,omitempty"` } + +// UAPStat holds the "stat" data for an access point. +// This is split out because of a JSON data format change from 5.10 to 5.11. +type UAPStat struct { + *ap +} +type ap struct { + SiteID string `json:"site_id"` + O string `json:"o"` + Oid string `json:"oid"` + Ap string `json:"ap"` + Time FlexInt `json:"time"` + Datetime time.Time `json:"datetime"` + GuestWifi0RxPackets FlexInt `json:"guest-wifi0-rx_packets"` + GuestWifi1RxPackets FlexInt `json:"guest-wifi1-rx_packets"` + UserWifi1RxPackets FlexInt `json:"user-wifi1-rx_packets"` + UserWifi0RxPackets FlexInt `json:"user-wifi0-rx_packets"` + UserRxPackets FlexInt `json:"user-rx_packets"` + GuestRxPackets FlexInt `json:"guest-rx_packets"` + Wifi0RxPackets FlexInt `json:"wifi0-rx_packets"` + Wifi1RxPackets FlexInt `json:"wifi1-rx_packets"` + RxPackets FlexInt `json:"rx_packets"` + GuestWifi0RxBytes FlexInt `json:"guest-wifi0-rx_bytes"` + GuestWifi1RxBytes FlexInt `json:"guest-wifi1-rx_bytes"` + UserWifi1RxBytes FlexInt `json:"user-wifi1-rx_bytes"` + UserWifi0RxBytes FlexInt `json:"user-wifi0-rx_bytes"` + UserRxBytes FlexInt `json:"user-rx_bytes"` + GuestRxBytes FlexInt `json:"guest-rx_bytes"` + Wifi0RxBytes FlexInt `json:"wifi0-rx_bytes"` + Wifi1RxBytes FlexInt `json:"wifi1-rx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + GuestWifi0RxErrors FlexInt `json:"guest-wifi0-rx_errors"` + GuestWifi1RxErrors FlexInt `json:"guest-wifi1-rx_errors"` + UserWifi1RxErrors FlexInt `json:"user-wifi1-rx_errors"` + UserWifi0RxErrors FlexInt `json:"user-wifi0-rx_errors"` + UserRxErrors FlexInt `json:"user-rx_errors"` + GuestRxErrors FlexInt `json:"guest-rx_errors"` + Wifi0RxErrors FlexInt `json:"wifi0-rx_errors"` + Wifi1RxErrors FlexInt `json:"wifi1-rx_errors"` + RxErrors FlexInt `json:"rx_errors"` + GuestWifi0RxDropped FlexInt `json:"guest-wifi0-rx_dropped"` + GuestWifi1RxDropped FlexInt `json:"guest-wifi1-rx_dropped"` + UserWifi1RxDropped FlexInt `json:"user-wifi1-rx_dropped"` + UserWifi0RxDropped FlexInt `json:"user-wifi0-rx_dropped"` + UserRxDropped FlexInt `json:"user-rx_dropped"` + GuestRxDropped FlexInt `json:"guest-rx_dropped"` + Wifi0RxDropped FlexInt `json:"wifi0-rx_dropped"` + Wifi1RxDropped FlexInt `json:"wifi1-rx_dropped"` + RxDropped FlexInt `json:"rx_dropped"` + GuestWifi0RxCrypts FlexInt `json:"guest-wifi0-rx_crypts"` + GuestWifi1RxCrypts FlexInt `json:"guest-wifi1-rx_crypts"` + UserWifi1RxCrypts FlexInt `json:"user-wifi1-rx_crypts"` + UserWifi0RxCrypts FlexInt `json:"user-wifi0-rx_crypts"` + UserRxCrypts FlexInt `json:"user-rx_crypts"` + GuestRxCrypts FlexInt `json:"guest-rx_crypts"` + Wifi0RxCrypts FlexInt `json:"wifi0-rx_crypts"` + Wifi1RxCrypts FlexInt `json:"wifi1-rx_crypts"` + RxCrypts FlexInt `json:"rx_crypts"` + GuestWifi0RxFrags FlexInt `json:"guest-wifi0-rx_frags"` + GuestWifi1RxFrags FlexInt `json:"guest-wifi1-rx_frags"` + UserWifi1RxFrags FlexInt `json:"user-wifi1-rx_frags"` + UserWifi0RxFrags FlexInt `json:"user-wifi0-rx_frags"` + UserRxFrags FlexInt `json:"user-rx_frags"` + GuestRxFrags FlexInt `json:"guest-rx_frags"` + Wifi0RxFrags FlexInt `json:"wifi0-rx_frags"` + Wifi1RxFrags FlexInt `json:"wifi1-rx_frags"` + RxFrags FlexInt `json:"rx_frags"` + GuestWifi0TxPackets FlexInt `json:"guest-wifi0-tx_packets"` + GuestWifi1TxPackets FlexInt `json:"guest-wifi1-tx_packets"` + UserWifi1TxPackets FlexInt `json:"user-wifi1-tx_packets"` + UserWifi0TxPackets FlexInt `json:"user-wifi0-tx_packets"` + UserTxPackets FlexInt `json:"user-tx_packets"` + GuestTxPackets FlexInt `json:"guest-tx_packets"` + Wifi0TxPackets FlexInt `json:"wifi0-tx_packets"` + Wifi1TxPackets FlexInt `json:"wifi1-tx_packets"` + TxPackets FlexInt `json:"tx_packets"` + GuestWifi0TxBytes FlexInt `json:"guest-wifi0-tx_bytes"` + GuestWifi1TxBytes FlexInt `json:"guest-wifi1-tx_bytes"` + UserWifi1TxBytes FlexInt `json:"user-wifi1-tx_bytes"` + UserWifi0TxBytes FlexInt `json:"user-wifi0-tx_bytes"` + UserTxBytes FlexInt `json:"user-tx_bytes"` + GuestTxBytes FlexInt `json:"guest-tx_bytes"` + Wifi0TxBytes FlexInt `json:"wifi0-tx_bytes"` + Wifi1TxBytes FlexInt `json:"wifi1-tx_bytes"` + TxBytes FlexInt `json:"tx_bytes"` + GuestWifi0TxErrors FlexInt `json:"guest-wifi0-tx_errors"` + GuestWifi1TxErrors FlexInt `json:"guest-wifi1-tx_errors"` + UserWifi1TxErrors FlexInt `json:"user-wifi1-tx_errors"` + UserWifi0TxErrors FlexInt `json:"user-wifi0-tx_errors"` + UserTxErrors FlexInt `json:"user-tx_errors"` + GuestTxErrors FlexInt `json:"guest-tx_errors"` + Wifi0TxErrors FlexInt `json:"wifi0-tx_errors"` + Wifi1TxErrors FlexInt `json:"wifi1-tx_errors"` + TxErrors FlexInt `json:"tx_errors"` + GuestWifi0TxDropped FlexInt `json:"guest-wifi0-tx_dropped"` + GuestWifi1TxDropped FlexInt `json:"guest-wifi1-tx_dropped"` + UserWifi1TxDropped FlexInt `json:"user-wifi1-tx_dropped"` + UserWifi0TxDropped FlexInt `json:"user-wifi0-tx_dropped"` + UserTxDropped FlexInt `json:"user-tx_dropped"` + GuestTxDropped FlexInt `json:"guest-tx_dropped"` + Wifi0TxDropped FlexInt `json:"wifi0-tx_dropped"` + Wifi1TxDropped FlexInt `json:"wifi1-tx_dropped"` + TxDropped FlexInt `json:"tx_dropped"` + GuestWifi0TxRetries FlexInt `json:"guest-wifi0-tx_retries"` + GuestWifi1TxRetries FlexInt `json:"guest-wifi1-tx_retries"` + UserWifi1TxRetries FlexInt `json:"user-wifi1-tx_retries"` + UserWifi0TxRetries FlexInt `json:"user-wifi0-tx_retries"` + UserTxRetries FlexInt `json:"user-tx_retries"` + GuestTxRetries FlexInt `json:"guest-tx_retries"` + Wifi0TxRetries FlexInt `json:"wifi0-tx_retries"` + Wifi1TxRetries FlexInt `json:"wifi1-tx_retries"` + TxRetries FlexInt `json:"tx_retries"` + GuestWifi0MacFilterRejections FlexInt `json:"guest-wifi0-mac_filter_rejections"` + GuestWifi1MacFilterRejections FlexInt `json:"guest-wifi1-mac_filter_rejections"` + UserWifi1MacFilterRejections FlexInt `json:"user-wifi1-mac_filter_rejections"` + UserWifi0MacFilterRejections FlexInt `json:"user-wifi0-mac_filter_rejections"` + UserMacFilterRejections FlexInt `json:"user-mac_filter_rejections"` + GuestMacFilterRejections FlexInt `json:"guest-mac_filter_rejections"` + Wifi0MacFilterRejections FlexInt `json:"wifi0-mac_filter_rejections"` + Wifi1MacFilterRejections FlexInt `json:"wifi1-mac_filter_rejections"` + MacFilterRejections FlexInt `json:"mac_filter_rejections"` + GuestWifi0WifiTxAttempts FlexInt `json:"guest-wifi0-wifi_tx_attempts"` + GuestWifi1WifiTxAttempts FlexInt `json:"guest-wifi1-wifi_tx_attempts"` + UserWifi1WifiTxAttempts FlexInt `json:"user-wifi1-wifi_tx_attempts"` + UserWifi0WifiTxAttempts FlexInt `json:"user-wifi0-wifi_tx_attempts"` + UserWifiTxAttempts FlexInt `json:"user-wifi_tx_attempts"` + GuestWifiTxAttempts FlexInt `json:"guest-wifi_tx_attempts"` + Wifi0WifiTxAttempts FlexInt `json:"wifi0-wifi_tx_attempts"` + Wifi1WifiTxAttempts FlexInt `json:"wifi1-wifi_tx_attempts"` + WifiTxAttempts FlexInt `json:"wifi_tx_attempts"` + GuestWifi0WifiTxDropped FlexInt `json:"guest-wifi0-wifi_tx_dropped"` + GuestWifi1WifiTxDropped FlexInt `json:"guest-wifi1-wifi_tx_dropped"` + UserWifi1WifiTxDropped FlexInt `json:"user-wifi1-wifi_tx_dropped"` + UserWifi0WifiTxDropped FlexInt `json:"user-wifi0-wifi_tx_dropped"` + UserWifiTxDropped FlexInt `json:"user-wifi_tx_dropped"` + GuestWifiTxDropped FlexInt `json:"guest-wifi_tx_dropped"` + Wifi0WifiTxDropped FlexInt `json:"wifi0-wifi_tx_dropped"` + Wifi1WifiTxDropped FlexInt `json:"wifi1-wifi_tx_dropped"` + WifiTxDropped FlexInt `json:"wifi_tx_dropped"` + Bytes FlexInt `json:"bytes"` + Duration FlexInt `json:"duration"` +} + +// UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Access Point Stat data. +func (v *UAPStat) UnmarshalJSON(data []byte) error { + var n struct { + ap `json:"ap"` + } + v.ap = &n.ap + err := json.Unmarshal(data, v.ap) // controller version 5.10. + if err != nil { + return json.Unmarshal(data, &n) // controller version 5.11. + } + return nil +} diff --git a/core/unifi/uap_type_test.go b/core/unifi/uap_type_test.go new file mode 100644 index 00000000..2ad1f982 --- /dev/null +++ b/core/unifi/uap_type_test.go @@ -0,0 +1,53 @@ +package unifi + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestUAPUnmarshalJSON(t *testing.T) { + testcontroller511 := `{ + "ap": { + "site_id": "mySite", + "o": "ap", + "oid": "00:00:00:00:00:00", + "ap": "00:00:00:00:00:00", + "time": 1577742600000, + "datetime": "2019-12-30T09:50:00Z", + "user-wifi1-rx_packets": 6596670, + "user-wifi0-rx_packets": 42659527, + "user-rx_packets": 49294197, + "guest-rx_packets": 0, + "wifi0-rx_packets": 42639527, + "wifi1-rx_packets": 6591670, + "rx_packets": 49299197}}` + + testcontroller510 := `{ + "site_id": "mySite", + "o": "ap", + "oid": "00:00:00:00:00:00", + "ap": "00:00:00:00:00:00", + "time": 1577742600000, + "datetime": "2019-12-30T09:50:00Z", + "user-wifi1-rx_packets": 6596670, + "user-wifi0-rx_packets": 42659527, + "user-rx_packets": 49294197, + "guest-rx_packets": 0, + "wifi0-rx_packets": 42639527, + "wifi1-rx_packets": 6591670, + "rx_packets": 49299197}` + + t.Parallel() + a := assert.New(t) + + u := &UAPStat{} + err := u.UnmarshalJSON([]byte(testcontroller510)) + a.Nil(err, "must be no error unmarshaling test strings") + a.Equal(float64(49299197), u.RxPackets.Val, "data was not properly unmarshaled") + + u = &UAPStat{} // reset + err = u.UnmarshalJSON([]byte(testcontroller511)) + a.Nil(err, "must be no error unmarshaling test strings") + a.Equal(float64(49299197), u.RxPackets.Val, "data was not properly unmarshaled") +} diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 93d28de9..76b53cf8 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -58,16 +58,22 @@ func (u *Unifi) getController(user, pass string) error { return errors.Errorf("authentication failed (user: %s): %s (status: %s)", user, u.baseURL+LoginPath, resp.Status) } - return nil + return errors.Wrap(u.getServer(), "unable to get server version") +} + +// getServer sets the controller's version and UUID. +func (u *Unifi) getServer() error { + var response struct { + Data server `json:"meta"` + } + u.server = &response.Data + return u.GetData(StatusPath, &response) } // GetServer returns the controller's version and UUID. -func (u *Unifi) GetServer() (Server, error) { - var response struct { - Data Server `json:"meta"` - } - err := u.GetData(StatusPath, &response) - return response.Data, err +// This method is deprecated and will go away in a future release, use u.Server* +func (u *Unifi) GetServer() (*server, error) { + return u.server, nil } // GetClients returns a response full of clients' data from the Unifi Controller. diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index 5ba8bc21..166eb5d3 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -1,6 +1,9 @@ package unifi -import "time" +import ( + "encoding/json" + "time" +) // USG represents all the data from the Ubiquiti Controller for a Unifi Security Gateway. type USG struct { @@ -230,32 +233,53 @@ type USG struct { MaxSpeed FlexInt `json:"max_speed"` Type string `json:"type"` } `json:"uplink"` - Stat struct { - SiteID string `json:"site_id"` - O string `json:"o"` - Oid string `json:"oid"` - Gw string `json:"gw"` - Time FlexInt `json:"time"` - Datetime time.Time `json:"datetime"` - Duration FlexInt `json:"duration"` - WanRxPackets FlexInt `json:"wan-rx_packets"` - WanRxBytes FlexInt `json:"wan-rx_bytes"` - WanTxPackets FlexInt `json:"wan-tx_packets"` - WanTxBytes FlexInt `json:"wan-tx_bytes"` - LanRxPackets FlexInt `json:"lan-rx_packets"` - LanRxBytes FlexInt `json:"lan-rx_bytes"` - LanTxPackets FlexInt `json:"lan-tx_packets"` - LanTxBytes FlexInt `json:"lan-tx_bytes"` - WanRxDropped FlexInt `json:"wan-rx_dropped"` - LanRxDropped FlexInt `json:"lan-rx_dropped"` - } `json:"stat"` - TxBytes FlexInt `json:"tx_bytes"` - RxBytes FlexInt `json:"rx_bytes"` - Bytes FlexInt `json:"bytes"` - NumSta FlexInt `json:"num_sta"` - UserNumSta FlexInt `json:"user-num_sta"` - GuestNumSta FlexInt `json:"guest-num_sta"` - NumDesktop FlexInt `json:"num_desktop"` - NumMobile FlexInt `json:"num_mobile"` - NumHandheld FlexInt `json:"num_handheld"` + Stat *USGStat `json:"stat"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + NumSta FlexInt `json:"num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` + NumDesktop FlexInt `json:"num_desktop"` + NumMobile FlexInt `json:"num_mobile"` + NumHandheld FlexInt `json:"num_handheld"` +} + +// USGStat holds the "stat" data for a gateway. +// This is split out because of a JSON data format change from 5.10 to 5.11. +type USGStat struct { + *gw +} + +type gw struct { + SiteID string `json:"site_id"` + O string `json:"o"` + Oid string `json:"oid"` + Gw string `json:"gw"` + Time FlexInt `json:"time"` + Datetime time.Time `json:"datetime"` + Duration FlexInt `json:"duration"` + WanRxPackets FlexInt `json:"wan-rx_packets"` + WanRxBytes FlexInt `json:"wan-rx_bytes"` + WanTxPackets FlexInt `json:"wan-tx_packets"` + WanTxBytes FlexInt `json:"wan-tx_bytes"` + LanRxPackets FlexInt `json:"lan-rx_packets"` + LanRxBytes FlexInt `json:"lan-rx_bytes"` + LanTxPackets FlexInt `json:"lan-tx_packets"` + LanTxBytes FlexInt `json:"lan-tx_bytes"` + WanRxDropped FlexInt `json:"wan-rx_dropped"` + LanRxDropped FlexInt `json:"lan-rx_dropped"` +} + +// UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Gateway Stat data. +func (v *USGStat) UnmarshalJSON(data []byte) error { + var n struct { + gw `json:"gw"` + } + v.gw = &n.gw + err := json.Unmarshal(data, v.gw) // controller version 5.10. + if err != nil { + return json.Unmarshal(data, &n) // controller version 5.11. + } + return nil } diff --git a/core/unifi/usg_type_test.go b/core/unifi/usg_type_test.go new file mode 100644 index 00000000..962dd677 --- /dev/null +++ b/core/unifi/usg_type_test.go @@ -0,0 +1,59 @@ +package unifi + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestUSGUnmarshalJSON(t *testing.T) { + testcontroller511 := `{ + "gw": { + "site_id": "mySite", + "o": "gw", + "oid": "00:00:00:00:00:00", + "gw": "00:00:00:00:00:00", + "time": 1577742600000, + "datetime": "2019-12-30T09:50:00Z", + "bytes": 0, + "duration": 3590568000, + "wan-rx_packets": 299729434558, + "wan-rx_bytes": 299882768958208, + "wan-tx_packets": 249639259523, + "wan-tx_bytes": 169183252492369, + "lan-rx_packets": 78912349453, + "lan-rx_bytes": 37599596992669, + "lan-tx_packets": 12991234992, + "lan-tx_bytes": 11794664098210}}` + + testcontroller510 := `{ + "site_id": "mySite", + "o": "gw", + "oid": "00:00:00:00:00:00", + "gw": "00:00:00:00:00:00", + "time": 1577742600000, + "datetime": "2019-12-30T09:50:00Z", + "bytes": 0, + "duration": 3590568000, + "wan-rx_packets": 299729434558, + "wan-rx_bytes": 299882768958208, + "wan-tx_packets": 249639259523, + "wan-tx_bytes": 169183252492369, + "lan-rx_packets": 78912349453, + "lan-rx_bytes": 37599596992669, + "lan-tx_packets": 12991234992, + "lan-tx_bytes": 11794664098210}` + + t.Parallel() + a := assert.New(t) + + u := &USGStat{} + err := u.UnmarshalJSON([]byte(testcontroller510)) + a.Nil(err, "must be no error unmarshaling test strings") + a.Equal(float64(37599596992669), u.LanRxBytes.Val, "data was not properly unmarshaled") + + u = &USGStat{} // reset + err = u.UnmarshalJSON([]byte(testcontroller511)) + a.Nil(err, "must be no error unmarshaling test strings") + a.Equal(float64(37599596992669), u.LanRxBytes.Val, "data was not properly unmarshaled") +} diff --git a/core/unifi/usw_type.go b/core/unifi/usw_type.go index c2dc14ad..4ad891cf 100644 --- a/core/unifi/usw_type.go +++ b/core/unifi/usw_type.go @@ -1,6 +1,9 @@ package unifi -import "time" +import ( + "encoding/json" + "time" +) // USW represents all the data from the Ubiquiti Controller for a Unifi Switch. type USW struct { @@ -167,202 +170,223 @@ type USW struct { LastUplink struct { UplinkMac string `json:"uplink_mac"` } `json:"last_uplink"` - UplinkDepth FlexInt `json:"uplink_depth"` - Stat struct { - SiteID string `json:"site_id"` - O string `json:"o"` - Oid string `json:"oid"` - Sw string `json:"sw"` - Time FlexInt `json:"time"` - Datetime time.Time `json:"datetime"` - RxPackets FlexInt `json:"rx_packets"` - RxBytes FlexInt `json:"rx_bytes"` - RxErrors FlexInt `json:"rx_errors"` - RxDropped FlexInt `json:"rx_dropped"` - RxCrypts FlexInt `json:"rx_crypts"` - RxFrags FlexInt `json:"rx_frags"` - TxPackets FlexInt `json:"tx_packets"` - TxBytes FlexInt `json:"tx_bytes"` - TxErrors FlexInt `json:"tx_errors"` - TxDropped FlexInt `json:"tx_dropped"` - TxRetries FlexInt `json:"tx_retries"` - RxMulticast FlexInt `json:"rx_multicast"` - RxBroadcast FlexInt `json:"rx_broadcast"` - TxMulticast FlexInt `json:"tx_multicast"` - TxBroadcast FlexInt `json:"tx_broadcast"` - Bytes FlexInt `json:"bytes"` - Duration FlexInt `json:"duration"` - Port1RxPackets FlexInt `json:"port_1-rx_packets"` - Port1RxBytes FlexInt `json:"port_1-rx_bytes"` - Port1TxPackets FlexInt `json:"port_1-tx_packets"` - Port1TxBytes FlexInt `json:"port_1-tx_bytes"` - Port1TxMulticast FlexInt `json:"port_1-tx_multicast"` - Port1TxBroadcast FlexInt `json:"port_1-tx_broadcast"` - Port3RxPackets FlexInt `json:"port_3-rx_packets"` - Port3RxBytes FlexInt `json:"port_3-rx_bytes"` - Port3TxPackets FlexInt `json:"port_3-tx_packets"` - Port3TxBytes FlexInt `json:"port_3-tx_bytes"` - Port3RxBroadcast FlexInt `json:"port_3-rx_broadcast"` - Port3TxMulticast FlexInt `json:"port_3-tx_multicast"` - Port3TxBroadcast FlexInt `json:"port_3-tx_broadcast"` - Port6RxPackets FlexInt `json:"port_6-rx_packets"` - Port6RxBytes FlexInt `json:"port_6-rx_bytes"` - Port6TxPackets FlexInt `json:"port_6-tx_packets"` - Port6TxBytes FlexInt `json:"port_6-tx_bytes"` - Port6RxMulticast FlexInt `json:"port_6-rx_multicast"` - Port6TxMulticast FlexInt `json:"port_6-tx_multicast"` - Port6TxBroadcast FlexInt `json:"port_6-tx_broadcast"` - Port7RxPackets FlexInt `json:"port_7-rx_packets"` - Port7RxBytes FlexInt `json:"port_7-rx_bytes"` - Port7TxPackets FlexInt `json:"port_7-tx_packets"` - Port7TxBytes FlexInt `json:"port_7-tx_bytes"` - Port7TxMulticast FlexInt `json:"port_7-tx_multicast"` - Port7TxBroadcast FlexInt `json:"port_7-tx_broadcast"` - Port9RxPackets FlexInt `json:"port_9-rx_packets"` - Port9RxBytes FlexInt `json:"port_9-rx_bytes"` - Port9TxPackets FlexInt `json:"port_9-tx_packets"` - Port9TxBytes FlexInt `json:"port_9-tx_bytes"` - Port9TxMulticast FlexInt `json:"port_9-tx_multicast"` - Port9TxBroadcast FlexInt `json:"port_9-tx_broadcast"` - Port10RxPackets FlexInt `json:"port_10-rx_packets"` - Port10RxBytes FlexInt `json:"port_10-rx_bytes"` - Port10TxPackets FlexInt `json:"port_10-tx_packets"` - Port10TxBytes FlexInt `json:"port_10-tx_bytes"` - Port10RxMulticast FlexInt `json:"port_10-rx_multicast"` - Port10TxMulticast FlexInt `json:"port_10-tx_multicast"` - Port10TxBroadcast FlexInt `json:"port_10-tx_broadcast"` - Port11RxPackets FlexInt `json:"port_11-rx_packets"` - Port11RxBytes FlexInt `json:"port_11-rx_bytes"` - Port11TxPackets FlexInt `json:"port_11-tx_packets"` - Port11TxBytes FlexInt `json:"port_11-tx_bytes"` - Port11TxMulticast FlexInt `json:"port_11-tx_multicast"` - Port11TxBroadcast FlexInt `json:"port_11-tx_broadcast"` - Port12RxPackets FlexInt `json:"port_12-rx_packets"` - Port12RxBytes FlexInt `json:"port_12-rx_bytes"` - Port12TxPackets FlexInt `json:"port_12-tx_packets"` - Port12TxBytes FlexInt `json:"port_12-tx_bytes"` - Port12TxMulticast FlexInt `json:"port_12-tx_multicast"` - Port12TxBroadcast FlexInt `json:"port_12-tx_broadcast"` - Port13RxPackets FlexInt `json:"port_13-rx_packets"` - Port13RxBytes FlexInt `json:"port_13-rx_bytes"` - Port13TxPackets FlexInt `json:"port_13-tx_packets"` - Port13TxBytes FlexInt `json:"port_13-tx_bytes"` - Port13RxMulticast FlexInt `json:"port_13-rx_multicast"` - Port13RxBroadcast FlexInt `json:"port_13-rx_broadcast"` - Port13TxMulticast FlexInt `json:"port_13-tx_multicast"` - Port13TxBroadcast FlexInt `json:"port_13-tx_broadcast"` - Port15RxPackets FlexInt `json:"port_15-rx_packets"` - Port15RxBytes FlexInt `json:"port_15-rx_bytes"` - Port15TxPackets FlexInt `json:"port_15-tx_packets"` - Port15TxBytes FlexInt `json:"port_15-tx_bytes"` - Port15RxBroadcast FlexInt `json:"port_15-rx_broadcast"` - Port15TxMulticast FlexInt `json:"port_15-tx_multicast"` - Port15TxBroadcast FlexInt `json:"port_15-tx_broadcast"` - Port16RxPackets FlexInt `json:"port_16-rx_packets"` - Port16RxBytes FlexInt `json:"port_16-rx_bytes"` - Port16TxPackets FlexInt `json:"port_16-tx_packets"` - Port16TxBytes FlexInt `json:"port_16-tx_bytes"` - Port16TxMulticast FlexInt `json:"port_16-tx_multicast"` - Port16TxBroadcast FlexInt `json:"port_16-tx_broadcast"` - Port17RxPackets FlexInt `json:"port_17-rx_packets"` - Port17RxBytes FlexInt `json:"port_17-rx_bytes"` - Port17TxPackets FlexInt `json:"port_17-tx_packets"` - Port17TxBytes FlexInt `json:"port_17-tx_bytes"` - Port17TxMulticast FlexInt `json:"port_17-tx_multicast"` - Port17TxBroadcast FlexInt `json:"port_17-tx_broadcast"` - Port18RxPackets FlexInt `json:"port_18-rx_packets"` - Port18RxBytes FlexInt `json:"port_18-rx_bytes"` - Port18TxPackets FlexInt `json:"port_18-tx_packets"` - Port18TxBytes FlexInt `json:"port_18-tx_bytes"` - Port18RxMulticast FlexInt `json:"port_18-rx_multicast"` - Port18TxMulticast FlexInt `json:"port_18-tx_multicast"` - Port18TxBroadcast FlexInt `json:"port_18-tx_broadcast"` - Port19RxPackets FlexInt `json:"port_19-rx_packets"` - Port19RxBytes FlexInt `json:"port_19-rx_bytes"` - Port19TxPackets FlexInt `json:"port_19-tx_packets"` - Port19TxBytes FlexInt `json:"port_19-tx_bytes"` - Port19TxMulticast FlexInt `json:"port_19-tx_multicast"` - Port19TxBroadcast FlexInt `json:"port_19-tx_broadcast"` - Port21RxPackets FlexInt `json:"port_21-rx_packets"` - Port21RxBytes FlexInt `json:"port_21-rx_bytes"` - Port21TxPackets FlexInt `json:"port_21-tx_packets"` - Port21TxBytes FlexInt `json:"port_21-tx_bytes"` - Port21RxBroadcast FlexInt `json:"port_21-rx_broadcast"` - Port21TxMulticast FlexInt `json:"port_21-tx_multicast"` - Port21TxBroadcast FlexInt `json:"port_21-tx_broadcast"` - Port22RxPackets FlexInt `json:"port_22-rx_packets"` - Port22RxBytes FlexInt `json:"port_22-rx_bytes"` - Port22TxPackets FlexInt `json:"port_22-tx_packets"` - Port22TxBytes FlexInt `json:"port_22-tx_bytes"` - Port22RxMulticast FlexInt `json:"port_22-rx_multicast"` - Port22TxMulticast FlexInt `json:"port_22-tx_multicast"` - Port22TxBroadcast FlexInt `json:"port_22-tx_broadcast"` - Port23RxPackets FlexInt `json:"port_23-rx_packets"` - Port23RxBytes FlexInt `json:"port_23-rx_bytes"` - Port23RxDropped FlexInt `json:"port_23-rx_dropped"` - Port23TxPackets FlexInt `json:"port_23-tx_packets"` - Port23TxBytes FlexInt `json:"port_23-tx_bytes"` - Port23RxMulticast FlexInt `json:"port_23-rx_multicast"` - Port23RxBroadcast FlexInt `json:"port_23-rx_broadcast"` - Port23TxMulticast FlexInt `json:"port_23-tx_multicast"` - Port23TxBroadcast FlexInt `json:"port_23-tx_broadcast"` - Port24RxPackets FlexInt `json:"port_24-rx_packets"` - Port24RxBytes FlexInt `json:"port_24-rx_bytes"` - Port24TxPackets FlexInt `json:"port_24-tx_packets"` - Port24TxBytes FlexInt `json:"port_24-tx_bytes"` - Port24RxMulticast FlexInt `json:"port_24-rx_multicast"` - Port24TxMulticast FlexInt `json:"port_24-tx_multicast"` - Port24TxBroadcast FlexInt `json:"port_24-tx_broadcast"` - Port1RxMulticast FlexInt `json:"port_1-rx_multicast"` - Port3RxDropped FlexInt `json:"port_3-rx_dropped"` - Port3RxMulticast FlexInt `json:"port_3-rx_multicast"` - Port6RxDropped FlexInt `json:"port_6-rx_dropped"` - Port7RxDropped FlexInt `json:"port_7-rx_dropped"` - Port7RxMulticast FlexInt `json:"port_7-rx_multicast"` - Port9RxDropped FlexInt `json:"port_9-rx_dropped"` - Port9RxMulticast FlexInt `json:"port_9-rx_multicast"` - Port9RxBroadcast FlexInt `json:"port_9-rx_broadcast"` - Port10RxBroadcast FlexInt `json:"port_10-rx_broadcast"` - Port12RxDropped FlexInt `json:"port_12-rx_dropped"` - Port12RxMulticast FlexInt `json:"port_12-rx_multicast"` - Port13RxDropped FlexInt `json:"port_13-rx_dropped"` - Port17RxDropped FlexInt `json:"port_17-rx_dropped"` - Port17RxMulticast FlexInt `json:"port_17-rx_multicast"` - Port17RxBroadcast FlexInt `json:"port_17-rx_broadcast"` - Port19RxDropped FlexInt `json:"port_19-rx_dropped"` - Port19RxMulticast FlexInt `json:"port_19-rx_multicast"` - Port19RxBroadcast FlexInt `json:"port_19-rx_broadcast"` - Port21RxDropped FlexInt `json:"port_21-rx_dropped"` - Port21RxMulticast FlexInt `json:"port_21-rx_multicast"` - Port7RxBroadcast FlexInt `json:"port_7-rx_broadcast"` - Port18RxBroadcast FlexInt `json:"port_18-rx_broadcast"` - Port16RxMulticast FlexInt `json:"port_16-rx_multicast"` - Port15RxDropped FlexInt `json:"port_15-rx_dropped"` - Port15RxMulticast FlexInt `json:"port_15-rx_multicast"` - Port16RxBroadcast FlexInt `json:"port_16-rx_broadcast"` - Port11RxBroadcast FlexInt `json:"port_11-rx_broadcast"` - Port12RxBroadcast FlexInt `json:"port_12-rx_broadcast"` - Port6RxBroadcast FlexInt `json:"port_6-rx_broadcast"` - Port24RxBroadcast FlexInt `json:"port_24-rx_broadcast"` - Port22RxBroadcast FlexInt `json:"port_22-rx_broadcast"` - Port10TxDropped FlexInt `json:"port_10-tx_dropped"` - Port16TxDropped FlexInt `json:"port_16-tx_dropped"` - Port1RxBroadcast FlexInt `json:"port_1-rx_broadcast"` - Port4RxPackets FlexInt `json:"port_4-rx_packets"` - Port4RxBytes FlexInt `json:"port_4-rx_bytes"` - Port4RxDropped FlexInt `json:"port_4-rx_dropped"` - Port4TxPackets FlexInt `json:"port_4-tx_packets"` - Port4TxBytes FlexInt `json:"port_4-tx_bytes"` - Port4TxDropped FlexInt `json:"port_4-tx_dropped"` - Port4RxMulticast FlexInt `json:"port_4-rx_multicast"` - Port4RxBroadcast FlexInt `json:"port_4-rx_broadcast"` - Port4TxMulticast FlexInt `json:"port_4-tx_multicast"` - Port4TxBroadcast FlexInt `json:"port_4-tx_broadcast"` - } `json:"stat"` - TxBytes FlexInt `json:"tx_bytes"` - RxBytes FlexInt `json:"rx_bytes"` - Bytes FlexInt `json:"bytes"` - NumSta FlexInt `json:"num_sta"` - UserNumSta FlexInt `json:"user-num_sta"` - GuestNumSta FlexInt `json:"guest-num_sta"` + UplinkDepth FlexInt `json:"uplink_depth"` + Stat *USWStat `json:"stat"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + NumSta FlexInt `json:"num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` +} + +// USWStat holds the "stat" data for a switch. +// This is split out because of a JSON data format change from 5.10 to 5.11. +type USWStat struct { + *sw +} + +type sw struct { + SiteID string `json:"site_id"` + O string `json:"o"` + Oid string `json:"oid"` + Sw string `json:"sw"` + Time FlexInt `json:"time"` + Datetime time.Time `json:"datetime"` + RxPackets FlexInt `json:"rx_packets"` + RxBytes FlexInt `json:"rx_bytes"` + RxErrors FlexInt `json:"rx_errors"` + RxDropped FlexInt `json:"rx_dropped"` + RxCrypts FlexInt `json:"rx_crypts"` + RxFrags FlexInt `json:"rx_frags"` + TxPackets FlexInt `json:"tx_packets"` + TxBytes FlexInt `json:"tx_bytes"` + TxErrors FlexInt `json:"tx_errors"` + TxDropped FlexInt `json:"tx_dropped"` + TxRetries FlexInt `json:"tx_retries"` + RxMulticast FlexInt `json:"rx_multicast"` + RxBroadcast FlexInt `json:"rx_broadcast"` + TxMulticast FlexInt `json:"tx_multicast"` + TxBroadcast FlexInt `json:"tx_broadcast"` + Bytes FlexInt `json:"bytes"` + Duration FlexInt `json:"duration"` + Port1RxPackets FlexInt `json:"port_1-rx_packets"` + Port1RxBytes FlexInt `json:"port_1-rx_bytes"` + Port1TxPackets FlexInt `json:"port_1-tx_packets"` + Port1TxBytes FlexInt `json:"port_1-tx_bytes"` + Port1TxMulticast FlexInt `json:"port_1-tx_multicast"` + Port1TxBroadcast FlexInt `json:"port_1-tx_broadcast"` + Port3RxPackets FlexInt `json:"port_3-rx_packets"` + Port3RxBytes FlexInt `json:"port_3-rx_bytes"` + Port3TxPackets FlexInt `json:"port_3-tx_packets"` + Port3TxBytes FlexInt `json:"port_3-tx_bytes"` + Port3RxBroadcast FlexInt `json:"port_3-rx_broadcast"` + Port3TxMulticast FlexInt `json:"port_3-tx_multicast"` + Port3TxBroadcast FlexInt `json:"port_3-tx_broadcast"` + Port6RxPackets FlexInt `json:"port_6-rx_packets"` + Port6RxBytes FlexInt `json:"port_6-rx_bytes"` + Port6TxPackets FlexInt `json:"port_6-tx_packets"` + Port6TxBytes FlexInt `json:"port_6-tx_bytes"` + Port6RxMulticast FlexInt `json:"port_6-rx_multicast"` + Port6TxMulticast FlexInt `json:"port_6-tx_multicast"` + Port6TxBroadcast FlexInt `json:"port_6-tx_broadcast"` + Port7RxPackets FlexInt `json:"port_7-rx_packets"` + Port7RxBytes FlexInt `json:"port_7-rx_bytes"` + Port7TxPackets FlexInt `json:"port_7-tx_packets"` + Port7TxBytes FlexInt `json:"port_7-tx_bytes"` + Port7TxMulticast FlexInt `json:"port_7-tx_multicast"` + Port7TxBroadcast FlexInt `json:"port_7-tx_broadcast"` + Port9RxPackets FlexInt `json:"port_9-rx_packets"` + Port9RxBytes FlexInt `json:"port_9-rx_bytes"` + Port9TxPackets FlexInt `json:"port_9-tx_packets"` + Port9TxBytes FlexInt `json:"port_9-tx_bytes"` + Port9TxMulticast FlexInt `json:"port_9-tx_multicast"` + Port9TxBroadcast FlexInt `json:"port_9-tx_broadcast"` + Port10RxPackets FlexInt `json:"port_10-rx_packets"` + Port10RxBytes FlexInt `json:"port_10-rx_bytes"` + Port10TxPackets FlexInt `json:"port_10-tx_packets"` + Port10TxBytes FlexInt `json:"port_10-tx_bytes"` + Port10RxMulticast FlexInt `json:"port_10-rx_multicast"` + Port10TxMulticast FlexInt `json:"port_10-tx_multicast"` + Port10TxBroadcast FlexInt `json:"port_10-tx_broadcast"` + Port11RxPackets FlexInt `json:"port_11-rx_packets"` + Port11RxBytes FlexInt `json:"port_11-rx_bytes"` + Port11TxPackets FlexInt `json:"port_11-tx_packets"` + Port11TxBytes FlexInt `json:"port_11-tx_bytes"` + Port11TxMulticast FlexInt `json:"port_11-tx_multicast"` + Port11TxBroadcast FlexInt `json:"port_11-tx_broadcast"` + Port12RxPackets FlexInt `json:"port_12-rx_packets"` + Port12RxBytes FlexInt `json:"port_12-rx_bytes"` + Port12TxPackets FlexInt `json:"port_12-tx_packets"` + Port12TxBytes FlexInt `json:"port_12-tx_bytes"` + Port12TxMulticast FlexInt `json:"port_12-tx_multicast"` + Port12TxBroadcast FlexInt `json:"port_12-tx_broadcast"` + Port13RxPackets FlexInt `json:"port_13-rx_packets"` + Port13RxBytes FlexInt `json:"port_13-rx_bytes"` + Port13TxPackets FlexInt `json:"port_13-tx_packets"` + Port13TxBytes FlexInt `json:"port_13-tx_bytes"` + Port13RxMulticast FlexInt `json:"port_13-rx_multicast"` + Port13RxBroadcast FlexInt `json:"port_13-rx_broadcast"` + Port13TxMulticast FlexInt `json:"port_13-tx_multicast"` + Port13TxBroadcast FlexInt `json:"port_13-tx_broadcast"` + Port15RxPackets FlexInt `json:"port_15-rx_packets"` + Port15RxBytes FlexInt `json:"port_15-rx_bytes"` + Port15TxPackets FlexInt `json:"port_15-tx_packets"` + Port15TxBytes FlexInt `json:"port_15-tx_bytes"` + Port15RxBroadcast FlexInt `json:"port_15-rx_broadcast"` + Port15TxMulticast FlexInt `json:"port_15-tx_multicast"` + Port15TxBroadcast FlexInt `json:"port_15-tx_broadcast"` + Port16RxPackets FlexInt `json:"port_16-rx_packets"` + Port16RxBytes FlexInt `json:"port_16-rx_bytes"` + Port16TxPackets FlexInt `json:"port_16-tx_packets"` + Port16TxBytes FlexInt `json:"port_16-tx_bytes"` + Port16TxMulticast FlexInt `json:"port_16-tx_multicast"` + Port16TxBroadcast FlexInt `json:"port_16-tx_broadcast"` + Port17RxPackets FlexInt `json:"port_17-rx_packets"` + Port17RxBytes FlexInt `json:"port_17-rx_bytes"` + Port17TxPackets FlexInt `json:"port_17-tx_packets"` + Port17TxBytes FlexInt `json:"port_17-tx_bytes"` + Port17TxMulticast FlexInt `json:"port_17-tx_multicast"` + Port17TxBroadcast FlexInt `json:"port_17-tx_broadcast"` + Port18RxPackets FlexInt `json:"port_18-rx_packets"` + Port18RxBytes FlexInt `json:"port_18-rx_bytes"` + Port18TxPackets FlexInt `json:"port_18-tx_packets"` + Port18TxBytes FlexInt `json:"port_18-tx_bytes"` + Port18RxMulticast FlexInt `json:"port_18-rx_multicast"` + Port18TxMulticast FlexInt `json:"port_18-tx_multicast"` + Port18TxBroadcast FlexInt `json:"port_18-tx_broadcast"` + Port19RxPackets FlexInt `json:"port_19-rx_packets"` + Port19RxBytes FlexInt `json:"port_19-rx_bytes"` + Port19TxPackets FlexInt `json:"port_19-tx_packets"` + Port19TxBytes FlexInt `json:"port_19-tx_bytes"` + Port19TxMulticast FlexInt `json:"port_19-tx_multicast"` + Port19TxBroadcast FlexInt `json:"port_19-tx_broadcast"` + Port21RxPackets FlexInt `json:"port_21-rx_packets"` + Port21RxBytes FlexInt `json:"port_21-rx_bytes"` + Port21TxPackets FlexInt `json:"port_21-tx_packets"` + Port21TxBytes FlexInt `json:"port_21-tx_bytes"` + Port21RxBroadcast FlexInt `json:"port_21-rx_broadcast"` + Port21TxMulticast FlexInt `json:"port_21-tx_multicast"` + Port21TxBroadcast FlexInt `json:"port_21-tx_broadcast"` + Port22RxPackets FlexInt `json:"port_22-rx_packets"` + Port22RxBytes FlexInt `json:"port_22-rx_bytes"` + Port22TxPackets FlexInt `json:"port_22-tx_packets"` + Port22TxBytes FlexInt `json:"port_22-tx_bytes"` + Port22RxMulticast FlexInt `json:"port_22-rx_multicast"` + Port22TxMulticast FlexInt `json:"port_22-tx_multicast"` + Port22TxBroadcast FlexInt `json:"port_22-tx_broadcast"` + Port23RxPackets FlexInt `json:"port_23-rx_packets"` + Port23RxBytes FlexInt `json:"port_23-rx_bytes"` + Port23RxDropped FlexInt `json:"port_23-rx_dropped"` + Port23TxPackets FlexInt `json:"port_23-tx_packets"` + Port23TxBytes FlexInt `json:"port_23-tx_bytes"` + Port23RxMulticast FlexInt `json:"port_23-rx_multicast"` + Port23RxBroadcast FlexInt `json:"port_23-rx_broadcast"` + Port23TxMulticast FlexInt `json:"port_23-tx_multicast"` + Port23TxBroadcast FlexInt `json:"port_23-tx_broadcast"` + Port24RxPackets FlexInt `json:"port_24-rx_packets"` + Port24RxBytes FlexInt `json:"port_24-rx_bytes"` + Port24TxPackets FlexInt `json:"port_24-tx_packets"` + Port24TxBytes FlexInt `json:"port_24-tx_bytes"` + Port24RxMulticast FlexInt `json:"port_24-rx_multicast"` + Port24TxMulticast FlexInt `json:"port_24-tx_multicast"` + Port24TxBroadcast FlexInt `json:"port_24-tx_broadcast"` + Port1RxMulticast FlexInt `json:"port_1-rx_multicast"` + Port3RxDropped FlexInt `json:"port_3-rx_dropped"` + Port3RxMulticast FlexInt `json:"port_3-rx_multicast"` + Port6RxDropped FlexInt `json:"port_6-rx_dropped"` + Port7RxDropped FlexInt `json:"port_7-rx_dropped"` + Port7RxMulticast FlexInt `json:"port_7-rx_multicast"` + Port9RxDropped FlexInt `json:"port_9-rx_dropped"` + Port9RxMulticast FlexInt `json:"port_9-rx_multicast"` + Port9RxBroadcast FlexInt `json:"port_9-rx_broadcast"` + Port10RxBroadcast FlexInt `json:"port_10-rx_broadcast"` + Port12RxDropped FlexInt `json:"port_12-rx_dropped"` + Port12RxMulticast FlexInt `json:"port_12-rx_multicast"` + Port13RxDropped FlexInt `json:"port_13-rx_dropped"` + Port17RxDropped FlexInt `json:"port_17-rx_dropped"` + Port17RxMulticast FlexInt `json:"port_17-rx_multicast"` + Port17RxBroadcast FlexInt `json:"port_17-rx_broadcast"` + Port19RxDropped FlexInt `json:"port_19-rx_dropped"` + Port19RxMulticast FlexInt `json:"port_19-rx_multicast"` + Port19RxBroadcast FlexInt `json:"port_19-rx_broadcast"` + Port21RxDropped FlexInt `json:"port_21-rx_dropped"` + Port21RxMulticast FlexInt `json:"port_21-rx_multicast"` + Port7RxBroadcast FlexInt `json:"port_7-rx_broadcast"` + Port18RxBroadcast FlexInt `json:"port_18-rx_broadcast"` + Port16RxMulticast FlexInt `json:"port_16-rx_multicast"` + Port15RxDropped FlexInt `json:"port_15-rx_dropped"` + Port15RxMulticast FlexInt `json:"port_15-rx_multicast"` + Port16RxBroadcast FlexInt `json:"port_16-rx_broadcast"` + Port11RxBroadcast FlexInt `json:"port_11-rx_broadcast"` + Port12RxBroadcast FlexInt `json:"port_12-rx_broadcast"` + Port6RxBroadcast FlexInt `json:"port_6-rx_broadcast"` + Port24RxBroadcast FlexInt `json:"port_24-rx_broadcast"` + Port22RxBroadcast FlexInt `json:"port_22-rx_broadcast"` + Port10TxDropped FlexInt `json:"port_10-tx_dropped"` + Port16TxDropped FlexInt `json:"port_16-tx_dropped"` + Port1RxBroadcast FlexInt `json:"port_1-rx_broadcast"` + Port4RxPackets FlexInt `json:"port_4-rx_packets"` + Port4RxBytes FlexInt `json:"port_4-rx_bytes"` + Port4RxDropped FlexInt `json:"port_4-rx_dropped"` + Port4TxPackets FlexInt `json:"port_4-tx_packets"` + Port4TxBytes FlexInt `json:"port_4-tx_bytes"` + Port4TxDropped FlexInt `json:"port_4-tx_dropped"` + Port4RxMulticast FlexInt `json:"port_4-rx_multicast"` + Port4RxBroadcast FlexInt `json:"port_4-rx_broadcast"` + Port4TxMulticast FlexInt `json:"port_4-tx_multicast"` + Port4TxBroadcast FlexInt `json:"port_4-tx_broadcast"` +} + +// UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Switch Stat data. +func (v *USWStat) UnmarshalJSON(data []byte) error { + var n struct { + sw `json:"sw"` + } + v.sw = &n.sw + err := json.Unmarshal(data, v.sw) // controller version 5.10. + if err != nil { + return json.Unmarshal(data, &n) // controller version 5.11. + } + return nil } diff --git a/core/unifi/usw_type_test.go b/core/unifi/usw_type_test.go new file mode 100644 index 00000000..a8220271 --- /dev/null +++ b/core/unifi/usw_type_test.go @@ -0,0 +1,93 @@ +package unifi + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestUSWUnmarshalJSON(t *testing.T) { + testcontroller511 := `{ + "sw": { + "site_id": "mySite", + "o": "sw", + "oid": "00:00:00:00:00:00", + "sw": "00:00:00:00:00:00", + "time": 1577742600000, + "datetime": "2019-12-30T09:40:00Z", + "rx_packets": 321, + "rx_bytes": 321, + "rx_errors": 123, + "rx_dropped": 123, + "rx_crypts": 123, + "rx_frags": 123, + "tx_packets": 123, + "tx_bytes": 123, + "tx_errors": 0, + "tx_dropped": 0, + "tx_retries": 0, + "rx_multicast": 123, + "rx_broadcast": 123, + "tx_multicast": 123, + "tx_broadcast": 123, + "bytes": 123, + "duration": 123, + "port_1-tx_packets": 123, + "port_1-tx_bytes": 123, + "port_1-tx_multicast": 123, + "port_1-tx_broadcast": 123, + "port_1-rx_packets": 123, + "port_1-rx_bytes": 123, + "port_1-rx_dropped": 123, + "port_1-rx_multicast": 123, + "port_1-rx_broadcast": 123, + "port_1-rx_errors": 123}}` + + testcontroller510 := `{ + "site_id": "mySite", + "o": "sw", + "oid": "00:00:00:00:00:00", + "sw": "00:00:00:00:00:00", + "time": 1577742600000, + "datetime": "2019-12-30T09:40:00Z", + "rx_packets": 321, + "rx_bytes": 321, + "rx_errors": 123, + "rx_dropped": 123, + "rx_crypts": 123, + "rx_frags": 123, + "tx_packets": 123, + "tx_bytes": 123, + "tx_errors": 0, + "tx_dropped": 0, + "tx_retries": 0, + "rx_multicast": 123, + "rx_broadcast": 123, + "tx_multicast": 123, + "tx_broadcast": 123, + "bytes": 123, + "duration": 123, + "port_1-tx_packets": 123, + "port_1-tx_bytes": 123, + "port_1-tx_multicast": 123, + "port_1-tx_broadcast": 123, + "port_1-rx_packets": 123, + "port_1-rx_bytes": 123, + "port_1-rx_dropped": 123, + "port_1-rx_multicast": 123, + "port_1-rx_broadcast": 123, + "port_1-rx_errors": 123}` + + t.Parallel() + a := assert.New(t) + + u := &USWStat{} + err := u.UnmarshalJSON([]byte(testcontroller510)) + a.Nil(err, "must be no error unmarshaling test strings") + a.Equal(float64(123), u.RxMulticast.Val, "data was not properly unmarshaled") + + u = &USWStat{} // reset + err = u.UnmarshalJSON([]byte(testcontroller511)) + a.Nil(err, "must be no error unmarshaling test strings") + a.Equal(float64(123), u.RxMulticast.Val, "data was not properly unmarshaled") +} From 2499930efed0a5589761d41b8eb1818cc5e5758c Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 7 Jul 2019 20:27:05 -0700 Subject: [PATCH 077/194] Fix unmarshal error. --- core/unifi/usg_influx.go | 1 + core/unifi/usg_type.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index 896b6bf9..da1242d1 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -158,6 +158,7 @@ func (u USG) Points() ([]*influx.Point, error) { "device_mac": u.Mac, "site_name": u.SiteName, "name": p.Name, + "up": p.Up.Txt, "dhcpd_dns_enabled": p.DhcpdDNSEnabled.Txt, "dhcpd_enabled": p.DhcpdEnabled.Txt, "dhcpd_ntp_enabled": p.DhcpdNtpEnabled.Txt, diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index 166eb5d3..7a8fa361 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -185,7 +185,7 @@ type USG struct { Mac string `json:"mac"` IsGuest FlexBool `json:"is_guest"` IP string `json:"ip"` - Up string `json:"up"` + Up FlexBool `json:"up"` NumSta FlexInt `json:"num_sta"` RxBytes FlexInt `json:"rx_bytes"` RxPackets FlexInt `json:"rx_packets"` From 8002117b0a9ea29e6c197ad6e45b8cda9b89886d Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 7 Jul 2019 20:28:24 -0700 Subject: [PATCH 078/194] Remove GetServer --- core/unifi/unifi.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 76b53cf8..4614d7eb 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -70,12 +70,6 @@ func (u *Unifi) getServer() error { return u.GetData(StatusPath, &response) } -// GetServer returns the controller's version and UUID. -// This method is deprecated and will go away in a future release, use u.Server* -func (u *Unifi) GetServer() (*server, error) { - return u.server, nil -} - // GetClients returns a response full of clients' data from the Unifi Controller. func (u *Unifi) GetClients(sites []Site) (Clients, error) { data := make([]Client, 0) From d80ad93a17d4ee48186e554f19d072f612f8bc44 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Mon, 8 Jul 2019 00:46:30 -0700 Subject: [PATCH 079/194] stop overriding false txt --- core/unifi/types.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/unifi/types.go b/core/unifi/types.go index 46dc652f..9d668543 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -102,9 +102,7 @@ type FlexBool struct { // UnmarshalJSON method converts armed/disarmed, yes/no, active/inactive or 0/1 to true/false. // Really it converts ready, ok, up, t, armed, yes, active, enabled, 1, true to true. Anything else is false. func (f *FlexBool) UnmarshalJSON(b []byte) error { - if f.Txt = strings.Trim(string(b), `"`); f.Txt == "" { - f.Txt = "false" - } + f.Txt = strings.Trim(string(b), `"`) f.Val = f.Txt == "1" || strings.EqualFold(f.Txt, "true") || strings.EqualFold(f.Txt, "yes") || strings.EqualFold(f.Txt, "t") || strings.EqualFold(f.Txt, "armed") || strings.EqualFold(f.Txt, "active") || strings.EqualFold(f.Txt, "enabled") || strings.EqualFold(f.Txt, "ready") || strings.EqualFold(f.Txt, "up") || From caf60bb7050d428d0c5acc1fecc39ba82ebf758f Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Wed, 10 Jul 2019 22:31:57 -0700 Subject: [PATCH 080/194] Add names to all devices. --- core/unifi/clients_influx.go | 19 ++++++++----------- core/unifi/devices.go | 32 +++++++++++++++++++++++--------- core/unifi/site_influx.go | 7 +++++++ core/unifi/uap_influx.go | 11 +++++++++-- core/unifi/unifi.go | 29 +++++++++++++---------------- core/unifi/usg_influx.go | 8 +++++++- core/unifi/usw_influx.go | 11 +++++++++-- 7 files changed, 76 insertions(+), 41 deletions(-) diff --git a/core/unifi/clients_influx.go b/core/unifi/clients_influx.go index 7a4ee00d..194f3fa4 100644 --- a/core/unifi/clients_influx.go +++ b/core/unifi/clients_influx.go @@ -9,16 +9,13 @@ import ( // Points generates Unifi Client datapoints for InfluxDB. // These points can be passed directly to influx. func (c Client) Points() ([]*influx.Point, error) { - // Fix name and hostname fields. Sometimes one or the other is blank. - switch { - case c.Hostname == "" && c.Name == "": - c.Hostname = c.Mac - c.Name = c.Mac - case c.Hostname == "" && c.Name != "": - c.Hostname = c.Name - case c.Name == "" && c.Hostname != "": - c.Name = c.Hostname - } + 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) { tags := map[string]string{ "id": c.ID, "mac": c.Mac, @@ -109,7 +106,7 @@ func (c Client) Points() ([]*influx.Point, error) { "dpi_tx_bytes": c.DpiStats.TxBytes.Val, "dpi_tx_packets": c.DpiStats.TxPackets.Val, } - pt, err := influx.NewPoint("clients", tags, fields, time.Now()) + pt, err := influx.NewPoint("clients", tags, fields, now) if err != nil { return nil, err } diff --git a/core/unifi/devices.go b/core/unifi/devices.go index 20a6a580..072cf31e 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -17,19 +17,22 @@ 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": - if uap := (UAP{}); u.unmarshalDevice(assetType, r, &uap) == nil { - uap.SiteName = siteName - devices.UAPs = append(devices.UAPs, uap) + 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. - if usg := (USG{}); u.unmarshalDevice(assetType, r, &usg) == nil { - usg.SiteName = siteName - devices.USGs = append(devices.USGs, usg) + 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": - if usw := (USW{}); u.unmarshalDevice(assetType, r, &usw) == nil { - usw.SiteName = siteName - devices.USWs = append(devices.USWs, usw) + dev := USW{SiteName: siteName} + if u.unmarshalDevice(assetType, r, &dev) == nil { + dev.Name = pick(dev.Name, dev.Mac) + devices.USWs = append(devices.USWs, dev) } default: u.ErrorLog("unknown asset type - %v - skipping", assetType) @@ -50,3 +53,14 @@ func (u *Unifi) unmarshalDevice(dev string, data json.RawMessage, v interface{}) } return err } + +// pick returns the first non empty string in a list. +// used in a few places around this library. +func pick(strings ...string) string { + for _, s := range strings { + if s != "" { + return s + } + } + return "" +} diff --git a/core/unifi/site_influx.go b/core/unifi/site_influx.go index 20a7543d..82dc53fd 100644 --- a/core/unifi/site_influx.go +++ b/core/unifi/site_influx.go @@ -10,6 +10,13 @@ import ( // Points generates Unifi Sites' datapoints for InfluxDB. // These points can be passed directly to influx. 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) { points := []*influx.Point{} for _, s := range u.Health { tags := map[string]string{ diff --git a/core/unifi/uap_influx.go b/core/unifi/uap_influx.go index d5b3bf63..6ed3ec1a 100644 --- a/core/unifi/uap_influx.go +++ b/core/unifi/uap_influx.go @@ -9,6 +9,13 @@ import ( // Points generates Wireless-Access-Point datapoints for InfluxDB. // These points can be passed directly to influx. 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) { tags := map[string]string{ "id": u.ID, "mac": u.Mac, @@ -161,7 +168,7 @@ func (u UAP) Points() ([]*influx.Point, error) { "stat_wifi0-tx_retries": u.Stat.Wifi0TxRetries.Val, "stat_wifi1-tx_retries": u.Stat.Wifi1TxRetries.Val, } - pt, err := influx.NewPoint("uap", tags, fields, time.Now()) + pt, err := influx.NewPoint("uap", tags, fields, now) if err != nil { return nil, err } @@ -265,7 +272,7 @@ func (u UAP) Points() ([]*influx.Point, error) { fields["user-num_sta"] = p.UserNumSta.Val } - pt, err := influx.NewPoint("uap_vaps", tags, fields, time.Now()) + pt, err := influx.NewPoint("uap_vaps", tags, fields, now) if err != nil { return points, err } diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 4614d7eb..25e08683 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -82,8 +82,12 @@ func (u *Unifi) GetClients(sites []Site) (Clients, error) { if err := u.GetData(clientPath, &response); err != nil { return nil, err } - for i := range response.Data { + for i, d := range response.Data { + // Add the special "Site Name" to each client. This becomes a Grafana filter somewhere. response.Data[i].SiteName = site.Desc + " (" + site.Name + ")" + // Fix name and hostname fields. Sometimes one or the other is blank. + response.Data[i].Hostname = pick(d.Hostname, d.Name, d.Mac) + response.Data[i].Name = pick(d.Name, d.Hostname) } data = append(data, response.Data...) } @@ -101,17 +105,7 @@ func (u *Unifi) GetDevices(sites []Site) (*Devices, error) { if err := u.GetData(devicePath, &response); err != nil { return nil, err } - loopDevices := u.parseDevices(response.Data, site.Desc+" ("+site.Name+")") - // Add SiteName to each device asset. - for i := range loopDevices.UAPs { - loopDevices.UAPs[i].SiteName = site.Desc + " (" + site.Name + ")" - } - for i := range loopDevices.USGs { - loopDevices.USGs[i].SiteName = site.Desc + " (" + site.Name + ")" - } - for i := range loopDevices.USWs { - loopDevices.USWs[i].SiteName = site.Desc + " (" + site.Name + ")" - } + loopDevices := u.parseDevices(response.Data, site.SiteName) devices.UAPs = append(devices.UAPs, loopDevices.UAPs...) devices.USGs = append(devices.USGs, loopDevices.USGs...) devices.USWs = append(devices.USWs, loopDevices.USWs...) @@ -127,10 +121,13 @@ func (u *Unifi) GetSites() (Sites, error) { if err := u.GetData(SiteList, &response); err != nil { return nil, err } - sites := make([]string, 0) - for i := range response.Data { - response.Data[i].SiteName = response.Data[i].Desc + " (" + response.Data[i].Name + ")" - sites = append(sites, response.Data[i].Name) + sites := []string{} // used for debug log only + for i, d := range response.Data { + // If the human name is missing (description), set it to the cryptic name. + response.Data[i].Desc = pick(d.Desc, d.Name) + // Add the custom site name to each site. used as a Grafana filter somewhere. + response.Data[i].SiteName = d.Desc + " (" + d.Name + ")" + sites = append(sites, d.Name) // used for debug log only } u.DebugLog("Found %d site(s): %s", len(sites), strings.Join(sites, ",")) return response.Data, nil diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index da1242d1..a989804e 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -10,7 +10,13 @@ import ( // Points generates Unifi Gateway datapoints for InfluxDB. // These points can be passed directly to influx. func (u USG) Points() ([]*influx.Point, error) { - now := time.Now() + 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) { 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 a48a8e3e..1dee7de9 100644 --- a/core/unifi/usw_influx.go +++ b/core/unifi/usw_influx.go @@ -9,6 +9,13 @@ import ( // Points generates Unifi Switch datapoints for InfluxDB. // These points can be passed directly to influx. 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) { tags := map[string]string{ "id": u.ID, "mac": u.Mac, @@ -93,7 +100,7 @@ func (u USW) Points() ([]*influx.Point, error) { "uplink_depth": u.UplinkDepth.Txt, // Add the port stats too. } - pt, err := influx.NewPoint("usw", tags, fields, time.Now()) + pt, err := influx.NewPoint("usw", tags, fields, now) if err != nil { return nil, err } @@ -153,7 +160,7 @@ func (u USW) Points() ([]*influx.Point, error) { "poe_voltage": p.PoeVoltage.Val, "full_duplex": p.FullDuplex.Val, } - pt, err = influx.NewPoint("usw_ports", tags, fields, time.Now()) + pt, err = influx.NewPoint("usw_ports", tags, fields, now) if err != nil { return points, err } From 407e3daff8dc66bd3d3445ee8fba677a5dcd18f4 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Wed, 10 Jul 2019 23:43:03 -0700 Subject: [PATCH 081/194] Add IDS data to the library. --- core/unifi/examples/ids.json | 66 +++++++++++++++ core/unifi/ids.go | 151 +++++++++++++++++++++++++++++++++++ core/unifi/types.go | 2 + 3 files changed, 219 insertions(+) create mode 100644 core/unifi/examples/ids.json create mode 100644 core/unifi/ids.go diff --git a/core/unifi/examples/ids.json b/core/unifi/examples/ids.json new file mode 100644 index 00000000..5dbb0fe2 --- /dev/null +++ b/core/unifi/examples/ids.json @@ -0,0 +1,66 @@ +{ + "_id": "5d2416c78f0385ccf1c6df44", + "archived": false, + "timestamp": 1562646211, + "flow_id": 1591464006222389, + "in_iface": "eth1", + "event_type": "alert", + "src_ip": "196.196.244.84", + "src_mac": "f0:9f:c2:c4:bb:f1", + "src_port": 51413, + "dest_ip": "192.168.3.2", + "dst_mac": "40:a8:f0:68:c3:58", + "dest_port": 36881, + "proto": "UDP", + "app_proto": "failed", + "host": "f0:22:22:22:22:22", + "usgip": "11.22.33.44", + "unique_alertid": "1341902566-2019-07-08T21:23:31.229941-0700", + "srcipCountry": "SE", + "dstipCountry": false, + "usgipCountry": "US", + "srcipGeo": { + "continent_code": "EU", + "country_code": "SE", + "country_code3": "SWE", + "country_name": "Sweden", + "region": "26", + "city": "Stockholm", + "postal_code": "168 65", + "latitude": 59.349998474121094, + "longitude": 17.91670036315918, + "dma_code": 0, + "area_code": 0 + }, + "dstipGeo": false, + "usgipGeo": { + "continent_code": "NA", + "country_code": "US", + "country_code3": "USA", + "country_name": "United States", + "region": "CA", + "city": "Other", + "postal_code": "99999", + "latitude": 99.139400482177734, + "longitude": -99.39669799804688, + "dma_code": 862, + "area_code": 999 + }, + "srcipASN": "AS42607 Internet Carrier Limited", + "dstipASN": "", + "usgipASN": "AS7922 Comcast Cable Communications, LLC", + "catname": "spamhaus", + "inner_alert_action": "allowed", + "inner_alert_gid": 1, + "inner_alert_signature_id": 2400022, + "inner_alert_rev": 2673, + "inner_alert_signature": "ET DROP Spamhaus DROP Listed Traffic Inbound group 23", + "inner_alert_category": "Misc Attack", + "inner_alert_severity": 2, + "key": "EVT_IPS_IpsAlert", + "subsystem": "www", + "site_id": "574e86994566ffb914a2683c", + "time": 1562646211000, + "datetime": "2019-07-09T04:23:31Z", + "msg": "IPS Alert 2: Misc Attack. Signature ET DROP Spamhaus DROP Listed Traffic Inbound group 23. From: 196.196.244.84:51413, to: 192.168.3.2:36881, protocol: UDP" +}, diff --git a/core/unifi/ids.go b/core/unifi/ids.go new file mode 100644 index 00000000..1a57d8f5 --- /dev/null +++ b/core/unifi/ids.go @@ -0,0 +1,151 @@ +package unifi + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" + + influx "github.com/influxdata/influxdb1-client/v2" + "github.com/pkg/errors" +) + +// IDS holds an Intrusion Prevention System Event. +type IDS struct { + ID string `json:"_id"` + Archived FlexBool `json:"archived"` + Timestamp int64 `json:"timestamp"` + FlowID int64 `json:"flow_id"` + InIface string `json:"in_iface"` + EventType string `json:"event_type"` + SrcIP string `json:"src_ip"` + SrcMac string `json:"src_mac"` + SrcPort int `json:"src_port,omitempty"` + DestIP string `json:"dest_ip"` + DstMac string `json:"dst_mac"` + DestPort int `json:"dest_port,omitempty"` + Proto string `json:"proto"` + AppProto string `json:"app_proto,omitempty"` + Host string `json:"host"` + Usgip string `json:"usgip"` + UniqueAlertid string `json:"unique_alertid"` + SrcipCountry string `json:"srcipCountry"` + DstipCountry FlexBool `json:"dstipCountry"` + UsgipCountry string `json:"usgipCountry"` + SrcipGeo struct { + ContinentCode string `json:"continent_code"` + CountryCode string `json:"country_code"` + CountryCode3 string `json:"country_code3"` + CountryName string `json:"country_name"` + Region string `json:"region"` + City string `json:"city"` + PostalCode string `json:"postal_code"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + DmaCode int64 `json:"dma_code"` + AreaCode int64 `json:"area_code"` + } `json:"srcipGeo"` + DstipGeo bool `json:"dstipGeo"` + UsgipGeo struct { + ContinentCode string `json:"continent_code"` + CountryCode string `json:"country_code"` + CountryCode3 string `json:"country_code3"` + CountryName string `json:"country_name"` + Region string `json:"region"` + City string `json:"city"` + PostalCode string `json:"postal_code"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + DmaCode int64 `json:"dma_code"` + AreaCode int64 `json:"area_code"` + } `json:"usgipGeo"` + SrcipASN string `json:"srcipASN"` + DstipASN string `json:"dstipASN"` + UsgipASN string `json:"usgipASN"` + Catname string `json:"catname"` + InnerAlertAction string `json:"inner_alert_action"` + InnerAlertGid int64 `json:"inner_alert_gid"` + InnerAlertSignatureID int64 `json:"inner_alert_signature_id"` + InnerAlertRev int64 `json:"inner_alert_rev"` + InnerAlertSignature string `json:"inner_alert_signature"` + InnerAlertCategory string `json:"inner_alert_category"` + InnerAlertSeverity int64 `json:"inner_alert_severity"` + Key string `json:"key"` + Subsystem string `json:"subsystem"` + SiteID string `json:"site_id"` + SiteName string `json:"-"` + Time int64 `json:"time"` + Datetime time.Time `json:"datetime"` + Msg string `json:"msg"` + IcmpType int64 `json:"icmp_type,omitempty"` + IcmpCode int64 `json:"icmp_code,omitempty"` +} + +// 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{} + for _, site := range sites { + var response struct { + Data []IDS `json:"data"` + } + u.DebugLog("Polling Controller, retreiving Unifi IDS/IPS Data, site %s (%s) ", site.Name, site.Desc) + URIpath := fmt.Sprintf(IDSEvents, site.Name) + params := fmt.Sprintf(`{"start":"%v","end":"%v","_limit":50000}`, from.UnixNano(), to.UnixNano()) + req, err := u.UniReq(URIpath, params) + if err != nil { + return nil, err + } + resp, err := u.Do(req) + if err != nil { + return nil, err + } + defer func() { + _ = resp.Body.Close() + }() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusOK { + return nil, errors.Errorf("invalid status code from server %s", resp.Status) + } + if err := json.Unmarshal(body, &response); err != nil { + return nil, err + } + for i := range response.Data { + response.Data[i].SiteName = site.SiteName + } + data = append(data, response.Data...) + } + return data, nil +} + +// Points generates intrusion detection datapoints for InfluxDB. +// These points can be passed directly to influx. +func (i IDS) Points() ([]*influx.Point, error) { + tags := map[string]string{ + "in_iface": i.InIface, + "event_type": i.EventType, + "proto": i.Proto, + "app_proto": i.AppProto, + "usgip": i.Usgip, + "country_code": i.SrcipGeo.CountryCode, + "country_name": i.SrcipGeo.CountryName, + "region": i.SrcipGeo.Region, + "city": i.SrcipGeo.City, + "postal_code": i.SrcipGeo.PostalCode, + "srcipASN": i.SrcipASN, + "usgipASN": i.UsgipASN, + "alert_category": i.InnerAlertCategory, + "subsystem": i.Subsystem, + "catname": i.Catname, + } + fields := map[string]interface{}{} + pt, err := influx.NewPoint("uap_vaps", tags, fields, i.Datetime) + if err != nil { + return nil, err + } + return []*influx.Point{pt}, nil +} diff --git a/core/unifi/types.go b/core/unifi/types.go index 9d668543..a7c14c0a 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -26,6 +26,8 @@ const ( UserGroupPath string = "/api/s/%s/rest/usergroup" // LoginPath is Unifi Controller Login API Path LoginPath string = "/api/login" + // IDSEvents returns Intrusion Detection Systems Events + IDSEvents string = "/api/s/%s/stat/ips/event" ) // Logger is a base type to deal with changing log outputs. Create a logger From 7de0c0db3ac8ea115ab90de3d5840f5c29371480 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Thu, 11 Jul 2019 00:21:50 -0700 Subject: [PATCH 082/194] update --- core/unifi/ids.go | 22 ++++++++++++++++++---- core/unifi/types.go | 4 ++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/core/unifi/ids.go b/core/unifi/ids.go index 1a57d8f5..4e0421fc 100644 --- a/core/unifi/ids.go +++ b/core/unifi/ids.go @@ -11,6 +11,9 @@ import ( "github.com/pkg/errors" ) +// IDSList contains a list that contains all of the IDS Events on a controller. +type IDSList []IDS + // IDS holds an Intrusion Prevention System Event. type IDS struct { ID string `json:"_id"` @@ -91,8 +94,8 @@ func (u *Unifi) GetIDS(sites []Site, from, to time.Time) ([]IDS, error) { Data []IDS `json:"data"` } u.DebugLog("Polling Controller, retreiving Unifi IDS/IPS Data, site %s (%s) ", site.Name, site.Desc) - URIpath := fmt.Sprintf(IDSEvents, site.Name) - params := fmt.Sprintf(`{"start":"%v","end":"%v","_limit":50000}`, from.UnixNano(), to.UnixNano()) + URIpath := fmt.Sprintf(IPSEvents, site.Name) + params := fmt.Sprintf(`{"start":"%v000","end":"%v000","_limit":50000}`, from.Unix(), to.Unix()) req, err := u.UniReq(URIpath, params) if err != nil { return nil, err @@ -118,6 +121,7 @@ func (u *Unifi) GetIDS(sites []Site, from, to time.Time) ([]IDS, error) { response.Data[i].SiteName = site.SiteName } data = append(data, response.Data...) + u.DebugLog("Found %d IDS entries. %s", len(data), params) } return data, nil } @@ -142,8 +146,18 @@ func (i IDS) Points() ([]*influx.Point, error) { "subsystem": i.Subsystem, "catname": i.Catname, } - fields := map[string]interface{}{} - pt, err := influx.NewPoint("uap_vaps", tags, fields, i.Datetime) + fields := map[string]interface{}{ + "event_type": i.EventType, + "proto": i.Proto, + "app_proto": i.AppProto, + "usgip": i.Usgip, + "country_name": i.SrcipGeo.CountryName, + "city": i.SrcipGeo.City, + "postal_code": i.SrcipGeo.PostalCode, + "srcipASN": i.SrcipASN, + "usgipASN": i.UsgipASN, + } + pt, err := influx.NewPoint("intrusion_detect", tags, fields, i.Datetime) if err != nil { return nil, err } diff --git a/core/unifi/types.go b/core/unifi/types.go index a7c14c0a..6b2e6f55 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -26,8 +26,8 @@ const ( UserGroupPath string = "/api/s/%s/rest/usergroup" // LoginPath is Unifi Controller Login API Path LoginPath string = "/api/login" - // IDSEvents returns Intrusion Detection Systems Events - IDSEvents string = "/api/s/%s/stat/ips/event" + // IPSEvents returns Intrusion Detection Systems Events + IPSEvents string = "/api/s/%s/stat/ips/event" ) // Logger is a base type to deal with changing log outputs. Create a logger From 085ce28943a101ddb44dbaa8c57bbc0b195fef12 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Thu, 11 Jul 2019 01:09:58 -0700 Subject: [PATCH 083/194] IDS code cleanup --- core/unifi/ids.go | 77 +++++++++++++++++++++++++++------------------ core/unifi/unifi.go | 12 +++---- 2 files changed, 53 insertions(+), 36 deletions(-) diff --git a/core/unifi/ids.go b/core/unifi/ids.go index 4e0421fc..47da5aa2 100644 --- a/core/unifi/ids.go +++ b/core/unifi/ids.go @@ -90,42 +90,59 @@ type IDS struct { func (u *Unifi) GetIDS(sites []Site, from, to time.Time) ([]IDS, error) { data := []IDS{} for _, site := range sites { - var response struct { - Data []IDS `json:"data"` - } - u.DebugLog("Polling Controller, retreiving Unifi IDS/IPS Data, site %s (%s) ", site.Name, site.Desc) - URIpath := fmt.Sprintf(IPSEvents, site.Name) - params := fmt.Sprintf(`{"start":"%v000","end":"%v000","_limit":50000}`, from.Unix(), to.Unix()) - req, err := u.UniReq(URIpath, params) + u.DebugLog("Polling Controller for IDS/IPS Data, site %s (%s) ", site.Name, site.Desc) + ids, err := u.GetSiteIDS(site, from, to) if err != nil { - return nil, err + return data, err } - resp, err := u.Do(req) - if err != nil { - return nil, err - } - defer func() { - _ = resp.Body.Close() - }() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - if resp.StatusCode != http.StatusOK { - return nil, errors.Errorf("invalid status code from server %s", resp.Status) - } - if err := json.Unmarshal(body, &response); err != nil { - return nil, err - } - for i := range response.Data { - response.Data[i].SiteName = site.SiteName - } - data = append(data, response.Data...) - u.DebugLog("Found %d IDS entries. %s", len(data), params) + data = append(data, ids...) } return data, nil } +// 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) { + var response struct { + Data []IDS `json:"data"` + } + URIpath := fmt.Sprintf(IPSEvents, site.Name) + params := fmt.Sprintf(`{"start":"%v000","end":"%v000","_limit":50000}`, from.Unix(), to.Unix()) + req, err := u.UniReq(URIpath, params) + if err != nil { + return nil, err + } + resp, err := u.Do(req) + if err != nil { + return nil, err + } + defer func() { + _ = resp.Body.Close() + }() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusOK { + return nil, errors.Errorf("invalid status code from server %s", resp.Status) + } + if err := json.Unmarshal(body, &response); err != nil { + return nil, err + } + for i := range response.Data { + response.Data[i].SiteName = site.SiteName + } + return response.Data, nil +} + +// PointsAt has no usefulness. It is provided to satisfy external interfaces. +// 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) { + 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) { diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 25e08683..8d985f21 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -1,4 +1,4 @@ -// Package unifi provides a set of types to unload (unmarshal) Unifi Ubiquiti +// Package unifi provides a set of types to unload (unmarshal) Ubiquiti UniFi // controller data. Also provided are methods to easily get data for devices - // things like access points and switches, and for clients - the things // connected to those access points and switches. As a bonus, each device and @@ -70,14 +70,14 @@ func (u *Unifi) getServer() error { return u.GetData(StatusPath, &response) } -// GetClients returns a response full of clients' data from the Unifi Controller. +// GetClients returns a response full of clients' data from the UniFi Controller. func (u *Unifi) GetClients(sites []Site) (Clients, error) { data := make([]Client, 0) for _, site := range sites { var response struct { Data []Client `json:"data"` } - u.DebugLog("Polling Controller, retreiving Unifi Clients, site %s (%s) ", site.Name, site.Desc) + u.DebugLog("Polling Controller, retreiving UniFi Clients, site %s (%s) ", site.Name, site.Desc) clientPath := fmt.Sprintf(ClientPath, site.Name) if err := u.GetData(clientPath, &response); err != nil { return nil, err @@ -94,7 +94,7 @@ func (u *Unifi) GetClients(sites []Site) (Clients, error) { return data, nil } -// GetDevices returns a response full of devices' data from the Unifi Controller. +// GetDevices returns a response full of devices' data from the UniFi Controller. func (u *Unifi) GetDevices(sites []Site) (*Devices, error) { devices := new(Devices) for _, site := range sites { @@ -113,7 +113,7 @@ func (u *Unifi) GetDevices(sites []Site) (*Devices, error) { return devices, nil } -// GetSites returns a list of configured sites on the Unifi controller. +// GetSites returns a list of configured sites on the UniFi controller. func (u *Unifi) GetSites() (Sites, error) { var response struct { Data []Site `json:"data"` @@ -144,7 +144,7 @@ func (u *Unifi) GetData(methodPath string, v interface{}) error { } // UniReq is a small helper function that adds an Accept header. -// Use this if you're unmarshalling Unifi data into custom types. +// Use this if you're unmarshalling UniFi data into custom types. // And if you're doing that... sumbut a pull request with your new struct. :) // This is a helper method that is exposed for convenience. func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err error) { From af597d9b589bb32e09cfd55fac95742bd0d24e91 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sat, 13 Jul 2019 03:16:26 -0700 Subject: [PATCH 084/194] Use pointers.... --- core/unifi/clients_influx.go | 4 ++-- core/unifi/clients_type.go | 2 +- core/unifi/devices.go | 12 ++++++------ core/unifi/ids.go | 14 +++++++------- core/unifi/site_influx.go | 4 ++-- core/unifi/site_type.go | 2 +- core/unifi/types.go | 6 +++--- core/unifi/uap_influx.go | 8 ++++++-- core/unifi/uap_influx_test.go | 18 ++++++++++++++++++ core/unifi/uap_type.go | 2 +- core/unifi/unifi.go | 10 +++++----- core/unifi/usg_influx.go | 4 ++-- core/unifi/usw_influx.go | 4 ++-- 13 files changed, 56 insertions(+), 34 deletions(-) create mode 100644 core/unifi/uap_influx_test.go 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, From d2d18e747da6faf9f055fff095ca62d176cb199f Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Mon, 15 Jul 2019 00:06:16 -0700 Subject: [PATCH 085/194] fix again --- core/unifi/usg_influx.go | 4 ++++ core/unifi/usw_influx.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index 5f766539..c1f90319 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -17,6 +17,10 @@ func (u *USG) Points() ([]*influx.Point, error) { // 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) { + if u.Stat.gw == nil { + // Disabled devices lack stats. + u.Stat.gw = &gw{} + } 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 8a745d26..f02e195b 100644 --- a/core/unifi/usw_influx.go +++ b/core/unifi/usw_influx.go @@ -16,6 +16,10 @@ func (u *USW) Points() ([]*influx.Point, error) { // 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) { + if u.Stat.sw == nil { + // Disabled devices lack stats. + u.Stat.sw = &sw{} + } tags := map[string]string{ "id": u.ID, "mac": u.Mac, From fe8dff549c2993389445c3aaee90ece0e4b2ab88 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Mon, 15 Jul 2019 00:16:09 -0700 Subject: [PATCH 086/194] Fix more! --- core/unifi/usg_type.go | 20 ++++++++++---------- core/unifi/usw_type.go | 16 ++++++++-------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index 7a8fa361..c797391d 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -233,16 +233,16 @@ type USG struct { MaxSpeed FlexInt `json:"max_speed"` Type string `json:"type"` } `json:"uplink"` - Stat *USGStat `json:"stat"` - TxBytes FlexInt `json:"tx_bytes"` - RxBytes FlexInt `json:"rx_bytes"` - Bytes FlexInt `json:"bytes"` - NumSta FlexInt `json:"num_sta"` - UserNumSta FlexInt `json:"user-num_sta"` - GuestNumSta FlexInt `json:"guest-num_sta"` - NumDesktop FlexInt `json:"num_desktop"` - NumMobile FlexInt `json:"num_mobile"` - NumHandheld FlexInt `json:"num_handheld"` + Stat USGStat `json:"stat"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + NumSta FlexInt `json:"num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` + NumDesktop FlexInt `json:"num_desktop"` + NumMobile FlexInt `json:"num_mobile"` + NumHandheld FlexInt `json:"num_handheld"` } // USGStat holds the "stat" data for a gateway. diff --git a/core/unifi/usw_type.go b/core/unifi/usw_type.go index 4ad891cf..ee3ebfb4 100644 --- a/core/unifi/usw_type.go +++ b/core/unifi/usw_type.go @@ -170,14 +170,14 @@ type USW struct { LastUplink struct { UplinkMac string `json:"uplink_mac"` } `json:"last_uplink"` - UplinkDepth FlexInt `json:"uplink_depth"` - Stat *USWStat `json:"stat"` - TxBytes FlexInt `json:"tx_bytes"` - RxBytes FlexInt `json:"rx_bytes"` - Bytes FlexInt `json:"bytes"` - NumSta FlexInt `json:"num_sta"` - UserNumSta FlexInt `json:"user-num_sta"` - GuestNumSta FlexInt `json:"guest-num_sta"` + UplinkDepth FlexInt `json:"uplink_depth"` + Stat USWStat `json:"stat"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + NumSta FlexInt `json:"num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` } // USWStat holds the "stat" data for a switch. From bd0ee8c6b976e725638be08041e121d83c9db13a Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 17 Jul 2019 02:35:47 -0700 Subject: [PATCH 087/194] Update README.md --- core/unifi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/README.md b/core/unifi/README.md index c0cf00e9..c575bd30 100644 --- a/core/unifi/README.md +++ b/core/unifi/README.md @@ -17,7 +17,7 @@ Here's a working example: package main import "log" -import "github.com/golift/unifi" +import "code.golift.io/unifi" func main() { username := "admin" From b49a0a37eaa518f131e81911f623da1ff3a8fe69 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 20 Jul 2019 02:21:56 -0700 Subject: [PATCH 088/194] Update README.md --- core/unifi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/README.md b/core/unifi/README.md index c575bd30..edc355f6 100644 --- a/core/unifi/README.md +++ b/core/unifi/README.md @@ -17,7 +17,7 @@ Here's a working example: package main import "log" -import "code.golift.io/unifi" +import "golift.io/unifi" func main() { username := "admin" From 64ea35112df6b27baabfe3c9814002b40eff7d0d Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Fri, 16 Aug 2019 01:42:25 -0700 Subject: [PATCH 089/194] Add UDM support. --- core/unifi/devices.go | 6 + core/unifi/types.go | 1 + core/unifi/uap_influx.go | 12 +- core/unifi/uap_type.go | 53 ++---- core/unifi/udm_influx.go | 333 +++++++++++++++++++++++++++++++++++++ core/unifi/udm_type.go | 185 +++++++++++++++++++++ core/unifi/usg_influx.go | 45 ++--- core/unifi/usg_type.go | 266 +++++++++++++++--------------- core/unifi/usw_influx.go | 92 +++++------ core/unifi/usw_type.go | 345 ++++++++++++++++++--------------------- 10 files changed, 890 insertions(+), 448 deletions(-) create mode 100644 core/unifi/udm_influx.go create mode 100644 core/unifi/udm_type.go diff --git a/core/unifi/devices.go b/core/unifi/devices.go index 4f9829e6..bc7bb593 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -34,6 +34,12 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { dev.Name = pick(dev.Name, dev.Mac) devices.USWs = append(devices.USWs, dev) } + case "udm": + dev := &UDM{SiteName: siteName} + if u.unmarshalDevice(assetType, r, dev) == nil { + dev.Name = pick(dev.Name, dev.Mac) + devices.UDMs = append(devices.UDMs, dev) + } default: u.ErrorLog("unknown asset type - %v - skipping", assetType) } diff --git a/core/unifi/types.go b/core/unifi/types.go index 64dccd9a..ea323538 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -45,6 +45,7 @@ type Devices struct { UAPs []*UAP USGs []*USG USWs []*USW + UDMs []*UDM } // 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 44d721a0..9ca988c0 100644 --- a/core/unifi/uap_influx.go +++ b/core/unifi/uap_influx.go @@ -64,15 +64,15 @@ func (u *UAP) PointsAt(now time.Time) ([]*influx.Point, error) { "user-num_sta": u.UserNumSta, "guest-num_sta": u.GuestNumSta, "version": u.Version, - "loadavg_1": u.SysStats.Loadavg1, - "loadavg_5": u.SysStats.Loadavg5, - "loadavg_15": u.SysStats.Loadavg15, + "loadavg_1": u.SysStats.Loadavg1.Val, + "loadavg_5": u.SysStats.Loadavg5.Val, + "loadavg_15": u.SysStats.Loadavg15.Val, "mem_buffer": u.SysStats.MemBuffer.Val, "mem_total": u.SysStats.MemTotal.Val, "mem_used": u.SysStats.MemUsed.Val, - "cpu": u.SystemStats.CPU, - "mem": u.SystemStats.Mem, - "system_uptime": u.SystemStats.Uptime, + "cpu": u.SystemStats.CPU.Val, + "mem": u.SystemStats.Mem.Val, + "system_uptime": u.SystemStats.Uptime.Val, "stat_guest-wifi0-rx_packets": u.Stat.GuestWifi0RxPackets.Val, "stat_guest-wifi1-rx_packets": u.Stat.GuestWifi1RxPackets.Val, "stat_user-wifi1-rx_packets": u.Stat.UserWifi1RxPackets.Val, diff --git a/core/unifi/uap_type.go b/core/unifi/uap_type.go index 538f09f4..5fa31fa6 100644 --- a/core/unifi/uap_type.go +++ b/core/unifi/uap_type.go @@ -44,26 +44,8 @@ type UAP struct { Model string `json:"model"` Name string `json:"name"` OutdoorModeOverride string `json:"outdoor_mode_override"` - PortTable []struct { - PortIdx FlexInt `json:"port_idx"` - OpMode string `json:"op_mode"` - PortconfID string `json:"portconf_id"` - AttrNoEdit FlexBool `json:"attr_no_edit,omitempty"` - Media string `json:"media"` - Name string `json:"name"` - PoeCaps FlexInt `json:"poe_caps"` - PortPoe FlexBool `json:"port_poe"` - TxBytesR FlexInt `json:"tx_bytes-r"` - RxBytesR FlexInt `json:"rx_bytes-r"` - BytesR FlexInt `json:"bytes-r"` - PortDelta struct { - TimeDelta FlexInt `json:"time_delta"` - } `json:"port_delta"` - Enable FlexBool `json:"enable"` - Masked FlexBool `json:"masked"` - AggregatedBy FlexBool `json:"aggregated_by"` - } `json:"port_table"` - RadioTable []struct { + PortTable []Port `json:"port_table"` + RadioTable []struct { Radio string `json:"radio"` Name string `json:"name"` Channel FlexInt `json:"channel"` @@ -112,27 +94,16 @@ type UAP struct { Locating FlexBool `json:"locating"` ConnectRequestIP string `json:"connect_request_ip"` ConnectRequestPort string `json:"connect_request_port"` - SysStats struct { - Loadavg1 float64 `json:"loadavg_1,string"` - Loadavg15 float64 `json:"loadavg_15,string"` - Loadavg5 float64 `json:"loadavg_5,string"` - MemBuffer FlexInt `json:"mem_buffer"` - MemTotal FlexInt `json:"mem_total"` - MemUsed FlexInt `json:"mem_used"` - } `json:"sys_stats"` - SystemStats struct { - CPU float64 `json:"cpu,string"` - Mem float64 `json:"mem,string"` - Uptime float64 `json:"uptime,string"` - } `json:"system-stats"` - SSHSessionTable []interface{} `json:"ssh_session_table"` - Scanning FlexBool `json:"scanning"` - SpectrumScanning FlexBool `json:"spectrum_scanning"` - GuestToken string `json:"guest_token"` - Meshv3PeerMac string `json:"meshv3_peer_mac"` - Satisfaction FlexInt `json:"satisfaction"` - Isolated FlexBool `json:"isolated"` - RadioTableStats []struct { + SysStats SysStats `json:"sys_stats"` + SystemStats SystemStats `json:"system-stats"` + SSHSessionTable []interface{} `json:"ssh_session_table"` + Scanning FlexBool `json:"scanning"` + SpectrumScanning FlexBool `json:"spectrum_scanning"` + GuestToken string `json:"guest_token"` + Meshv3PeerMac string `json:"meshv3_peer_mac"` + Satisfaction FlexInt `json:"satisfaction"` + Isolated FlexBool `json:"isolated"` + RadioTableStats []struct { Name string `json:"name"` Channel FlexInt `json:"channel"` Radio string `json:"radio"` diff --git a/core/unifi/udm_influx.go b/core/unifi/udm_influx.go new file mode 100644 index 00000000..34ffc1ac --- /dev/null +++ b/core/unifi/udm_influx.go @@ -0,0 +1,333 @@ +package unifi + +import ( + "time" + + influx "github.com/influxdata/influxdb1-client/v2" +) + +// Points generates Unifi Gateway datapoints for InfluxDB. +// These points can be passed directly to influx. +func (u *UDM) 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 *UDM) PointsAt(now time.Time) ([]*influx.Point, error) { + if u.Stat.gw == nil { + // Disabled devices lack stats. + u.Stat.gw = &gw{} + } + if u.Stat.sw == nil { + // Disabled devices lack stats. + u.Stat.sw = &sw{} + } + tags := map[string]string{ + "id": u.ID, + "mac": u.Mac, + "device_oid": u.Stat.gw.Oid, + "site_id": u.SiteID, + "site_name": u.SiteName, + "adopted": u.Adopted.Txt, + "name": u.Name, + "cfgversion": u.Cfgversion, + "config_network_ip": u.ConfigNetwork.IP, + "config_network_type": u.ConfigNetwork.Type, + "connect_request_ip": u.ConnectRequestIP, + "connect_request_port": u.ConnectRequestPort, + "device_id": u.DeviceID, + "guest_token": u.GuestToken, + "inform_ip": u.InformIP, + "known_cfgversion": u.KnownCfgversion, + "model": u.Model, + "serial": u.Serial, + "type": u.Type, + "usg_caps": u.UsgCaps.Txt, + "speedtest-status-saved": u.SpeedtestStatusSaved.Txt, + "wan1_up": u.Wan1.Up.Txt, + "wan2_up": u.Wan2.Up.Txt, + } + fields := map[string]interface{}{ + "ip": u.IP, + "bytes": u.Bytes.Val, + "last_seen": u.LastSeen.Val, + "license_state": u.LicenseState, + "fw_caps": u.FwCaps.Val, + "guest-num_sta": u.GuestNumSta.Val, + "rx_bytes": u.RxBytes.Val, + "tx_bytes": u.TxBytes.Val, + "uptime": u.Uptime.Val, + "state": u.State.Val, + "user-num_sta": u.UserNumSta.Val, + "version": u.Version, + "num_desktop": u.NumDesktop.Val, + "num_handheld": u.NumHandheld.Val, + "num_mobile": u.NumMobile.Val, + "speedtest-status_latency": u.SpeedtestStatus.Latency.Val, + "speedtest-status_rundate": u.SpeedtestStatus.Rundate.Val, + "speedtest-status_runtime": u.SpeedtestStatus.Runtime.Val, + "speedtest-status_download": u.SpeedtestStatus.StatusDownload.Val, + "speedtest-status_ping": u.SpeedtestStatus.StatusPing.Val, + "speedtest-status_summary": u.SpeedtestStatus.StatusSummary.Val, + "speedtest-status_upload": u.SpeedtestStatus.StatusUpload.Val, + "speedtest-status_xput_download": u.SpeedtestStatus.XputDownload.Val, + "speedtest-status_xput_upload": u.SpeedtestStatus.XputUpload.Val, + "config_network_wan_type": u.ConfigNetwork.Type, + "wan1_bytes-r": u.Wan1.BytesR.Val, + "wan1_enable": u.Wan1.Enable.Val, + "wan1_full_duplex": u.Wan1.FullDuplex.Val, + "wan1_gateway": u.Wan1.Gateway, + "wan1_ifname": u.Wan1.Ifname, + "wan1_ip": u.Wan1.IP, + "wan1_mac": u.Wan1.Mac, + "wan1_max_speed": u.Wan1.MaxSpeed.Val, + "wan1_name": u.Wan1.Name, + "wan1_netmask": u.Wan1.Netmask, + "wan1_rx_bytes": u.Wan1.RxBytes.Val, + "wan1_rx_bytes-r": u.Wan1.RxBytesR.Val, + "wan1_rx_dropped": u.Wan1.RxDropped.Val, + "wan1_rx_errors": u.Wan1.RxErrors.Val, + "wan1_rx_multicast": u.Wan1.RxMulticast.Val, + "wan1_rx_packets": u.Wan1.RxPackets.Val, + "wan1_type": u.Wan1.Type, + "wan1_speed": u.Wan1.Speed.Val, + "wan1_up": u.Wan1.Up.Val, + "wan1_tx_bytes": u.Wan1.TxBytes.Val, + "wan1_tx_bytes-r": u.Wan1.TxBytesR.Val, + "wan1_tx_dropped": u.Wan1.TxDropped.Val, + "wan1_tx_errors": u.Wan1.TxErrors.Val, + "wan1_tx_packets": u.Wan1.TxPackets.Val, + "wan2_bytes-r": u.Wan2.BytesR.Val, + "wan2_enable": u.Wan2.Enable.Val, + "wan2_full_duplex": u.Wan2.FullDuplex.Val, + "wan2_gateway": u.Wan2.Gateway, + "wan2_ifname": u.Wan2.Ifname, + "wan2_ip": u.Wan2.IP, + "wan2_mac": u.Wan2.Mac, + "wan2_max_speed": u.Wan2.MaxSpeed.Val, + "wan2_name": u.Wan2.Name, + "wan2_netmask": u.Wan2.Netmask, + "wan2_rx_bytes": u.Wan2.RxBytes.Val, + "wan2_rx_bytes-r": u.Wan2.RxBytesR.Val, + "wan2_rx_dropped": u.Wan2.RxDropped.Val, + "wan2_rx_errors": u.Wan2.RxErrors.Val, + "wan2_rx_multicast": u.Wan2.RxMulticast.Val, + "wan2_rx_packets": u.Wan2.RxPackets.Val, + "wan2_type": u.Wan2.Type, + "wan2_speed": u.Wan2.Speed.Val, + "wan2_up": u.Wan2.Up.Val, + "wan2_tx_bytes": u.Wan2.TxBytes.Val, + "wan2_tx_bytes-r": u.Wan2.TxBytesR.Val, + "wan2_tx_dropped": u.Wan2.TxDropped.Val, + "wan2_tx_errors": u.Wan2.TxErrors.Val, + "wan2_tx_packets": u.Wan2.TxPackets.Val, + "loadavg_1": u.SysStats.Loadavg1.Val, + "loadavg_5": u.SysStats.Loadavg5.Val, + "loadavg_15": u.SysStats.Loadavg15.Val, + "mem_used": u.SysStats.MemUsed.Val, + "mem_buffer": u.SysStats.MemBuffer.Val, + "mem_total": u.SysStats.MemTotal.Val, + "cpu": u.SystemStats.CPU.Val, + "mem": u.SystemStats.Mem.Val, + "system_uptime": u.SystemStats.Uptime.Val, + "gw": u.Stat.Gw, + "lan-rx_bytes": u.Stat.LanRxBytes.Val, + "lan-rx_packets": u.Stat.LanRxPackets.Val, + "lan-tx_bytes": u.Stat.LanTxBytes.Val, + "lan-tx_packets": u.Stat.LanTxPackets.Val, + "wan-rx_bytes": u.Stat.WanRxBytes.Val, + "wan-rx_dropped": u.Stat.WanRxDropped.Val, + "wan-rx_packets": u.Stat.WanRxPackets.Val, + "wan-tx_bytes": u.Stat.WanTxBytes.Val, + "wan-tx_packets": u.Stat.WanTxPackets.Val, + "uplink_name": u.Uplink.Name, + "uplink_latency": u.Uplink.Latency.Val, + "uplink_speed": u.Uplink.Speed.Val, + "uplink_num_ports": u.Uplink.NumPort.Val, + "uplink_max_speed": u.Uplink.MaxSpeed.Val, + } + pt, err := influx.NewPoint("usg", tags, fields, now) + if err != nil { + return nil, err + } + points := []*influx.Point{pt} + tags = map[string]string{ + "id": u.ID, + "mac": u.Mac, + "device_oid": u.Stat.sw.Oid, + "site_id": u.SiteID, + "site_name": u.SiteName, + "name": u.Name, + "adopted": u.Adopted.Txt, + "cfgversion": u.Cfgversion, + "config_network_ip": u.ConfigNetwork.IP, + "config_network_type": u.ConfigNetwork.Type, + "device_id": u.DeviceID, + "inform_ip": u.InformIP, + "known_cfgversion": u.KnownCfgversion, + "locating": u.Locating.Txt, + "model": u.Model, + "serial": u.Serial, + "type": u.Type, + "dot1x_portctrl_enabled": u.Dot1XPortctrlEnabled.Txt, + "flowctrl_enabled": u.FlowctrlEnabled.Txt, + "has_fan": u.HasFan.Txt, + "has_temperature": u.HasTemperature.Txt, + "jumboframe_enabled": u.JumboframeEnabled.Txt, + "stp_priority": u.StpPriority, + "stp_version": u.StpVersion, + } + fields = map[string]interface{}{ + "fw_caps": u.FwCaps.Val, + "guest-num_sta": u.GuestNumSta.Val, + "ip": u.IP, + "bytes": u.Bytes.Val, + "fan_level": float64(0), + "general_temperature": float64(0), + "last_seen": u.LastSeen.Val, + "license_state": u.LicenseState, + "overheating": u.Overheating.Val, + "rx_bytes": u.RxBytes.Val, + "tx_bytes": u.TxBytes.Val, + "uptime": u.Uptime.Val, + "state": u.State.Val, + "user-num_sta": u.UserNumSta.Val, + "version": u.Version, + "loadavg_1": u.SysStats.Loadavg1.Val, + "loadavg_5": u.SysStats.Loadavg5.Val, + "loadavg_15": u.SysStats.Loadavg15.Val, + "mem_buffer": u.SysStats.MemBuffer.Val, + "mem_used": u.SysStats.MemUsed.Val, + "mem_total": u.SysStats.MemTotal.Val, + "cpu": u.SystemStats.CPU.Val, + "mem": u.SystemStats.Mem.Val, + "system_uptime": u.SystemStats.Uptime.Val, + "stat_bytes": u.Stat.Bytes.Val, + "stat_rx_bytes": u.Stat.RxBytes.Val, + "stat_rx_crypts": u.Stat.RxCrypts.Val, + "stat_rx_dropped": u.Stat.RxDropped.Val, + "stat_rx_errors": u.Stat.RxErrors.Val, + "stat_rx_frags": u.Stat.RxFrags.Val, + "stat_rx_packets": u.Stat.TxPackets.Val, + "stat_tx_bytes": u.Stat.TxBytes.Val, + "stat_tx_dropped": u.Stat.TxDropped.Val, + "stat_tx_errors": u.Stat.TxErrors.Val, + "stat_tx_packets": u.Stat.TxPackets.Val, + "stat_tx_retries": u.Stat.TxRetries.Val, + "uplink_depth": "0", + } + pt, err = influx.NewPoint("usw", tags, fields, now) + if err != nil { + return nil, err + } + points = append(points, pt) + + for _, p := range u.NetworkTable { + tags := map[string]string{ + "device_name": u.Name, + "device_id": u.ID, + "device_mac": u.Mac, + "site_name": u.SiteName, + "up": p.Up.Txt, + "dhcpd_dns_enabled": p.DhcpdDNSEnabled.Txt, + "dhcpd_enabled": p.DhcpdEnabled.Txt, + "dhcpd_time_offset_enabled": p.DhcpdTimeOffsetEnabled.Txt, + "dhcp_relay_enabledy": p.DhcpRelayEnabled.Txt, + "dhcpd_gateway_enabled": p.DhcpdGatewayEnabled.Txt, + "enabled": p.Enabled.Txt, + "vlan_enabled": p.VlanEnabled.Txt, + "attr_no_delete": p.AttrNoDelete.Txt, + "is_guest": p.IsGuest.Txt, + "is_nat": p.IsNat.Txt, + "networkgroup": p.Networkgroup, + "site_id": p.SiteID, + } + fields := map[string]interface{}{ + "domain_name": p.DomainName, + "dhcpd_start": p.DhcpdStart, + "dhcpd_stop": p.DhcpdStop, + "ip": p.IP, + "ip_subnet": p.IPSubnet, + "mac": p.Mac, + "name": p.Name, + "num_sta": p.NumSta.Val, + "purpose": p.Purpose, + "rx_bytes": p.RxBytes.Val, + "rx_packets": p.RxPackets.Val, + "tx_bytes": p.TxBytes.Val, + "tx_packets": p.TxPackets.Val, + "ipv6_interface_type": p.Ipv6InterfaceType, + "attr_hidden_id": p.AttrHiddenID, + } + pt, err = influx.NewPoint("usg_networks", tags, fields, now) + if err != nil { + return points, err + } + points = append(points, pt) + } + + for _, p := range u.PortTable { + tags := map[string]string{ + "site_id": u.SiteID, + "site_name": u.SiteName, + "device_name": u.Name, + "name": p.Name, + "enable": p.Enable.Txt, + "is_uplink": p.IsUplink.Txt, + "up": p.Up.Txt, + "portconf_id": p.PortconfID, + "dot1x_mode": p.Dot1XMode, + "dot1x_status": p.Dot1XStatus, + "stp_state": p.StpState, + "sfp_found": p.SfpFound.Txt, + "op_mode": p.OpMode, + "poe_mode": p.PoeMode, + "port_poe": p.PortPoe.Txt, + "port_idx": p.PortIdx.Txt, + "port_id": u.Name + " Port " + p.PortIdx.Txt, + "poe_enable": p.PoeEnable.Txt, + "flowctrl_rx": p.FlowctrlRx.Txt, + "flowctrl_tx": p.FlowctrlTx.Txt, + "autoneg": p.Autoneg.Txt, + "full_duplex": p.FullDuplex.Txt, + "jumbo": p.Jumbo.Txt, + "masked": p.Masked.Txt, + "poe_good": p.PoeGood.Txt, + "media": p.Media, + "poe_class": p.PoeClass, + "poe_caps": p.PoeCaps.Txt, + "aggregated_by": p.AggregatedBy.Txt, + } + fields := map[string]interface{}{ + "dbytes_r": p.BytesR.Val, + "rx_broadcast": p.RxBroadcast.Val, + "rx_bytes": p.RxBytes.Val, + "rx_bytes-r": p.RxBytesR.Val, + "rx_dropped": p.RxDropped.Val, + "rx_errors": p.RxErrors.Val, + "rx_multicast": p.RxMulticast.Val, + "rx_packets": p.RxPackets.Val, + "speed": p.Speed.Val, + "stp_pathcost": p.StpPathcost.Val, + "tx_broadcast": p.TxBroadcast.Val, + "tx_bytes": p.TxBytes.Val, + "tx_bytes-r": p.TxBytesR.Val, + "tx_dropped": p.TxDropped.Val, + "tx_errors": p.TxErrors.Val, + "tx_multicast": p.TxMulticast.Val, + "tx_packets": p.TxPackets.Val, + "poe_current": p.PoeCurrent.Val, + "poe_power": p.PoePower.Val, + "poe_voltage": p.PoeVoltage.Val, + "full_duplex": p.FullDuplex.Val, + } + pt, err = influx.NewPoint("usw_ports", tags, fields, now) + if err != nil { + return points, err + } + points = append(points, pt) + } + return points, nil +} diff --git a/core/unifi/udm_type.go b/core/unifi/udm_type.go new file mode 100644 index 00000000..8d32027b --- /dev/null +++ b/core/unifi/udm_type.go @@ -0,0 +1,185 @@ +package unifi + +// UDM represents all the data from the Ubiquiti Controller for a Unifi Dream Machine. +// The UDM shares several structs/type-data with USW and USG. +type UDM struct { + SiteID string `json:"site_id"` + SiteName string `json:"-"` + Mac string `json:"mac"` + Adopted FlexBool `json:"adopted"` + Serial string `json:"serial"` + IP string `json:"ip"` + Uptime FlexInt `json:"uptime"` + Model string `json:"model"` + Version string `json:"version"` + Name string `json:"hostname"` + Default FlexBool `json:"default"` + Locating FlexBool `json:"locating"` + Type string `json:"type"` + Unsupported FlexBool `json:"unsupported"` + UnsupportedReason FlexInt `json:"unsupported_reason"` + DiscoveredVia string `json:"discovered_via"` + AdoptIP string `json:"adopt_ip"` + AdoptURL string `json:"adopt_url"` + State FlexInt `json:"state"` + AdoptStatus FlexInt `json:"adopt_status"` + UpgradeState FlexInt `json:"upgrade_state"` + LastSeen FlexInt `json:"last_seen"` + AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` + Cfgversion string `json:"cfgversion"` + ConfigNetwork struct { + Type string `json:"type"` + IP string `json:"ip"` + } `json:"config_network"` + VwireTable []interface{} `json:"vwire_table"` + Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"` + JumboframeEnabled FlexBool `json:"jumboframe_enabled"` + FlowctrlEnabled FlexBool `json:"flowctrl_enabled"` + StpVersion string `json:"stp_version"` + StpPriority string `json:"stp_priority"` + PowerSourceCtrlEnabled FlexBool `json:"power_source_ctrl_enabled"` + LicenseState string `json:"license_state"` + ID string `json:"_id"` + DeviceID string `json:"device_id"` + AdoptState FlexInt `json:"adopt_state"` + AdoptTries FlexInt `json:"adopt_tries"` + AdoptManual FlexBool `json:"adopt_manual"` + InformURL string `json:"inform_url"` + InformIP string `json:"inform_ip"` + RequiredVersion string `json:"required_version"` + BoardRev FlexInt `json:"board_rev"` + EthernetTable []struct { + Mac string `json:"mac"` + NumPort FlexInt `json:"num_port"` + Name string `json:"name"` + } `json:"ethernet_table"` + PortTable []Port `json:"port_table"` + EthernetOverrides []struct { + Ifname string `json:"ifname"` + Networkgroup string `json:"networkgroup"` + } `json:"ethernet_overrides"` + UsgCaps FlexInt `json:"usg_caps"` + HasSpeaker FlexBool `json:"has_speaker"` + HasEth1 FlexBool `json:"has_eth1"` + FwCaps FlexInt `json:"fw_caps"` + HwCaps FlexInt `json:"hw_caps"` + SwitchCaps struct { + MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` + MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` + } `json:"switch_caps"` + HasFan FlexBool `json:"has_fan"` + HasTemperature FlexBool `json:"has_temperature"` + RulesetInterfaces struct { + Br0 string `json:"br0"` + Eth8 string `json:"eth8"` + Eth9 string `json:"eth9"` + } `json:"ruleset_interfaces"` + KnownCfgversion string `json:"known_cfgversion"` + SysStats SysStats `json:"sys_stats"` + SystemStats SystemStats `json:"system-stats"` + GuestToken string `json:"guest_token"` + Overheating FlexBool `json:"overheating"` + SpeedtestStatus SpeedtestStatus `json:"speedtest-status"` + SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"` + Wan1 Wan `json:"wan1"` + Wan2 Wan `json:"wan2"` + Uplink Uplink `json:"uplink"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + DownlinkTable []interface{} `json:"downlink_table"` + NetworkTable []struct { + ID string `json:"_id"` + AttrNoDelete FlexBool `json:"attr_no_delete"` + AttrHiddenID string `json:"attr_hidden_id"` + Name string `json:"name"` + SiteID string `json:"site_id"` + VlanEnabled FlexBool `json:"vlan_enabled"` + Purpose string `json:"purpose"` + IPSubnet string `json:"ip_subnet"` + Ipv6InterfaceType string `json:"ipv6_interface_type"` + DomainName string `json:"domain_name"` + IsNat FlexBool `json:"is_nat"` + DhcpdEnabled FlexBool `json:"dhcpd_enabled"` + DhcpdStart string `json:"dhcpd_start"` + DhcpdStop string `json:"dhcpd_stop"` + Dhcpdv6Enabled FlexBool `json:"dhcpdv6_enabled"` + Ipv6RaEnabled FlexBool `json:"ipv6_ra_enabled"` + LteLanEnabled FlexBool `json:"lte_lan_enabled"` + Networkgroup string `json:"networkgroup"` + DhcpdLeasetime FlexInt `json:"dhcpd_leasetime"` + DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"` + DhcpdGatewayEnabled FlexBool `json:"dhcpd_gateway_enabled"` + DhcpdTimeOffsetEnabled FlexBool `json:"dhcpd_time_offset_enabled"` + Ipv6PdStart string `json:"ipv6_pd_start"` + Ipv6PdStop string `json:"ipv6_pd_stop"` + DhcpdDNS1 string `json:"dhcpd_dns_1"` + DhcpdDNS2 string `json:"dhcpd_dns_2"` + DhcpdDNS3 string `json:"dhcpd_dns_3"` + DhcpdDNS4 string `json:"dhcpd_dns_4"` + Enabled FlexBool `json:"enabled"` + DhcpRelayEnabled FlexBool `json:"dhcp_relay_enabled"` + Mac string `json:"mac"` + IsGuest FlexBool `json:"is_guest"` + IP string `json:"ip"` + Up FlexBool `json:"up"` + DpistatsTable struct { + LastUpdated FlexInt `json:"last_updated"` + ByCat []struct { + Cat FlexInt `json:"cat"` + Apps []FlexInt `json:"apps"` + RxBytes FlexInt `json:"rx_bytes"` + TxBytes FlexInt `json:"tx_bytes"` + RxPackets FlexInt `json:"rx_packets"` + TxPackets FlexInt `json:"tx_packets"` + } `json:"by_cat"` + ByApp []struct { + App FlexInt `json:"app"` + Cat FlexInt `json:"cat"` + Clients []struct { + Mac string `json:"mac"` + RxBytes FlexInt `json:"rx_bytes"` + TxBytes FlexInt `json:"tx_bytes"` + RxPackets FlexInt `json:"rx_packets"` + TxPackets FlexInt `json:"tx_packets"` + } `json:"clients"` + KnownClients FlexInt `json:"known_clients"` + RxBytes FlexInt `json:"rx_bytes"` + TxBytes FlexInt `json:"tx_bytes"` + RxPackets FlexInt `json:"rx_packets"` + TxPackets FlexInt `json:"tx_packets"` + } `json:"by_app"` + } `json:"dpistats_table,omitempty"` + NumSta FlexInt `json:"num_sta"` + RxBytes FlexInt `json:"rx_bytes"` + RxPackets FlexInt `json:"rx_packets"` + TxBytes FlexInt `json:"tx_bytes"` + TxPackets FlexInt `json:"tx_packets"` + } `json:"network_table"` + PortOverrides []struct { + PortIdx FlexInt `json:"port_idx"` + PortconfID string `json:"portconf_id"` + } `json:"port_overrides"` + Stat UDMStat `json:"stat"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + NumSta FlexInt `json:"num_sta"` + WlanNumSta FlexInt `json:"wlan-num_sta"` + LanNumSta FlexInt `json:"lan-num_sta"` + UserWlanNumSta FlexInt `json:"user-wlan-num_sta"` + UserLanNumSta FlexInt `json:"user-lan-num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` + GuestWlanNumSta FlexInt `json:"guest-wlan-num_sta"` + GuestLanNumSta FlexInt `json:"guest-lan-num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` + NumDesktop FlexInt `json:"num_desktop"` + NumMobile FlexInt `json:"num_mobile"` + NumHandheld FlexInt `json:"num_handheld"` +} + +// UDMStat holds the "stat" data for a dream machine. +// A dream machine is a USG + USW + Controller +type UDMStat struct { + *gw + *sw +} diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go index c1f90319..11df9260 100644 --- a/core/unifi/usg_influx.go +++ b/core/unifi/usg_influx.go @@ -81,7 +81,6 @@ func (u *USG) PointsAt(now time.Time) ([]*influx.Point, error) { "wan1_bytes-r": u.Wan1.BytesR.Val, "wan1_enable": u.Wan1.Enable.Val, "wan1_full_duplex": u.Wan1.FullDuplex.Val, - "wan1_purpose": "uplink", // because it should have a purpose. "wan1_gateway": u.Wan1.Gateway, "wan1_ifname": u.Wan1.Ifname, "wan1_ip": u.Wan1.IP, @@ -106,7 +105,6 @@ func (u *USG) PointsAt(now time.Time) ([]*influx.Point, error) { "wan2_bytes-r": u.Wan2.BytesR.Val, "wan2_enable": u.Wan2.Enable.Val, "wan2_full_duplex": u.Wan2.FullDuplex.Val, - "wan2_purpose": "uplink", // because it should have a purpose. "wan2_gateway": u.Wan2.Gateway, "wan2_ifname": u.Wan2.Ifname, "wan2_ip": u.Wan2.IP, @@ -140,7 +138,6 @@ func (u *USG) PointsAt(now time.Time) ([]*influx.Point, error) { "stat_duration": u.Stat.Duration.Val, "stat_datetime": u.Stat.Datetime, "gw": u.Stat.Gw, - "false": "false", // to fill holes in graphs. "lan-rx_bytes": u.Stat.LanRxBytes.Val, "lan-rx_packets": u.Stat.LanRxPackets.Val, "lan-tx_bytes": u.Stat.LanTxBytes.Val, @@ -167,46 +164,36 @@ func (u *USG) PointsAt(now time.Time) ([]*influx.Point, error) { "device_id": u.ID, "device_mac": u.Mac, "site_name": u.SiteName, - "name": p.Name, "up": p.Up.Txt, "dhcpd_dns_enabled": p.DhcpdDNSEnabled.Txt, "dhcpd_enabled": p.DhcpdEnabled.Txt, - "dhcpd_ntp_enabled": p.DhcpdNtpEnabled.Txt, "dhcpd_time_offset_enabled": p.DhcpdTimeOffsetEnabled.Txt, "dhcp_relay_enabledy": p.DhcpRelayEnabled.Txt, "dhcpd_gateway_enabled": p.DhcpdGatewayEnabled.Txt, - "dhcpd_wins_enabled": p.DhcpdWinsEnabled.Txt, - "dhcpguard_enabled": p.DhcpguardEnabled.Txt, "enabled": p.Enabled.Txt, "vlan_enabled": p.VlanEnabled.Txt, "attr_no_delete": p.AttrNoDelete.Txt, - "upnp_lan_enabled": p.UpnpLanEnabled.Txt, - "igmp_snooping": p.IgmpSnooping.Txt, "is_guest": p.IsGuest.Txt, "is_nat": p.IsNat.Txt, "networkgroup": p.Networkgroup, "site_id": p.SiteID, } fields := map[string]interface{}{ - "dhcpd_ip_1": p.DhcpdIP1, - "domain_name": p.DomainName, - "dhcpd_start": p.DhcpdStart, - "dhcpd_stop": p.DhcpdStop, - "ip": p.IP, - "ip_subnet": p.IPSubnet, - "mac": p.Mac, - "name": p.Name, - "num_sta": p.NumSta.Val, - "purpose": p.Purpose, - "rx_bytes": p.RxBytes.Val, - "rx_packets": p.RxPackets.Val, - "tx_bytes": p.TxBytes.Val, - "tx_packets": p.TxPackets.Val, - "vlan": p.Vlan.Txt, - "dhcpd_ntp_1": p.DhcpdNtp1, - "dhcpd_unifi_controller": p.DhcpdUnifiController, - "ipv6_interface_type": p.Ipv6InterfaceType, - "attr_hidden_id": p.AttrHiddenID, + "domain_name": p.DomainName, + "dhcpd_start": p.DhcpdStart, + "dhcpd_stop": p.DhcpdStop, + "ip": p.IP, + "ip_subnet": p.IPSubnet, + "mac": p.Mac, + "name": p.Name, + "num_sta": p.NumSta.Val, + "purpose": p.Purpose, + "rx_bytes": p.RxBytes.Val, + "rx_packets": p.RxPackets.Val, + "tx_bytes": p.TxBytes.Val, + "tx_packets": p.TxPackets.Val, + "ipv6_interface_type": p.Ipv6InterfaceType, + "attr_hidden_id": p.AttrHiddenID, } pt, err = influx.NewPoint("usg_networks", tags, fields, now) if err != nil { @@ -223,13 +210,11 @@ func (u *USG) PointsAt(now time.Time) ([]*influx.Point, error) { "name": p.Name, "ifname": p.Ifname, "ip": p.IP, - "netmask": p.Netmask, "mac": p.Mac, "up": p.Up.Txt, "speed": p.Speed.Txt, "full_duplex": p.FullDuplex.Txt, "enable": p.Enable.Txt, - "gateway": p.Gateway, } fields := map[string]interface{}{ "rx_bytes": p.RxBytes.Val, diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index c797391d..c92bd426 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -40,102 +40,29 @@ type USG struct { Ifname string `json:"ifname"` Networkgroup string `json:"networkgroup"` } `json:"ethernet_overrides"` - HwCaps FlexInt `json:"hw_caps"` - BoardRev FlexInt `json:"board_rev"` - Unsupported FlexBool `json:"unsupported"` - UnsupportedReason FlexInt `json:"unsupported_reason"` - DeviceID string `json:"device_id"` - State FlexInt `json:"state"` - LastSeen FlexInt `json:"last_seen"` - Upgradable FlexBool `json:"upgradable"` - AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` - Rollupgrade FlexBool `json:"rollupgrade"` - KnownCfgversion string `json:"known_cfgversion"` - Uptime FlexInt `json:"uptime"` - Locating FlexBool `json:"locating"` - ConnectRequestIP string `json:"connect_request_ip"` - ConnectRequestPort string `json:"connect_request_port"` - SysStats struct { - Loadavg1 FlexInt `json:"loadavg_1"` - Loadavg15 FlexInt `json:"loadavg_15"` - Loadavg5 FlexInt `json:"loadavg_5"` - MemBuffer FlexInt `json:"mem_buffer"` - MemTotal FlexInt `json:"mem_total"` - MemUsed FlexInt `json:"mem_used"` - } `json:"sys_stats"` - SystemStats struct { - CPU FlexInt `json:"cpu"` - Mem FlexInt `json:"mem"` - Uptime FlexInt `json:"uptime"` - } `json:"system-stats"` - GuestToken string `json:"guest_token"` - SpeedtestStatus struct { - Latency FlexInt `json:"latency"` - Rundate FlexInt `json:"rundate"` - Runtime FlexInt `json:"runtime"` - StatusDownload FlexInt `json:"status_download"` - StatusPing FlexInt `json:"status_ping"` - StatusSummary FlexInt `json:"status_summary"` - StatusUpload FlexInt `json:"status_upload"` - XputDownload FlexInt `json:"xput_download"` - XputUpload FlexInt `json:"xput_upload"` - } `json:"speedtest-status"` - SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"` - Wan1 struct { - TxBytesR FlexInt `json:"tx_bytes-r"` - RxBytesR FlexInt `json:"rx_bytes-r"` - BytesR FlexInt `json:"bytes-r"` - MaxSpeed FlexInt `json:"max_speed"` - Type string `json:"type"` - Name string `json:"name"` - Ifname string `json:"ifname"` - IP string `json:"ip"` - Netmask string `json:"netmask"` - Mac string `json:"mac"` - Up FlexBool `json:"up"` - Speed FlexInt `json:"speed"` - FullDuplex FlexBool `json:"full_duplex"` - RxBytes FlexInt `json:"rx_bytes"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxPackets FlexInt `json:"rx_packets"` - TxBytes FlexInt `json:"tx_bytes"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxPackets FlexInt `json:"tx_packets"` - RxMulticast FlexInt `json:"rx_multicast"` - Enable FlexBool `json:"enable"` - DNS []string `json:"dns"` - Gateway string `json:"gateway"` - } `json:"wan1"` - Wan2 struct { - TxBytesR FlexInt `json:"tx_bytes-r"` - RxBytesR FlexInt `json:"rx_bytes-r"` - BytesR FlexInt `json:"bytes-r"` - MaxSpeed FlexInt `json:"max_speed"` - Type string `json:"type"` - Name string `json:"name"` - Ifname string `json:"ifname"` - IP string `json:"ip"` - Netmask string `json:"netmask"` - Mac string `json:"mac"` - Up FlexBool `json:"up"` - Speed FlexInt `json:"speed"` - FullDuplex FlexBool `json:"full_duplex"` - RxBytes FlexInt `json:"rx_bytes"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxPackets FlexInt `json:"rx_packets"` - TxBytes FlexInt `json:"tx_bytes"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxPackets FlexInt `json:"tx_packets"` - RxMulticast FlexInt `json:"rx_multicast"` - Enable FlexBool `json:"enable"` - DNS []string `json:"dns"` - Gateway string `json:"gateway"` - } `json:"wan2"` - PortTable []struct { + HwCaps FlexInt `json:"hw_caps"` + BoardRev FlexInt `json:"board_rev"` + Unsupported FlexBool `json:"unsupported"` + UnsupportedReason FlexInt `json:"unsupported_reason"` + DeviceID string `json:"device_id"` + State FlexInt `json:"state"` + LastSeen FlexInt `json:"last_seen"` + Upgradable FlexBool `json:"upgradable"` + AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` + Rollupgrade FlexBool `json:"rollupgrade"` + KnownCfgversion string `json:"known_cfgversion"` + Uptime FlexInt `json:"uptime"` + Locating FlexBool `json:"locating"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + SysStats SysStats `json:"sys_stats"` + SystemStats SystemStats `json:"system-stats"` + GuestToken string `json:"guest_token"` + SpeedtestStatus SpeedtestStatus `json:"speedtest-status"` + SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"` + Wan1 Wan `json:"wan1"` + Wan2 Wan `json:"wan2"` + PortTable []struct { Name string `json:"name"` Ifname string `json:"ifname"` IP string `json:"ip"` @@ -198,41 +125,7 @@ type USG struct { AttrNoDelete FlexBool `json:"attr_no_delete,omitempty"` AttrHiddenID string `json:"attr_hidden_id,omitempty"` } `json:"network_table"` - Uplink struct { - Drops FlexInt `json:"drops"` - Enable FlexBool `json:"enable"` - FullDuplex FlexBool `json:"full_duplex"` - Gateways []string `json:"gateways"` - IP string `json:"ip"` - Latency FlexInt `json:"latency"` - Mac string `json:"mac"` - Name string `json:"name"` - Nameservers []string `json:"nameservers"` - Netmask string `json:"netmask"` - NumPort FlexInt `json:"num_port"` - RxBytes FlexInt `json:"rx_bytes"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxMulticast FlexInt `json:"rx_multicast"` - RxPackets FlexInt `json:"rx_packets"` - Speed FlexInt `json:"speed"` - SpeedtestLastrun FlexInt `json:"speedtest_lastrun"` - SpeedtestPing FlexInt `json:"speedtest_ping"` - SpeedtestStatus string `json:"speedtest_status"` - TxBytes FlexInt `json:"tx_bytes"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxPackets FlexInt `json:"tx_packets"` - Up FlexBool `json:"up"` - Uptime FlexInt `json:"uptime"` - XputDown FlexInt `json:"xput_down"` - XputUp FlexInt `json:"xput_up"` - TxBytesR FlexInt `json:"tx_bytes-r"` - RxBytesR FlexInt `json:"rx_bytes-r"` - BytesR FlexInt `json:"bytes-r"` - MaxSpeed FlexInt `json:"max_speed"` - Type string `json:"type"` - } `json:"uplink"` + Uplink Uplink `json:"uplink"` Stat USGStat `json:"stat"` TxBytes FlexInt `json:"tx_bytes"` RxBytes FlexInt `json:"rx_bytes"` @@ -245,6 +138,114 @@ type USG struct { NumHandheld FlexInt `json:"num_handheld"` } +// Uplink is the Internet connection (or uplink) on a UniFi device. +type Uplink struct { + BytesR FlexInt `json:"bytes-r"` + Drops FlexInt `json:"drops"` + Enable FlexBool `json:"enable,omitempty"` + FullDuplex FlexBool `json:"full_duplex"` + Gateways []string `json:"gateways,omitempty"` + IP string `json:"ip"` + Latency FlexInt `json:"latency"` + Mac string `json:"mac,omitempty"` + MaxSpeed FlexInt `json:"max_speed"` + Name string `json:"name"` + Nameservers []string `json:"nameservers"` + Netmask string `json:"netmask"` + NumPort FlexInt `json:"num_port"` + RxBytes FlexInt `json:"rx_bytes"` + RxBytesR FlexInt `json:"rx_bytes-r"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxMulticast FlexInt `json:"rx_multicast"` + RxPackets FlexInt `json:"rx_packets"` + Speed FlexInt `json:"speed"` + SpeedtestLastrun FlexInt `json:"speedtest_lastrun,omitempty"` + SpeedtestPing FlexInt `json:"speedtest_ping,omitempty"` + SpeedtestStatus string `json:"speedtest_status,omitempty"` + TxBytes FlexInt `json:"tx_bytes"` + TxBytesR FlexInt `json:"tx_bytes-r"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxPackets FlexInt `json:"tx_packets"` + Type string `json:"type"` + Up FlexBool `json:"up"` + Uptime FlexInt `json:"uptime"` + XputDown FlexInt `json:"xput_down,omitempty"` + XputUp FlexInt `json:"xput_up,omitempty"` +} + +// Wan is a Wan interface on a USG or UDM. +type Wan struct { + Autoneg FlexBool `json:"autoneg"` + BytesR FlexInt `json:"bytes-r"` + DNS []string `json:"dns"` + Enable FlexBool `json:"enable"` + FlowctrlRx FlexBool `json:"flowctrl_rx"` + FlowctrlTx FlexBool `json:"flowctrl_tx"` + FullDuplex FlexBool `json:"full_duplex"` + Gateway string `json:"gateway"` // may be deprecated + IP string `json:"ip"` + Ifname string `json:"ifname"` + IsUplink FlexBool `json:"is_uplink"` + Mac string `json:"mac"` + MaxSpeed FlexInt `json:"max_speed"` + Media string `json:"media"` + Name string `json:"name"` + Netmask string `json:"netmask"` // may be deprecated + NumPort int `json:"num_port"` + PortIdx int `json:"port_idx"` + PortPoe FlexBool `json:"port_poe"` + RxBroadcast FlexInt `json:"rx_broadcast"` + RxBytes FlexInt `json:"rx_bytes"` + RxBytesR FlexInt `json:"rx_bytes-r"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxMulticast FlexInt `json:"rx_multicast"` + RxPackets FlexInt `json:"rx_packets"` + Speed FlexInt `json:"speed"` + TxBroadcast FlexInt `json:"tx_broadcast"` + TxBytes FlexInt `json:"tx_bytes"` + TxBytesR FlexInt `json:"tx_bytes-r"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxMulticast FlexInt `json:"tx_multicast"` + TxPackets FlexInt `json:"tx_packets"` + Type string `json:"type"` + Up FlexBool `json:"up"` +} + +// SpeedtestStatus is the speed test info on a USG or UDM. +type SpeedtestStatus struct { + Latency FlexInt `json:"latency"` + Rundate FlexInt `json:"rundate"` + Runtime FlexInt `json:"runtime"` + ServerDesc string `json:"server_desc,omitempty"` + StatusDownload FlexInt `json:"status_download"` + StatusPing FlexInt `json:"status_ping"` + StatusSummary FlexInt `json:"status_summary"` + StatusUpload FlexInt `json:"status_upload"` + XputDownload FlexInt `json:"xput_download"` + XputUpload FlexInt `json:"xput_upload"` +} + +// SystemStats is system info for a UDM, USG, USW. +type SystemStats struct { + CPU FlexInt `json:"cpu"` + Mem FlexInt `json:"mem"` + Uptime FlexInt `json:"uptime"` +} + +// SysStats is load info for a UDM, USG, USW. +type SysStats struct { + Loadavg1 FlexInt `json:"loadavg_1"` + Loadavg15 FlexInt `json:"loadavg_15"` + Loadavg5 FlexInt `json:"loadavg_5"` + MemBuffer FlexInt `json:"mem_buffer"` + MemTotal FlexInt `json:"mem_total"` + MemUsed FlexInt `json:"mem_used"` +} + // USGStat holds the "stat" data for a gateway. // This is split out because of a JSON data format change from 5.10 to 5.11. type USGStat struct { @@ -261,14 +262,15 @@ type gw struct { Duration FlexInt `json:"duration"` WanRxPackets FlexInt `json:"wan-rx_packets"` WanRxBytes FlexInt `json:"wan-rx_bytes"` + WanRxDropped FlexInt `json:"wan-rx_dropped"` WanTxPackets FlexInt `json:"wan-tx_packets"` WanTxBytes FlexInt `json:"wan-tx_bytes"` LanRxPackets FlexInt `json:"lan-rx_packets"` LanRxBytes FlexInt `json:"lan-rx_bytes"` LanTxPackets FlexInt `json:"lan-tx_packets"` LanTxBytes FlexInt `json:"lan-tx_bytes"` - WanRxDropped FlexInt `json:"wan-rx_dropped"` LanRxDropped FlexInt `json:"lan-rx_dropped"` + WanRxErrors FlexInt `json:"wan-rx_errors,omitempty"` } // UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Gateway Stat data. diff --git a/core/unifi/usw_influx.go b/core/unifi/usw_influx.go index f02e195b..01744d4b 100644 --- a/core/unifi/usw_influx.go +++ b/core/unifi/usw_influx.go @@ -23,7 +23,6 @@ func (u *USW) PointsAt(now time.Time) ([]*influx.Point, error) { tags := map[string]string{ "id": u.ID, "mac": u.Mac, - "device_type": u.Stat.O, "device_oid": u.Stat.Oid, "site_id": u.SiteID, "site_name": u.SiteName, @@ -34,12 +33,9 @@ func (u *USW) PointsAt(now time.Time) ([]*influx.Point, error) { "config_network_type": u.ConfigNetwork.Type, "device_id": u.DeviceID, "inform_ip": u.InformIP, - "last_uplink_mac": u.LastUplink.UplinkMac, "known_cfgversion": u.KnownCfgversion, - "led_override": u.LedOverride, "locating": u.Locating.Txt, "model": u.Model, - "outdoor_mode_override": u.OutdoorModeOverride, "serial": u.Serial, "type": u.Type, "dot1x_portctrl_enabled": u.Dot1XPortctrlEnabled.Txt, @@ -51,57 +47,43 @@ func (u *USW) PointsAt(now time.Time) ([]*influx.Point, error) { "stp_version": u.StpVersion, } fields := map[string]interface{}{ - "fw_caps": u.FwCaps.Val, - "guest-num_sta": u.GuestNumSta.Val, - "ip": u.IP, - "bytes": u.Bytes.Val, - "fan_level": u.FanLevel.Val, - "general_temperature": u.GeneralTemperature.Val, - "last_seen": u.LastSeen.Val, - "license_state": u.LicenseState, - "overheating": u.Overheating.Val, - "rx_bytes": u.RxBytes.Val, - "tx_bytes": u.TxBytes.Val, - "uptime": u.Uptime.Val, - "roll_upgrade": u.Rollupgrade.Val, - "state": u.State.Val, - "upgradable": u.Upgradable.Val, - "user-num_sta": u.UserNumSta.Val, - "version": u.Version, - "loadavg_1": u.SysStats.Loadavg1.Val, - "loadavg_5": u.SysStats.Loadavg5.Val, - "loadavg_15": u.SysStats.Loadavg15.Val, - "mem_buffer": u.SysStats.MemBuffer.Val, - "mem_used": u.SysStats.MemUsed.Val, - "mem_total": u.SysStats.MemTotal.Val, - "cpu": u.SystemStats.CPU.Val, - "mem": u.SystemStats.Mem.Val, - "system_uptime": u.SystemStats.Uptime.Val, - "stat_bytes": u.Stat.Bytes.Val, - "stat_duration": u.Stat.Duration.Val, - "stat_guest-rx_bytes": u.Stat.RxBytes.Val, - "stat_guest-rx_crypts": u.Stat.RxCrypts.Val, - "stat_guest-rx_dropped": u.Stat.RxDropped.Val, - "stat_guest-rx_errors": u.Stat.RxErrors.Val, - "stat_guest-rx_frags": u.Stat.RxFrags.Val, - "stat_guest-rx_packets": u.Stat.RxPackets.Val, - "stat_guest-tx_bytes": u.Stat.TxBytes.Val, - "stat_guest-tx_dropped": u.Stat.TxDropped.Val, - "stat_guest-tx_errors": u.Stat.TxErrors.Val, - "stat_guest-tx_packets": u.Stat.TxPackets.Val, - "stat_guest-tx_retries": u.Stat.TxRetries.Val, - "stat_rx_bytes": u.Stat.RxBytes.Val, - "stat_rx_crypts": u.Stat.RxCrypts.Val, - "stat_rx_dropped": u.Stat.RxDropped.Val, - "stat_rx_errors": u.Stat.RxErrors.Val, - "stat_rx_frags": u.Stat.RxFrags.Val, - "stat_rx_packets": u.Stat.TxPackets.Val, - "stat_tx_bytes": u.Stat.TxBytes.Val, - "stat_tx_dropped": u.Stat.TxDropped.Val, - "stat_tx_errors": u.Stat.TxErrors.Val, - "stat_tx_packets": u.Stat.TxPackets.Val, - "stat_tx_retries": u.Stat.TxRetries.Val, - "uplink_depth": u.UplinkDepth.Txt, + "fw_caps": u.FwCaps.Val, + "guest-num_sta": u.GuestNumSta.Val, + "ip": u.IP, + "bytes": u.Bytes.Val, + "fan_level": u.FanLevel.Val, + "general_temperature": u.GeneralTemperature.Val, + "last_seen": u.LastSeen.Val, + "license_state": u.LicenseState, + "overheating": u.Overheating.Val, + "rx_bytes": u.RxBytes.Val, + "tx_bytes": u.TxBytes.Val, + "uptime": u.Uptime.Val, + "state": u.State.Val, + "user-num_sta": u.UserNumSta.Val, + "version": u.Version, + "loadavg_1": u.SysStats.Loadavg1.Val, + "loadavg_5": u.SysStats.Loadavg5.Val, + "loadavg_15": u.SysStats.Loadavg15.Val, + "mem_buffer": u.SysStats.MemBuffer.Val, + "mem_used": u.SysStats.MemUsed.Val, + "mem_total": u.SysStats.MemTotal.Val, + "cpu": u.SystemStats.CPU.Val, + "mem": u.SystemStats.Mem.Val, + "system_uptime": u.SystemStats.Uptime.Val, + "stat_bytes": u.Stat.Bytes.Val, + "stat_rx_bytes": u.Stat.RxBytes.Val, + "stat_rx_crypts": u.Stat.RxCrypts.Val, + "stat_rx_dropped": u.Stat.RxDropped.Val, + "stat_rx_errors": u.Stat.RxErrors.Val, + "stat_rx_frags": u.Stat.RxFrags.Val, + "stat_rx_packets": u.Stat.TxPackets.Val, + "stat_tx_bytes": u.Stat.TxBytes.Val, + "stat_tx_dropped": u.Stat.TxDropped.Val, + "stat_tx_errors": u.Stat.TxErrors.Val, + "stat_tx_packets": u.Stat.TxPackets.Val, + "stat_tx_retries": u.Stat.TxRetries.Val, + "uplink_depth": u.UplinkDepth.Txt, // Add the port stats too. } pt, err := influx.NewPoint("usw", tags, fields, now) diff --git a/core/unifi/usw_type.go b/core/unifi/usw_type.go index ee3ebfb4..90a2848e 100644 --- a/core/unifi/usw_type.go +++ b/core/unifi/usw_type.go @@ -42,55 +42,7 @@ type USW struct { PortIdx FlexInt `json:"port_idx"` PortconfID string `json:"portconf_id"` } `json:"port_overrides"` - PortTable []struct { - PortIdx FlexInt `json:"port_idx"` - Media string `json:"media"` - PortPoe FlexBool `json:"port_poe"` - PoeCaps FlexInt `json:"poe_caps"` - SpeedCaps FlexInt `json:"speed_caps"` - OpMode string `json:"op_mode"` - PortconfID string `json:"portconf_id"` - PoeMode string `json:"poe_mode,omitempty"` - Autoneg FlexBool `json:"autoneg"` - Dot1XMode string `json:"dot1x_mode"` - Dot1XStatus string `json:"dot1x_status"` - Enable FlexBool `json:"enable"` - FlowctrlRx FlexBool `json:"flowctrl_rx"` - FlowctrlTx FlexBool `json:"flowctrl_tx"` - FullDuplex FlexBool `json:"full_duplex"` - IsUplink FlexBool `json:"is_uplink"` - Jumbo FlexBool `json:"jumbo"` - PoeClass string `json:"poe_class,omitempty"` - PoeCurrent FlexInt `json:"poe_current,omitempty"` - PoeEnable FlexBool `json:"poe_enable,omitempty"` - PoeGood FlexBool `json:"poe_good,omitempty"` - PoePower FlexInt `json:"poe_power,omitempty"` - PoeVoltage FlexInt `json:"poe_voltage,omitempty"` - RxBroadcast FlexInt `json:"rx_broadcast"` - RxBytes FlexInt `json:"rx_bytes"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxMulticast FlexInt `json:"rx_multicast"` - RxPackets FlexInt `json:"rx_packets"` - Satisfaction FlexInt `json:"satisfaction"` - Speed FlexInt `json:"speed"` - StpPathcost FlexInt `json:"stp_pathcost"` - StpState string `json:"stp_state"` - TxBroadcast FlexInt `json:"tx_broadcast"` - TxBytes FlexInt `json:"tx_bytes"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxMulticast FlexInt `json:"tx_multicast"` - TxPackets FlexInt `json:"tx_packets"` - Up FlexBool `json:"up"` - TxBytesR FlexInt `json:"tx_bytes-r"` - RxBytesR FlexInt `json:"rx_bytes-r"` - BytesR FlexInt `json:"bytes-r"` - Name string `json:"name"` - Masked FlexBool `json:"masked"` - AggregatedBy FlexBool `json:"aggregated_by"` - SfpFound FlexBool `json:"sfp_found,omitempty"` - } `json:"port_table"` + PortTable []Port `json:"port_table"` Serial string `json:"serial"` SiteID string `json:"site_id"` StpPriority string `json:"stp_priority"` @@ -103,70 +55,34 @@ type USW struct { MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` } `json:"switch_caps"` - HwCaps FlexInt `json:"hw_caps"` - Unsupported FlexBool `json:"unsupported"` - UnsupportedReason FlexInt `json:"unsupported_reason"` - SysErrorCaps FlexInt `json:"sys_error_caps"` - DeviceID string `json:"device_id"` - State FlexInt `json:"state"` - LastSeen FlexInt `json:"last_seen"` - Upgradable FlexBool `json:"upgradable"` - AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` - Rollupgrade FlexBool `json:"rollupgrade"` - KnownCfgversion string `json:"known_cfgversion"` - Uptime FlexInt `json:"uptime"` - Locating FlexBool `json:"locating"` - ConnectRequestIP string `json:"connect_request_ip"` - ConnectRequestPort string `json:"connect_request_port"` - SysStats struct { - Loadavg1 FlexInt `json:"loadavg_1"` - Loadavg15 FlexInt `json:"loadavg_15"` - Loadavg5 FlexInt `json:"loadavg_5"` - MemBuffer FlexInt `json:"mem_buffer"` - MemTotal FlexInt `json:"mem_total"` - MemUsed FlexInt `json:"mem_used"` - } `json:"sys_stats"` - SystemStats struct { - CPU FlexInt `json:"cpu"` - Mem FlexInt `json:"mem"` - Uptime FlexInt `json:"uptime"` - } `json:"system-stats"` - FanLevel FlexInt `json:"fan_level"` - GeneralTemperature FlexInt `json:"general_temperature"` - Overheating FlexBool `json:"overheating"` - TotalMaxPower FlexInt `json:"total_max_power"` - DownlinkTable []struct { + HwCaps FlexInt `json:"hw_caps"` + Unsupported FlexBool `json:"unsupported"` + UnsupportedReason FlexInt `json:"unsupported_reason"` + SysErrorCaps FlexInt `json:"sys_error_caps"` + DeviceID string `json:"device_id"` + State FlexInt `json:"state"` + LastSeen FlexInt `json:"last_seen"` + Upgradable FlexBool `json:"upgradable"` + AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` + Rollupgrade FlexBool `json:"rollupgrade"` + KnownCfgversion string `json:"known_cfgversion"` + Uptime FlexInt `json:"uptime"` + Locating FlexBool `json:"locating"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + SysStats SysStats `json:"sys_stats"` + SystemStats SystemStats `json:"system-stats"` + FanLevel FlexInt `json:"fan_level"` + GeneralTemperature FlexInt `json:"general_temperature"` + Overheating FlexBool `json:"overheating"` + TotalMaxPower FlexInt `json:"total_max_power"` + DownlinkTable []struct { PortIdx FlexInt `json:"port_idx"` Speed FlexInt `json:"speed"` FullDuplex FlexBool `json:"full_duplex"` Mac string `json:"mac"` } `json:"downlink_table"` - Uplink struct { - FullDuplex FlexBool `json:"full_duplex"` - IP string `json:"ip"` - Mac string `json:"mac"` - Name string `json:"name"` - Netmask string `json:"netmask"` - NumPort FlexInt `json:"num_port"` - RxBytes FlexInt `json:"rx_bytes"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxMulticast FlexInt `json:"rx_multicast"` - RxPackets FlexInt `json:"rx_packets"` - Speed FlexInt `json:"speed"` - TxBytes FlexInt `json:"tx_bytes"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxPackets FlexInt `json:"tx_packets"` - Up FlexBool `json:"up"` - PortIdx FlexInt `json:"port_idx"` - Media string `json:"media"` - MaxSpeed FlexInt `json:"max_speed"` - UplinkMac string `json:"uplink_mac"` - Type string `json:"type"` - TxBytesR FlexInt `json:"tx_bytes-r"` - RxBytesR FlexInt `json:"rx_bytes-r"` - } `json:"uplink"` + Uplink Uplink `json:"uplink"` LastUplink struct { UplinkMac string `json:"uplink_mac"` } `json:"last_uplink"` @@ -180,6 +96,67 @@ type USW struct { GuestNumSta FlexInt `json:"guest-num_sta"` } +// Port is a physical connection on a USW or UDM. +type Port struct { + AggregatedBy FlexBool `json:"aggregated_by"` + Autoneg FlexBool `json:"autoneg,omitempty"` + BytesR FlexInt `json:"bytes-r"` + DNS []string `json:"dns,omitempty"` + Dot1XMode string `json:"dot1x_mode"` + Dot1XStatus string `json:"dot1x_status"` + Enable FlexBool `json:"enable"` + FlowctrlRx FlexBool `json:"flowctrl_rx"` + FlowctrlTx FlexBool `json:"flowctrl_tx"` + FullDuplex FlexBool `json:"full_duplex"` + IP string `json:"ip,omitempty"` + Ifname string `json:"ifname,omitempty"` + IsUplink FlexBool `json:"is_uplink"` + Mac string `json:"mac,omitempty"` + Jumbo FlexBool `json:"jumbo,omitempty"` + Masked FlexBool `json:"masked"` + Media string `json:"media"` + Name string `json:"name"` + NetworkName string `json:"network_name,omitempty"` + NumPort int `json:"num_port,omitempty"` + OpMode string `json:"op_mode"` + PoeCaps FlexInt `json:"poe_caps"` + PoeClass string `json:"poe_class,omitempty"` + PoeCurrent FlexInt `json:"poe_current,omitempty"` + PoeEnable FlexBool `json:"poe_enable,omitempty"` + PoeGood FlexBool `json:"poe_good,omitempty"` + PoeMode string `json:"poe_mode,omitempty"` + PoePower FlexInt `json:"poe_power,omitempty"` + PoeVoltage FlexInt `json:"poe_voltage,omitempty"` + PortDelta struct { + TimeDelta int64 `json:"time_delta"` + } `json:"port_delta,omitempty"` + PortIdx FlexInt `json:"port_idx"` + PortPoe FlexBool `json:"port_poe"` + PortconfID string `json:"portconf_id"` + RxBroadcast FlexInt `json:"rx_broadcast"` + RxBytes FlexInt `json:"rx_bytes"` + RxBytesR FlexInt `json:"rx_bytes-r"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxMulticast FlexInt `json:"rx_multicast"` + RxPackets FlexInt `json:"rx_packets"` + Satisfaction FlexInt `json:"satisfaction,omitempty"` + SfpFound FlexBool `json:"sfp_found,omitempty"` + Speed FlexInt `json:"speed"` + SpeedCaps FlexInt `json:"speed_caps"` + StpPathcost FlexInt `json:"stp_pathcost"` + StpState string `json:"stp_state"` + TxBroadcast FlexInt `json:"tx_broadcast"` + TxBytes FlexInt `json:"tx_bytes"` + TxBytesR FlexInt `json:"tx_bytes-r"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxMulticast FlexInt `json:"tx_multicast"` + TxPackets FlexInt `json:"tx_packets"` + Type string `json:"type,omitempty"` + Up FlexBool `json:"up"` +} + // USWStat holds the "stat" data for a switch. // This is split out because of a JSON data format change from 5.10 to 5.11. type USWStat struct { @@ -210,124 +187,124 @@ type sw struct { TxBroadcast FlexInt `json:"tx_broadcast"` Bytes FlexInt `json:"bytes"` Duration FlexInt `json:"duration"` - Port1RxPackets FlexInt `json:"port_1-rx_packets"` - Port1RxBytes FlexInt `json:"port_1-rx_bytes"` - Port1TxPackets FlexInt `json:"port_1-tx_packets"` - Port1TxBytes FlexInt `json:"port_1-tx_bytes"` + Port1RxPackets FlexInt `json:"port_1-rx_packets,omitempty"` + Port1RxBytes FlexInt `json:"port_1-rx_bytes,omitempty"` + Port1TxPackets FlexInt `json:"port_1-tx_packets,omitempty"` + Port1TxBytes FlexInt `json:"port_1-tx_bytes,omitempty"` Port1TxMulticast FlexInt `json:"port_1-tx_multicast"` Port1TxBroadcast FlexInt `json:"port_1-tx_broadcast"` - Port3RxPackets FlexInt `json:"port_3-rx_packets"` - Port3RxBytes FlexInt `json:"port_3-rx_bytes"` - Port3TxPackets FlexInt `json:"port_3-tx_packets"` - Port3TxBytes FlexInt `json:"port_3-tx_bytes"` + Port3RxPackets FlexInt `json:"port_3-rx_packets,omitempty"` + Port3RxBytes FlexInt `json:"port_3-rx_bytes,omitempty"` + Port3TxPackets FlexInt `json:"port_3-tx_packets,omitempty"` + Port3TxBytes FlexInt `json:"port_3-tx_bytes,omitempty"` Port3RxBroadcast FlexInt `json:"port_3-rx_broadcast"` Port3TxMulticast FlexInt `json:"port_3-tx_multicast"` Port3TxBroadcast FlexInt `json:"port_3-tx_broadcast"` - Port6RxPackets FlexInt `json:"port_6-rx_packets"` - Port6RxBytes FlexInt `json:"port_6-rx_bytes"` - Port6TxPackets FlexInt `json:"port_6-tx_packets"` - Port6TxBytes FlexInt `json:"port_6-tx_bytes"` + Port6RxPackets FlexInt `json:"port_6-rx_packets,omitempty"` + Port6RxBytes FlexInt `json:"port_6-rx_bytes,omitempty"` + Port6TxPackets FlexInt `json:"port_6-tx_packets,omitempty"` + Port6TxBytes FlexInt `json:"port_6-tx_bytes,omitempty"` Port6RxMulticast FlexInt `json:"port_6-rx_multicast"` Port6TxMulticast FlexInt `json:"port_6-tx_multicast"` Port6TxBroadcast FlexInt `json:"port_6-tx_broadcast"` - Port7RxPackets FlexInt `json:"port_7-rx_packets"` - Port7RxBytes FlexInt `json:"port_7-rx_bytes"` - Port7TxPackets FlexInt `json:"port_7-tx_packets"` - Port7TxBytes FlexInt `json:"port_7-tx_bytes"` + Port7RxPackets FlexInt `json:"port_7-rx_packets,omitempty"` + Port7RxBytes FlexInt `json:"port_7-rx_bytes,omitempty"` + Port7TxPackets FlexInt `json:"port_7-tx_packets,omitempty"` + Port7TxBytes FlexInt `json:"port_7-tx_bytes,omitempty"` Port7TxMulticast FlexInt `json:"port_7-tx_multicast"` Port7TxBroadcast FlexInt `json:"port_7-tx_broadcast"` - Port9RxPackets FlexInt `json:"port_9-rx_packets"` - Port9RxBytes FlexInt `json:"port_9-rx_bytes"` - Port9TxPackets FlexInt `json:"port_9-tx_packets"` - Port9TxBytes FlexInt `json:"port_9-tx_bytes"` + Port9RxPackets FlexInt `json:"port_9-rx_packets,omitempty"` + Port9RxBytes FlexInt `json:"port_9-rx_bytes,omitempty"` + Port9TxPackets FlexInt `json:"port_9-tx_packets,omitempty"` + Port9TxBytes FlexInt `json:"port_9-tx_bytes,omitempty"` Port9TxMulticast FlexInt `json:"port_9-tx_multicast"` Port9TxBroadcast FlexInt `json:"port_9-tx_broadcast"` - Port10RxPackets FlexInt `json:"port_10-rx_packets"` - Port10RxBytes FlexInt `json:"port_10-rx_bytes"` - Port10TxPackets FlexInt `json:"port_10-tx_packets"` - Port10TxBytes FlexInt `json:"port_10-tx_bytes"` + Port10RxPackets FlexInt `json:"port_10-rx_packets,omitempty"` + Port10RxBytes FlexInt `json:"port_10-rx_bytes,omitempty"` + Port10TxPackets FlexInt `json:"port_10-tx_packets,omitempty"` + Port10TxBytes FlexInt `json:"port_10-tx_bytes,omitempty"` Port10RxMulticast FlexInt `json:"port_10-rx_multicast"` Port10TxMulticast FlexInt `json:"port_10-tx_multicast"` Port10TxBroadcast FlexInt `json:"port_10-tx_broadcast"` - Port11RxPackets FlexInt `json:"port_11-rx_packets"` - Port11RxBytes FlexInt `json:"port_11-rx_bytes"` - Port11TxPackets FlexInt `json:"port_11-tx_packets"` - Port11TxBytes FlexInt `json:"port_11-tx_bytes"` + Port11RxPackets FlexInt `json:"port_11-rx_packets,omitempty"` + Port11RxBytes FlexInt `json:"port_11-rx_bytes,omitempty"` + Port11TxPackets FlexInt `json:"port_11-tx_packets,omitempty"` + Port11TxBytes FlexInt `json:"port_11-tx_bytes,omitempty"` Port11TxMulticast FlexInt `json:"port_11-tx_multicast"` Port11TxBroadcast FlexInt `json:"port_11-tx_broadcast"` - Port12RxPackets FlexInt `json:"port_12-rx_packets"` - Port12RxBytes FlexInt `json:"port_12-rx_bytes"` - Port12TxPackets FlexInt `json:"port_12-tx_packets"` - Port12TxBytes FlexInt `json:"port_12-tx_bytes"` + Port12RxPackets FlexInt `json:"port_12-rx_packets,omitempty"` + Port12RxBytes FlexInt `json:"port_12-rx_bytes,omitempty"` + Port12TxPackets FlexInt `json:"port_12-tx_packets,omitempty"` + Port12TxBytes FlexInt `json:"port_12-tx_bytes,omitempty"` Port12TxMulticast FlexInt `json:"port_12-tx_multicast"` Port12TxBroadcast FlexInt `json:"port_12-tx_broadcast"` - Port13RxPackets FlexInt `json:"port_13-rx_packets"` - Port13RxBytes FlexInt `json:"port_13-rx_bytes"` - Port13TxPackets FlexInt `json:"port_13-tx_packets"` - Port13TxBytes FlexInt `json:"port_13-tx_bytes"` + Port13RxPackets FlexInt `json:"port_13-rx_packets,omitempty"` + Port13RxBytes FlexInt `json:"port_13-rx_bytes,omitempty"` + Port13TxPackets FlexInt `json:"port_13-tx_packets,omitempty"` + Port13TxBytes FlexInt `json:"port_13-tx_bytes,omitempty"` Port13RxMulticast FlexInt `json:"port_13-rx_multicast"` Port13RxBroadcast FlexInt `json:"port_13-rx_broadcast"` Port13TxMulticast FlexInt `json:"port_13-tx_multicast"` Port13TxBroadcast FlexInt `json:"port_13-tx_broadcast"` - Port15RxPackets FlexInt `json:"port_15-rx_packets"` - Port15RxBytes FlexInt `json:"port_15-rx_bytes"` - Port15TxPackets FlexInt `json:"port_15-tx_packets"` - Port15TxBytes FlexInt `json:"port_15-tx_bytes"` + Port15RxPackets FlexInt `json:"port_15-rx_packets,omitempty"` + Port15RxBytes FlexInt `json:"port_15-rx_bytes,omitempty"` + Port15TxPackets FlexInt `json:"port_15-tx_packets,omitempty"` + Port15TxBytes FlexInt `json:"port_15-tx_bytes,omitempty"` Port15RxBroadcast FlexInt `json:"port_15-rx_broadcast"` Port15TxMulticast FlexInt `json:"port_15-tx_multicast"` Port15TxBroadcast FlexInt `json:"port_15-tx_broadcast"` - Port16RxPackets FlexInt `json:"port_16-rx_packets"` - Port16RxBytes FlexInt `json:"port_16-rx_bytes"` - Port16TxPackets FlexInt `json:"port_16-tx_packets"` - Port16TxBytes FlexInt `json:"port_16-tx_bytes"` + Port16RxPackets FlexInt `json:"port_16-rx_packets,omitempty"` + Port16RxBytes FlexInt `json:"port_16-rx_bytes,omitempty"` + Port16TxPackets FlexInt `json:"port_16-tx_packets,omitempty"` + Port16TxBytes FlexInt `json:"port_16-tx_bytes,omitempty"` Port16TxMulticast FlexInt `json:"port_16-tx_multicast"` Port16TxBroadcast FlexInt `json:"port_16-tx_broadcast"` - Port17RxPackets FlexInt `json:"port_17-rx_packets"` - Port17RxBytes FlexInt `json:"port_17-rx_bytes"` - Port17TxPackets FlexInt `json:"port_17-tx_packets"` - Port17TxBytes FlexInt `json:"port_17-tx_bytes"` + Port17RxPackets FlexInt `json:"port_17-rx_packets,omitempty"` + Port17RxBytes FlexInt `json:"port_17-rx_bytes,omitempty"` + Port17TxPackets FlexInt `json:"port_17-tx_packets,omitempty"` + Port17TxBytes FlexInt `json:"port_17-tx_bytes,omitempty"` Port17TxMulticast FlexInt `json:"port_17-tx_multicast"` Port17TxBroadcast FlexInt `json:"port_17-tx_broadcast"` - Port18RxPackets FlexInt `json:"port_18-rx_packets"` - Port18RxBytes FlexInt `json:"port_18-rx_bytes"` - Port18TxPackets FlexInt `json:"port_18-tx_packets"` - Port18TxBytes FlexInt `json:"port_18-tx_bytes"` + Port18RxPackets FlexInt `json:"port_18-rx_packets,omitempty"` + Port18RxBytes FlexInt `json:"port_18-rx_bytes,omitempty"` + Port18TxPackets FlexInt `json:"port_18-tx_packets,omitempty"` + Port18TxBytes FlexInt `json:"port_18-tx_bytes,omitempty"` Port18RxMulticast FlexInt `json:"port_18-rx_multicast"` Port18TxMulticast FlexInt `json:"port_18-tx_multicast"` Port18TxBroadcast FlexInt `json:"port_18-tx_broadcast"` - Port19RxPackets FlexInt `json:"port_19-rx_packets"` - Port19RxBytes FlexInt `json:"port_19-rx_bytes"` - Port19TxPackets FlexInt `json:"port_19-tx_packets"` - Port19TxBytes FlexInt `json:"port_19-tx_bytes"` + Port19RxPackets FlexInt `json:"port_19-rx_packets,omitempty"` + Port19RxBytes FlexInt `json:"port_19-rx_bytes,omitempty"` + Port19TxPackets FlexInt `json:"port_19-tx_packets,omitempty"` + Port19TxBytes FlexInt `json:"port_19-tx_bytes,omitempty"` Port19TxMulticast FlexInt `json:"port_19-tx_multicast"` Port19TxBroadcast FlexInt `json:"port_19-tx_broadcast"` - Port21RxPackets FlexInt `json:"port_21-rx_packets"` - Port21RxBytes FlexInt `json:"port_21-rx_bytes"` - Port21TxPackets FlexInt `json:"port_21-tx_packets"` - Port21TxBytes FlexInt `json:"port_21-tx_bytes"` + Port21RxPackets FlexInt `json:"port_21-rx_packets,omitempty"` + Port21RxBytes FlexInt `json:"port_21-rx_bytes,omitempty"` + Port21TxPackets FlexInt `json:"port_21-tx_packets,omitempty"` + Port21TxBytes FlexInt `json:"port_21-tx_bytes,omitempty"` Port21RxBroadcast FlexInt `json:"port_21-rx_broadcast"` Port21TxMulticast FlexInt `json:"port_21-tx_multicast"` Port21TxBroadcast FlexInt `json:"port_21-tx_broadcast"` - Port22RxPackets FlexInt `json:"port_22-rx_packets"` - Port22RxBytes FlexInt `json:"port_22-rx_bytes"` - Port22TxPackets FlexInt `json:"port_22-tx_packets"` - Port22TxBytes FlexInt `json:"port_22-tx_bytes"` + Port22RxPackets FlexInt `json:"port_22-rx_packets,omitempty"` + Port22RxBytes FlexInt `json:"port_22-rx_bytes,omitempty"` + Port22TxPackets FlexInt `json:"port_22-tx_packets,omitempty"` + Port22TxBytes FlexInt `json:"port_22-tx_bytes,omitempty"` Port22RxMulticast FlexInt `json:"port_22-rx_multicast"` Port22TxMulticast FlexInt `json:"port_22-tx_multicast"` Port22TxBroadcast FlexInt `json:"port_22-tx_broadcast"` - Port23RxPackets FlexInt `json:"port_23-rx_packets"` - Port23RxBytes FlexInt `json:"port_23-rx_bytes"` + Port23RxPackets FlexInt `json:"port_23-rx_packets,omitempty"` + Port23RxBytes FlexInt `json:"port_23-rx_bytes,omitempty"` Port23RxDropped FlexInt `json:"port_23-rx_dropped"` - Port23TxPackets FlexInt `json:"port_23-tx_packets"` - Port23TxBytes FlexInt `json:"port_23-tx_bytes"` + Port23TxPackets FlexInt `json:"port_23-tx_packets,omitempty"` + Port23TxBytes FlexInt `json:"port_23-tx_bytes,omitempty"` Port23RxMulticast FlexInt `json:"port_23-rx_multicast"` Port23RxBroadcast FlexInt `json:"port_23-rx_broadcast"` Port23TxMulticast FlexInt `json:"port_23-tx_multicast"` Port23TxBroadcast FlexInt `json:"port_23-tx_broadcast"` - Port24RxPackets FlexInt `json:"port_24-rx_packets"` - Port24RxBytes FlexInt `json:"port_24-rx_bytes"` - Port24TxPackets FlexInt `json:"port_24-tx_packets"` - Port24TxBytes FlexInt `json:"port_24-tx_bytes"` + Port24RxPackets FlexInt `json:"port_24-rx_packets,omitempty"` + Port24RxBytes FlexInt `json:"port_24-rx_bytes,omitempty"` + Port24TxPackets FlexInt `json:"port_24-tx_packets,omitempty"` + Port24TxBytes FlexInt `json:"port_24-tx_bytes,omitempty"` Port24RxMulticast FlexInt `json:"port_24-rx_multicast"` Port24TxMulticast FlexInt `json:"port_24-tx_multicast"` Port24TxBroadcast FlexInt `json:"port_24-tx_broadcast"` @@ -366,11 +343,11 @@ type sw struct { Port10TxDropped FlexInt `json:"port_10-tx_dropped"` Port16TxDropped FlexInt `json:"port_16-tx_dropped"` Port1RxBroadcast FlexInt `json:"port_1-rx_broadcast"` - Port4RxPackets FlexInt `json:"port_4-rx_packets"` - Port4RxBytes FlexInt `json:"port_4-rx_bytes"` + Port4RxPackets FlexInt `json:"port_4-rx_packets,omitempty"` + Port4RxBytes FlexInt `json:"port_4-rx_bytes,omitempty"` Port4RxDropped FlexInt `json:"port_4-rx_dropped"` - Port4TxPackets FlexInt `json:"port_4-tx_packets"` - Port4TxBytes FlexInt `json:"port_4-tx_bytes"` + Port4TxPackets FlexInt `json:"port_4-tx_packets,omitempty"` + Port4TxBytes FlexInt `json:"port_4-tx_bytes,omitempty"` Port4TxDropped FlexInt `json:"port_4-tx_dropped"` Port4RxMulticast FlexInt `json:"port_4-rx_multicast"` Port4RxBroadcast FlexInt `json:"port_4-rx_broadcast"` From 48b9fb701eaa874a9417a7d224f0ea372cf501ff Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sat, 24 Aug 2019 01:02:15 -0700 Subject: [PATCH 090/194] fix --- core/unifi/usw_influx.go | 1 - core/unifi/usw_type.go | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/core/unifi/usw_influx.go b/core/unifi/usw_influx.go index 01744d4b..0797783a 100644 --- a/core/unifi/usw_influx.go +++ b/core/unifi/usw_influx.go @@ -84,7 +84,6 @@ func (u *USW) PointsAt(now time.Time) ([]*influx.Point, error) { "stat_tx_packets": u.Stat.TxPackets.Val, "stat_tx_retries": u.Stat.TxRetries.Val, "uplink_depth": u.UplinkDepth.Txt, - // Add the port stats too. } pt, err := influx.NewPoint("usw", tags, fields, now) if err != nil { diff --git a/core/unifi/usw_type.go b/core/unifi/usw_type.go index 90a2848e..a6c94d25 100644 --- a/core/unifi/usw_type.go +++ b/core/unifi/usw_type.go @@ -62,9 +62,9 @@ type USW struct { DeviceID string `json:"device_id"` State FlexInt `json:"state"` LastSeen FlexInt `json:"last_seen"` - Upgradable FlexBool `json:"upgradable"` - AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` - Rollupgrade FlexBool `json:"rollupgrade"` + Upgradable FlexBool `json:"upgradable,omitempty"` + AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded,omitempty"` + Rollupgrade FlexBool `json:"rollupgrade,omitempty"` KnownCfgversion string `json:"known_cfgversion"` Uptime FlexInt `json:"uptime"` Locating FlexBool `json:"locating"` From 39c6f6801e45c538300d7e390ebbcd091ed25a2b Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sat, 24 Aug 2019 01:32:12 -0700 Subject: [PATCH 091/194] Bug fix on FlexInt=nil/null, remove errors pkg, minor cleanup. --- core/unifi/Gopkg.lock | 25 ++++++++++++------------- core/unifi/Gopkg.toml | 35 ----------------------------------- core/unifi/ids.go | 3 +-- core/unifi/types.go | 9 ++++++--- core/unifi/unifi.go | 26 +++++++++++++------------- 5 files changed, 32 insertions(+), 66 deletions(-) diff --git a/core/unifi/Gopkg.lock b/core/unifi/Gopkg.lock index 0ee3eca3..8c4a3916 100644 --- a/core/unifi/Gopkg.lock +++ b/core/unifi/Gopkg.lock @@ -19,15 +19,7 @@ "v2", ] pruneopts = "UT" - revision = "8ff2fc3824fcb533795f9a2f233275f0bb18d6c5" - -[[projects]] - digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b" - name = "github.com/pkg/errors" - packages = ["."] - pruneopts = "UT" - revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4" - version = "v0.8.1" + revision = "fc22c7df067eefd070157f157893fbce961d6359" [[projects]] digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" @@ -38,19 +30,26 @@ version = "v1.0.0" [[projects]] - digest = "1:972c2427413d41a1e06ca4897e8528e5a1622894050e2f527b38ddf0f343f759" + digest = "1:8548c309c65a85933a625be5e7d52b6ac927ca30c56869fae58123b8a77a75e1" name = "github.com/stretchr/testify" packages = ["assert"] pruneopts = "UT" - revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053" - version = "v1.3.0" + revision = "221dbe5ed46703ee255b1da0dec05086f5035f62" + version = "v1.4.0" + +[[projects]] + digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96" + name = "gopkg.in/yaml.v2" + packages = ["."] + pruneopts = "UT" + revision = "51d6538a90f86fe93ac480b35f37b2be17fef232" + version = "v2.2.2" [solve-meta] analyzer-name = "dep" analyzer-version = 1 input-imports = [ "github.com/influxdata/influxdb1-client/v2", - "github.com/pkg/errors", "github.com/stretchr/testify/assert", ] solver-name = "gps-cdcl" diff --git a/core/unifi/Gopkg.toml b/core/unifi/Gopkg.toml index b38356cd..ab0e6c81 100644 --- a/core/unifi/Gopkg.toml +++ b/core/unifi/Gopkg.toml @@ -1,42 +1,7 @@ -# Gopkg.toml example -# -# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" -# -# [prune] -# non-go = false -# go-tests = true -# unused-packages = true - - [[constraint]] branch = "master" name = "github.com/influxdata/influxdb1-client" -[[constraint]] - name = "github.com/pkg/errors" - version = "0.8.1" - -[[constraint]] - name = "github.com/stretchr/testify" - version = "1.3.0" - [prune] go-tests = true unused-packages = true diff --git a/core/unifi/ids.go b/core/unifi/ids.go index 634644a6..82dfc5b2 100644 --- a/core/unifi/ids.go +++ b/core/unifi/ids.go @@ -8,7 +8,6 @@ import ( "time" influx "github.com/influxdata/influxdb1-client/v2" - "github.com/pkg/errors" ) // IDSList contains a list that contains all of the IDS Events on a controller. @@ -124,7 +123,7 @@ func (u *Unifi) GetSiteIDS(site *Site, from, to time.Time) ([]*IDS, error) { return nil, err } if resp.StatusCode != http.StatusOK { - return nil, errors.Errorf("invalid status code from server %s", resp.Status) + return nil, fmt.Errorf("invalid status code from server %s", resp.Status) } if err := json.Unmarshal(body, &response); err != nil { return nil, err diff --git a/core/unifi/types.go b/core/unifi/types.go index ea323538..40d6d637 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -2,11 +2,10 @@ package unifi import ( "encoding/json" + "fmt" "net/http" "strconv" "strings" - - "github.com/pkg/errors" ) // This is a list of unifi API paths. @@ -90,8 +89,12 @@ func (f *FlexInt) UnmarshalJSON(b []byte) error { f.Txt = i f.Val, _ = strconv.ParseFloat(i, 64) return nil + case nil: + f.Txt = "0" + f.Val = 0 + return nil default: - return errors.New("Cannot unmarshal to FlexInt") + return fmt.Errorf("cannot unmarshal to FlexInt: %s", b) } } diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 3404c55c..0b376248 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -16,8 +16,6 @@ import ( "net/http" "net/http/cookiejar" "strings" - - "github.com/pkg/errors" ) // NewUnifi creates a http.Client with authenticated cookies. @@ -26,7 +24,7 @@ import ( func NewUnifi(user, pass, url string, verifySSL bool) (*Unifi, error) { jar, err := cookiejar.New(nil) if err != nil { - return nil, errors.Wrap(err, "cookiejar.New(nil)") + return nil, err } u := &Unifi{baseURL: strings.TrimRight(url, "/"), Client: &http.Client{ @@ -44,21 +42,24 @@ func (u *Unifi) getController(user, pass string) error { // magic login. req, err := u.UniReq(LoginPath, fmt.Sprintf(`{"username":"%s","password":"%s"}`, user, pass)) if err != nil { - return errors.Wrap(err, "UniReq(LoginPath, json)") + return err } resp, err := u.Do(req) if err != nil { - return errors.Wrap(err, "authReq.Do(req)") + return err } defer func() { _, _ = io.Copy(ioutil.Discard, resp.Body) // avoid leaking. _ = resp.Body.Close() }() if resp.StatusCode != http.StatusOK { - return errors.Errorf("authentication failed (user: %s): %s (status: %s)", + return fmt.Errorf("authentication failed (user: %s): %s (status: %s)", user, u.baseURL+LoginPath, resp.Status) } - return errors.Wrap(u.getServer(), "unable to get server version") + if err := u.getServer(); err != nil { + return fmt.Errorf("unable to get server version: %v", err) + } + return nil } // getServer sets the controller's version and UUID. @@ -139,8 +140,7 @@ func (u *Unifi) GetData(methodPath string, v interface{}) error { if err != nil { return err } - err = json.Unmarshal(body, v) - return errors.Wrapf(err, "json.Unmarshal(%s)", methodPath) + return json.Unmarshal(body, v) } // UniReq is a small helper function that adds an Accept header. @@ -164,21 +164,21 @@ func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err er func (u *Unifi) GetJSON(apiPath string) ([]byte, error) { req, err := u.UniReq(apiPath, "") if err != nil { - return []byte{}, errors.Wrapf(err, "c.UniReq(%s)", apiPath) + return []byte{}, err } resp, err := u.Do(req) if err != nil { - return []byte{}, errors.Wrapf(err, "c.Do(%s)", apiPath) + return []byte{}, err } defer func() { _ = resp.Body.Close() }() body, err := ioutil.ReadAll(resp.Body) if err != nil { - return body, errors.Wrapf(err, "ioutil.ReadAll(%s)", apiPath) + return body, err } if resp.StatusCode != http.StatusOK { - err = errors.Errorf("invalid status code from server %s", resp.Status) + err = fmt.Errorf("invalid status code from server %s", resp.Status) } return body, err } From 22d98cf6ed87b27886d75383b7cc6c7c0a35c0eb Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sat, 24 Aug 2019 01:34:55 -0700 Subject: [PATCH 092/194] fix test --- core/unifi/unifi_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/unifi_test.go b/core/unifi/unifi_test.go index 7ab1df31..b399995d 100644 --- a/core/unifi/unifi_test.go +++ b/core/unifi/unifi_test.go @@ -15,7 +15,7 @@ func TestNewUnifi(t *testing.T) { authReq, err := NewUnifi("user1", "pass2", url, false) a.NotNil(err) a.EqualValues(url, authReq.baseURL) - a.Contains(err.Error(), "authReq.Do(req):", "an invalid destination should product a .Do(req) error.") + a.Contains(err.Error(), "connection refused", "an invalid destination should product a connection error.") /* TODO: OPEN web server, check parameters posted, more. This test is incomplete. a.EqualValues(`{"username": "user1","password": "pass2"}`, string(post_params), "user/pass json parameters improperly encoded") From 97dcf6e309f027f1442b813484b81743bb3e3478 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sat, 24 Aug 2019 03:56:37 -0700 Subject: [PATCH 093/194] allow duplicate code --- core/unifi/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/.travis.yml b/core/unifi/.travis.yml index a05c4c9f..5266b77c 100644 --- a/core/unifi/.travis.yml +++ b/core/unifi/.travis.yml @@ -11,5 +11,5 @@ before_install: install: - dep ensure script: -- golangci-lint run --enable-all -e G402 +- golangci-lint run --enable-all -e G402 -e dupl - go test ./... From 934e7cdd7573292b05b453011e0fe92cd7911755 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 25 Aug 2019 03:20:01 -0700 Subject: [PATCH 094/194] Remove influx and add Config input struct --- core/unifi/Gopkg.lock | 17 +- core/unifi/Gopkg.toml | 4 - core/unifi/clients_influx.go | 114 ------------ core/unifi/ids.go | 48 ----- core/unifi/site_influx.go | 89 --------- core/unifi/types.go | 15 +- core/unifi/uap_influx.go | 286 ----------------------------- core/unifi/uap_influx_test.go | 18 -- core/unifi/uap_type.go | 12 +- core/unifi/udm_influx.go | 333 ---------------------------------- core/unifi/udm_type.go | 4 +- core/unifi/unifi.go | 36 ++-- core/unifi/unifi_test.go | 38 ++-- core/unifi/usg_influx.go | 238 ------------------------ core/unifi/usg_type.go | 11 +- core/unifi/usw_influx.go | 155 ---------------- core/unifi/usw_type.go | 11 +- 17 files changed, 75 insertions(+), 1354 deletions(-) delete mode 100644 core/unifi/clients_influx.go delete mode 100644 core/unifi/site_influx.go delete mode 100644 core/unifi/uap_influx.go delete mode 100644 core/unifi/uap_influx_test.go delete mode 100644 core/unifi/udm_influx.go delete mode 100644 core/unifi/usg_influx.go delete mode 100644 core/unifi/usw_influx.go diff --git a/core/unifi/Gopkg.lock b/core/unifi/Gopkg.lock index 8c4a3916..82983fff 100644 --- a/core/unifi/Gopkg.lock +++ b/core/unifi/Gopkg.lock @@ -9,18 +9,6 @@ revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" version = "v1.1.1" -[[projects]] - branch = "master" - digest = "1:50708c8fc92aec981df5c446581cf9f90ba9e2a5692118e0ce75d4534aaa14a2" - name = "github.com/influxdata/influxdb1-client" - packages = [ - "models", - "pkg/escape", - "v2", - ] - pruneopts = "UT" - revision = "fc22c7df067eefd070157f157893fbce961d6359" - [[projects]] digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" name = "github.com/pmezard/go-difflib" @@ -48,9 +36,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - input-imports = [ - "github.com/influxdata/influxdb1-client/v2", - "github.com/stretchr/testify/assert", - ] + input-imports = ["github.com/stretchr/testify/assert"] solver-name = "gps-cdcl" solver-version = 1 diff --git a/core/unifi/Gopkg.toml b/core/unifi/Gopkg.toml index ab0e6c81..5c879c7d 100644 --- a/core/unifi/Gopkg.toml +++ b/core/unifi/Gopkg.toml @@ -1,7 +1,3 @@ -[[constraint]] - branch = "master" - name = "github.com/influxdata/influxdb1-client" - [prune] go-tests = true unused-packages = true diff --git a/core/unifi/clients_influx.go b/core/unifi/clients_influx.go deleted file mode 100644 index 29f76f03..00000000 --- a/core/unifi/clients_influx.go +++ /dev/null @@ -1,114 +0,0 @@ -package unifi - -import ( - "time" - - influx "github.com/influxdata/influxdb1-client/v2" -) - -// Points generates Unifi Client datapoints for InfluxDB. -// These points can be passed directly to influx. -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) { - tags := map[string]string{ - "id": c.ID, - "mac": c.Mac, - "user_id": c.UserID, - "site_id": c.SiteID, - "site_name": c.SiteName, - "network_id": c.NetworkID, - "usergroup_id": c.UserGroupID, - "ap_mac": c.ApMac, - "gw_mac": c.GwMac, - "sw_mac": c.SwMac, - "ap_name": c.ApName, - "gw_name": c.GwName, - "sw_name": c.SwName, - "oui": c.Oui, - "radio_name": c.RadioName, - "radio": c.Radio, - "radio_proto": c.RadioProto, - "name": c.Name, - "fixed_ip": c.FixedIP, - "sw_port": c.SwPort.Txt, - "os_class": c.OsClass.Txt, - "os_name": c.OsName.Txt, - "dev_cat": c.DevCat.Txt, - "dev_id": c.DevID.Txt, - "dev_vendor": c.DevVendor.Txt, - "dev_family": c.DevFamily.Txt, - "is_11r": c.Is11R.Txt, - "is_wired": c.IsWired.Txt, - "is_guest": c.IsGuest.Txt, - "is_guest_by_uap": c.IsGuestByUAP.Txt, - "is_guest_by_ugw": c.IsGuestByUGW.Txt, - "is_guest_by_usw": c.IsGuestByUSW.Txt, - "noted": c.Noted.Txt, - "powersave_enabled": c.PowersaveEnabled.Txt, - "qos_policy_applied": c.QosPolicyApplied.Txt, - "use_fixedip": c.UseFixedIP.Txt, - "channel": c.Channel.Txt, - "vlan": c.Vlan.Txt, - } - fields := map[string]interface{}{ - "anomalies": c.Anomalies, - "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, - "wifi_tx_attempts": c.WifiTxAttempts, - "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, - "dpi_app": c.DpiStats.App.Val, - "dpi_cat": c.DpiStats.Cat.Val, - "dpi_rx_bytes": c.DpiStats.RxBytes.Val, - "dpi_rx_packets": c.DpiStats.RxPackets.Val, - "dpi_tx_bytes": c.DpiStats.TxBytes.Val, - "dpi_tx_packets": c.DpiStats.TxPackets.Val, - } - pt, err := influx.NewPoint("clients", tags, fields, now) - if err != nil { - return nil, err - } - return []*influx.Point{pt}, nil -} diff --git a/core/unifi/ids.go b/core/unifi/ids.go index 82dfc5b2..dcf22c9f 100644 --- a/core/unifi/ids.go +++ b/core/unifi/ids.go @@ -6,8 +6,6 @@ import ( "io/ioutil" "net/http" "time" - - influx "github.com/influxdata/influxdb1-client/v2" ) // IDSList contains a list that contains all of the IDS Events on a controller. @@ -133,49 +131,3 @@ func (u *Unifi) GetSiteIDS(site *Site, from, to time.Time) ([]*IDS, error) { } return response.Data, nil } - -// PointsAt has no usefulness. It is provided to satisfy external interfaces. -// 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) { - 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) { - tags := map[string]string{ - "in_iface": i.InIface, - "event_type": i.EventType, - "proto": i.Proto, - "app_proto": i.AppProto, - "usgip": i.Usgip, - "country_code": i.SrcipGeo.CountryCode, - "country_name": i.SrcipGeo.CountryName, - "region": i.SrcipGeo.Region, - "city": i.SrcipGeo.City, - "postal_code": i.SrcipGeo.PostalCode, - "srcipASN": i.SrcipASN, - "usgipASN": i.UsgipASN, - "alert_category": i.InnerAlertCategory, - "subsystem": i.Subsystem, - "catname": i.Catname, - } - fields := map[string]interface{}{ - "event_type": i.EventType, - "proto": i.Proto, - "app_proto": i.AppProto, - "usgip": i.Usgip, - "country_name": i.SrcipGeo.CountryName, - "city": i.SrcipGeo.City, - "postal_code": i.SrcipGeo.PostalCode, - "srcipASN": i.SrcipASN, - "usgipASN": i.UsgipASN, - } - pt, err := influx.NewPoint("intrusion_detect", tags, fields, i.Datetime) - if err != nil { - return nil, err - } - return []*influx.Point{pt}, nil -} diff --git a/core/unifi/site_influx.go b/core/unifi/site_influx.go deleted file mode 100644 index ac6f8045..00000000 --- a/core/unifi/site_influx.go +++ /dev/null @@ -1,89 +0,0 @@ -package unifi - -import ( - "strings" - "time" - - influx "github.com/influxdata/influxdb1-client/v2" -) - -// Points generates Unifi Sites' datapoints for InfluxDB. -// These points can be passed directly to influx. -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) { - points := []*influx.Point{} - for _, s := range u.Health { - tags := map[string]string{ - "id": u.ID, - "name": u.Name, - "site_name": u.SiteName, - "desc": u.Desc, - "status": s.Status, - "subsystem": s.Subsystem, - "wan_ip": s.WanIP, - "netmask": s.Netmask, - "gw_name": s.GwName, - "gw_mac": s.GwMac, - "gw_version": s.GwVersion, - "speedtest_status": s.SpeedtestStatus, - "lan_ip": s.LanIP, - "remote_user_enabled": s.RemoteUserEnabled.Txt, - "site_to_site_enabled": s.SiteToSiteEnabled.Txt, - "nameservers": strings.Join(s.Nameservers, ","), - "gateways": strings.Join(s.Gateways, ","), - "num_new_alarms": u.NumNewAlarms.Txt, - "attr_hidden_id": u.AttrHiddenID, - "attr_no_delete": u.AttrNoDelete.Txt, - } - fields := map[string]interface{}{ - "attr_hidden_id": u.AttrHiddenID, - "attr_no_delete": u.AttrNoDelete.Val, - "num_user": s.NumUser.Val, - "num_guest": s.NumGuest.Val, - "num_iot": s.NumIot.Val, - "tx_bytes-r": s.TxBytesR.Val, - "rx_bytes-r": s.RxBytesR.Val, - "status": s.Status, - "num_ap": s.NumAp.Val, - "num_adopted": s.NumAdopted.Val, - "num_disabled": s.NumDisabled.Val, - "num_disconnected": s.NumDisconnected.Val, - "num_pending": s.NumPending.Val, - "num_gw": s.NumGw.Val, - "wan_ip": s.WanIP, - "num_sta": s.NumSta.Val, - "gw_cpu": s.GwSystemStats.CPU.Val, - "gw_mem": s.GwSystemStats.Mem.Val, - "gw_uptime": s.GwSystemStats.Uptime.Val, - "latency": s.Latency.Val, - "uptime": s.Uptime.Val, - "drops": s.Drops.Val, - "xput_up": s.XputUp.Val, - "xput_down": s.XputDown.Val, - "speedtest_ping": s.SpeedtestPing.Val, - "speedtest_lastrun": s.SpeedtestLastrun.Val, - "num_sw": s.NumSw.Val, - "remote_user_num_active": s.RemoteUserNumActive.Val, - "remote_user_num_inactive": s.RemoteUserNumInactive.Val, - "remote_user_rx_bytes": s.RemoteUserRxBytes.Val, - "remote_user_tx_bytes": s.RemoteUserTxBytes.Val, - "remote_user_rx_packets": s.RemoteUserRxPackets.Val, - "remote_user_tx_packets": s.RemoteUserTxPackets.Val, - "num_new_alarms": u.NumNewAlarms.Val, - "nameservers": len(s.Nameservers), - "gateways": len(s.Gateways), - } - pt, err := influx.NewPoint("subsystems", tags, fields, time.Now()) - if err != nil { - return points, err - } - points = append(points, pt) - } - return points, nil -} diff --git a/core/unifi/types.go b/core/unifi/types.go index 40d6d637..571f333b 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -47,15 +47,24 @@ type Devices struct { UDMs []*UDM } +// Config is the data passed into our library. This configures things and allows +// us to connect to a controller and write log messages. +type Config struct { + User string + Pass string + URL string + VerifySSL bool + ErrorLog Logger + DebugLog Logger +} + // Unifi is what you get in return for providing a password! Unifi represents // a controller that you can make authenticated requests to. Use this to make // additional requests for devices, clients or other custom data. Do not set // the loggers to nil. Set them to DiscardLogs if you want no logs. type Unifi struct { *http.Client - baseURL string - ErrorLog Logger - DebugLog Logger + *Config *server } diff --git a/core/unifi/uap_influx.go b/core/unifi/uap_influx.go deleted file mode 100644 index 9ca988c0..00000000 --- a/core/unifi/uap_influx.go +++ /dev/null @@ -1,286 +0,0 @@ -package unifi - -import ( - "time" - - influx "github.com/influxdata/influxdb1-client/v2" -) - -// Points generates Wireless-Access-Point datapoints for InfluxDB. -// These points can be passed directly to influx. -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) { - if u.Stat.ap == nil { - // Disabled devices lack stats. - u.Stat.ap = &ap{} - } - tags := map[string]string{ - "id": u.ID, - "mac": u.Mac, - "device_type": u.Stat.O, - "device_oid": u.Stat.Oid, - "device_ap": u.Stat.Ap, - "site_id": u.SiteID, - "site_name": u.SiteName, - "name": u.Name, - "adopted": u.Adopted.Txt, - "cfgversion": u.Cfgversion, - "config_network_ip": u.ConfigNetwork.IP, - "config_network_type": u.ConfigNetwork.Type, - "connect_request_ip": u.ConnectRequestIP, - "device_id": u.DeviceID, - "has_eth1": u.HasEth1.Txt, - "inform_ip": u.InformIP, - "isolated": u.Isolated.Txt, - "known_cfgversion": u.KnownCfgversion, - "model": u.Model, - "outdoor_mode_override": u.OutdoorModeOverride, - "serial": u.Serial, - "type": u.Type, - "vwireEnabled": u.VwireEnabled.Txt, - } - fields := map[string]interface{}{ - "ip": u.IP, - "bytes": u.Bytes.Val, - "bytes_d": u.BytesD.Val, - "bytes_r": u.BytesR.Val, - "last_seen": u.LastSeen.Val, - "rx_bytes": u.RxBytes.Val, - "rx_bytes-d": u.RxBytesD.Val, - "tx_bytes": u.TxBytes.Val, - "tx_bytes-d": u.TxBytesD.Val, - "uptime": u.Uptime.Val, - "scanning": u.Scanning.Val, - "spectrum_scanning": u.SpectrumScanning.Val, - "roll_upgrade": u.Rollupgrade.Val, - "state": u.State, - "upgradable": u.Upgradable.Val, - "user-num_sta": u.UserNumSta, - "guest-num_sta": u.GuestNumSta, - "version": u.Version, - "loadavg_1": u.SysStats.Loadavg1.Val, - "loadavg_5": u.SysStats.Loadavg5.Val, - "loadavg_15": u.SysStats.Loadavg15.Val, - "mem_buffer": u.SysStats.MemBuffer.Val, - "mem_total": u.SysStats.MemTotal.Val, - "mem_used": u.SysStats.MemUsed.Val, - "cpu": u.SystemStats.CPU.Val, - "mem": u.SystemStats.Mem.Val, - "system_uptime": u.SystemStats.Uptime.Val, - "stat_guest-wifi0-rx_packets": u.Stat.GuestWifi0RxPackets.Val, - "stat_guest-wifi1-rx_packets": u.Stat.GuestWifi1RxPackets.Val, - "stat_user-wifi1-rx_packets": u.Stat.UserWifi1RxPackets.Val, - "stat_user-wifi0-rx_packets": u.Stat.UserWifi0RxPackets.Val, - "stat_user-rx_packets": u.Stat.UserRxPackets.Val, - "stat_guest-rx_packets": u.Stat.GuestRxPackets.Val, - "stat_wifi0-rx_packets": u.Stat.Wifi0RxPackets.Val, - "stat_wifi1-rx_packets": u.Stat.Wifi1RxPackets.Val, - "stat_rx_packets": u.Stat.RxPackets.Val, - "stat_guest-wifi0-rx_bytes": u.Stat.GuestWifi0RxBytes.Val, - "stat_guest-wifi1-rx_bytes": u.Stat.GuestWifi1RxBytes.Val, - "stat_user-wifi1-rx_bytes": u.Stat.UserWifi1RxBytes.Val, - "stat_user-wifi0-rx_bytes": u.Stat.UserWifi0RxBytes.Val, - "stat_user-rx_bytes": u.Stat.UserRxBytes.Val, - "stat_guest-rx_bytes": u.Stat.GuestRxBytes.Val, - "stat_wifi0-rx_bytes": u.Stat.Wifi0RxBytes.Val, - "stat_wifi1-rx_bytes": u.Stat.Wifi1RxBytes.Val, - "stat_rx_bytes": u.Stat.RxBytes.Val, - "stat_guest-wifi0-rx_errors": u.Stat.GuestWifi0RxErrors.Val, - "stat_guest-wifi1-rx_errors": u.Stat.GuestWifi1RxErrors.Val, - "stat_user-wifi1-rx_errors": u.Stat.UserWifi1RxErrors.Val, - "stat_user-wifi0-rx_errors": u.Stat.UserWifi0RxErrors.Val, - "stat_user-rx_errors": u.Stat.UserRxErrors.Val, - "stat_guest-rx_errors": u.Stat.GuestRxErrors.Val, - "stat_wifi0-rx_errors": u.Stat.Wifi0RxErrors.Val, - "stat_wifi1-rx_errors": u.Stat.Wifi1RxErrors.Val, - "stat_rx_errors": u.Stat.RxErrors.Val, - "stat_guest-wifi0-rx_dropped": u.Stat.GuestWifi0RxDropped.Val, - "stat_guest-wifi1-rx_dropped": u.Stat.GuestWifi1RxDropped.Val, - "stat_user-wifi1-rx_dropped": u.Stat.UserWifi1RxDropped.Val, - "stat_user-wifi0-rx_dropped": u.Stat.UserWifi0RxDropped.Val, - "stat_user-rx_dropped": u.Stat.UserRxDropped.Val, - "stat_guest-rx_dropped": u.Stat.GuestRxDropped.Val, - "stat_wifi0-rx_dropped": u.Stat.Wifi0RxDropped.Val, - "stat_wifi1-rx_dropped": u.Stat.Wifi1RxDropped.Val, - "stat_rx_dropped": u.Stat.RxDropped.Val, - "stat_guest-wifi0-rx_crypts": u.Stat.GuestWifi0RxCrypts.Val, - "stat_guest-wifi1-rx_crypts": u.Stat.GuestWifi1RxCrypts.Val, - "stat_user-wifi1-rx_crypts": u.Stat.UserWifi1RxCrypts.Val, - "stat_user-wifi0-rx_crypts": u.Stat.UserWifi0RxCrypts.Val, - "stat_user-rx_crypts": u.Stat.UserRxCrypts.Val, - "stat_guest-rx_crypts": u.Stat.GuestRxCrypts.Val, - "stat_wifi0-rx_crypts": u.Stat.Wifi0RxCrypts.Val, - "stat_wifi1-rx_crypts": u.Stat.Wifi1RxCrypts.Val, - "stat_rx_crypts": u.Stat.RxCrypts.Val, - "stat_guest-wifi0-rx_frags": u.Stat.GuestWifi0RxFrags.Val, - "stat_guest-wifi1-rx_frags": u.Stat.GuestWifi1RxFrags.Val, - "stat_user-wifi1-rx_frags": u.Stat.UserWifi1RxFrags.Val, - "stat_user-wifi0-rx_frags": u.Stat.UserWifi0RxFrags.Val, - "stat_user-rx_frags": u.Stat.UserRxFrags.Val, - "stat_guest-rx_frags": u.Stat.GuestRxFrags.Val, - "stat_wifi0-rx_frags": u.Stat.Wifi0RxFrags.Val, - "stat_wifi1-rx_frags": u.Stat.Wifi1RxFrags.Val, - "stat_rx_frags": u.Stat.RxFrags.Val, - "stat_guest-wifi0-tx_packets": u.Stat.GuestWifi0TxPackets.Val, - "stat_guest-wifi1-tx_packets": u.Stat.GuestWifi1TxPackets.Val, - "stat_user-wifi1-tx_packets": u.Stat.UserWifi1TxPackets.Val, - "stat_user-wifi0-tx_packets": u.Stat.UserWifi0TxPackets.Val, - "stat_user-tx_packets": u.Stat.UserTxPackets.Val, - "stat_guest-tx_packets": u.Stat.GuestTxPackets.Val, - "stat_wifi0-tx_packets": u.Stat.Wifi0TxPackets.Val, - "stat_wifi1-tx_packets": u.Stat.Wifi1TxPackets.Val, - "stat_tx_packets": u.Stat.TxPackets.Val, - "stat_guest-wifi0-tx_bytes": u.Stat.GuestWifi0TxBytes.Val, - "stat_guest-wifi1-tx_bytes": u.Stat.GuestWifi1TxBytes.Val, - "stat_user-wifi1-tx_bytes": u.Stat.UserWifi1TxBytes.Val, - "stat_user-wifi0-tx_bytes": u.Stat.UserWifi0TxBytes.Val, - "stat_user-tx_bytes": u.Stat.UserTxBytes.Val, - "stat_guest-tx_bytes": u.Stat.GuestTxBytes.Val, - "stat_wifi0-tx_bytes": u.Stat.Wifi0TxBytes.Val, - "stat_wifi1-tx_bytes": u.Stat.Wifi1TxBytes.Val, - "stat_tx_bytes": u.Stat.TxBytes.Val, - "stat_guest-wifi0-tx_errors": u.Stat.GuestWifi0TxErrors.Val, - "stat_guest-wifi1-tx_errors": u.Stat.GuestWifi1TxErrors.Val, - "stat_user-wifi1-tx_errors": u.Stat.UserWifi1TxErrors.Val, - "stat_user-wifi0-tx_errors": u.Stat.UserWifi0TxErrors.Val, - "stat_user-tx_errors": u.Stat.UserTxErrors.Val, - "stat_guest-tx_errors": u.Stat.GuestTxErrors.Val, - "stat_wifi0-tx_errors": u.Stat.Wifi0TxErrors.Val, - "stat_wifi1-tx_errors": u.Stat.Wifi1TxErrors.Val, - "stat_tx_errors": u.Stat.TxErrors.Val, - "stat_guest-wifi0-tx_dropped": u.Stat.GuestWifi0TxDropped.Val, - "stat_guest-wifi1-tx_dropped": u.Stat.GuestWifi1TxDropped.Val, - "stat_user-wifi1-tx_dropped": u.Stat.UserWifi1TxDropped.Val, - "stat_user-wifi0-tx_dropped": u.Stat.UserWifi0TxDropped.Val, - "stat_user-tx_dropped": u.Stat.UserTxDropped.Val, - "stat_guest-tx_dropped": u.Stat.GuestTxDropped.Val, - "stat_wifi0-tx_dropped": u.Stat.Wifi0TxDropped.Val, - "stat_wifi1-tx_dropped": u.Stat.Wifi1TxDropped.Val, - "stat_tx_dropped": u.Stat.TxDropped.Val, - "stat_guest-wifi0-tx_retries": u.Stat.GuestWifi0TxRetries.Val, - "stat_guest-wifi1-tx_retries": u.Stat.GuestWifi1TxRetries.Val, - "stat_user-wifi1-tx_retries": u.Stat.UserWifi1TxRetries.Val, - "stat_user-wifi0-tx_retries": u.Stat.UserWifi0TxRetries.Val, - "stat_user-tx_retries": u.Stat.UserTxRetries.Val, - "stat_guest-tx_retries": u.Stat.GuestTxRetries.Val, - "stat_wifi0-tx_retries": u.Stat.Wifi0TxRetries.Val, - "stat_wifi1-tx_retries": u.Stat.Wifi1TxRetries.Val, - } - pt, err := influx.NewPoint("uap", tags, fields, now) - if err != nil { - return nil, err - } - points := []*influx.Point{pt} - - tags = make(map[string]string) - fields = make(map[string]interface{}) - // Loop each virtual AP (ESSID) and extract data for it - // from radio_tables and radio_table_stats. - for _, s := range u.VapTable { - tags["device_name"] = u.Name - tags["device_id"] = u.ID - tags["device_mac"] = u.Mac - tags["site_name"] = u.SiteName - tags["ap_mac"] = s.ApMac - tags["bssid"] = s.Bssid - tags["id"] = s.ID - tags["name"] = s.Name - tags["radio_name"] = s.RadioName - tags["wlanconf_id"] = s.WlanconfID - tags["essid"] = s.Essid - tags["site_id"] = s.SiteID - tags["usage"] = s.Usage - tags["state"] = s.State - tags["is_guest"] = s.IsGuest.Txt - tags["is_wep"] = s.IsWep.Txt - - fields["ccq"] = s.Ccq - fields["extchannel"] = s.Extchannel - fields["mac_filter_rejections"] = s.MacFilterRejections - fields["num_satisfaction_sta"] = s.NumSatisfactionSta.Val - fields["avg_client_signal"] = s.AvgClientSignal.Val - fields["satisfaction"] = s.Satisfaction.Val - fields["satisfaction_now"] = s.SatisfactionNow.Val - fields["rx_bytes"] = s.RxBytes.Val - fields["rx_crypts"] = s.RxCrypts.Val - fields["rx_dropped"] = s.RxDropped.Val - fields["rx_errors"] = s.RxErrors.Val - fields["rx_frags"] = s.RxFrags.Val - fields["rx_nwids"] = s.RxNwids.Val - fields["rx_packets"] = s.RxPackets.Val - fields["tx_bytes"] = s.TxBytes.Val - fields["tx_dropped"] = s.TxDropped.Val - fields["tx_errors"] = s.TxErrors.Val - fields["tx_packets"] = s.TxPackets.Val - fields["tx_power"] = s.TxPower.Val - fields["tx_retries"] = s.TxRetries.Val - fields["tx_combined_retries"] = s.TxCombinedRetries.Val - fields["tx_data_mpdu_bytes"] = s.TxDataMpduBytes.Val - fields["tx_rts_retries"] = s.TxRtsRetries.Val - fields["tx_success"] = s.TxSuccess.Val - fields["tx_total"] = s.TxTotal.Val - fields["tx_tcp_goodbytes"] = s.TxTCPStats.Goodbytes.Val - fields["tx_tcp_lat_avg"] = s.TxTCPStats.LatAvg.Val - fields["tx_tcp_lat_max"] = s.TxTCPStats.LatMax.Val - fields["tx_tcp_lat_min"] = s.TxTCPStats.LatMin.Val - fields["rx_tcp_goodbytes"] = s.RxTCPStats.Goodbytes.Val - fields["rx_tcp_lat_avg"] = s.RxTCPStats.LatAvg.Val - fields["rx_tcp_lat_max"] = s.RxTCPStats.LatMax.Val - fields["rx_tcp_lat_min"] = s.RxTCPStats.LatMin.Val - fields["wifi_tx_latency_mov_avg"] = s.WifiTxLatencyMov.Avg.Val - fields["wifi_tx_latency_mov_max"] = s.WifiTxLatencyMov.Max.Val - fields["wifi_tx_latency_mov_min"] = s.WifiTxLatencyMov.Min.Val - fields["wifi_tx_latency_mov_total"] = s.WifiTxLatencyMov.Total.Val - fields["wifi_tx_latency_mov_cuont"] = s.WifiTxLatencyMov.TotalCount.Val - - for _, p := range u.RadioTable { - if p.Name != s.RadioName { - continue - } - tags["wlangroup_id"] = p.WlangroupID - tags["channel"] = p.Channel.Txt - tags["radio"] = p.Radio - fields["current_antenna_gain"] = p.CurrentAntennaGain.Val - fields["ht"] = p.Ht - fields["max_txpower"] = p.MaxTxpower.Val - fields["min_rssi_enabled"] = p.MinRssiEnabled.Val - fields["min_txpower"] = p.MinTxpower.Val - fields["nss"] = p.Nss.Val - fields["radio_caps"] = p.RadioCaps.Val - fields["tx_power"] = p.TxPower.Val - } - - for _, p := range u.RadioTableStats { - if p.Name != s.RadioName { - continue - } - fields["ast_be_xmit"] = p.AstBeXmit.Val - fields["channel"] = p.Channel.Val - fields["cu_self_rx"] = p.CuSelfRx.Val - fields["cu_self_tx"] = p.CuSelfTx.Val - fields["cu_total"] = p.CuTotal.Val - fields["extchannel"] = p.Extchannel.Val - fields["gain"] = p.Gain.Val - fields["guest-num_sta"] = p.GuestNumSta.Val - fields["num_sta"] = p.NumSta.Val - fields["radio"] = p.Radio - fields["tx_packets"] = p.TxPackets.Val - fields["tx_power"] = p.TxPower.Val - fields["tx_retries"] = p.TxRetries.Val - fields["user-num_sta"] = p.UserNumSta.Val - } - - pt, err := influx.NewPoint("uap_vaps", tags, fields, now) - if err != nil { - return points, err - } - points = append(points, pt) - } - return points, nil -} diff --git a/core/unifi/uap_influx_test.go b/core/unifi/uap_influx_test.go deleted file mode 100644 index 7f03f20f..00000000 --- a/core/unifi/uap_influx_test.go +++ /dev/null @@ -1,18 +0,0 @@ -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 5fa31fa6..a83657b7 100644 --- a/core/unifi/uap_type.go +++ b/core/unifi/uap_type.go @@ -294,9 +294,11 @@ type UAP struct { // UAPStat holds the "stat" data for an access point. // This is split out because of a JSON data format change from 5.10 to 5.11. type UAPStat struct { - *ap + *Ap } -type ap struct { + +// Ap is a subtype of UAPStat to make unmarshalling of different controller versions possible. +type Ap struct { SiteID string `json:"site_id"` O string `json:"o"` Oid string `json:"oid"` @@ -436,10 +438,10 @@ type ap struct { // UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Access Point Stat data. func (v *UAPStat) UnmarshalJSON(data []byte) error { var n struct { - ap `json:"ap"` + Ap `json:"ap"` } - v.ap = &n.ap - err := json.Unmarshal(data, v.ap) // controller version 5.10. + v.Ap = &n.Ap + err := json.Unmarshal(data, v.Ap) // controller version 5.10. if err != nil { return json.Unmarshal(data, &n) // controller version 5.11. } diff --git a/core/unifi/udm_influx.go b/core/unifi/udm_influx.go deleted file mode 100644 index 34ffc1ac..00000000 --- a/core/unifi/udm_influx.go +++ /dev/null @@ -1,333 +0,0 @@ -package unifi - -import ( - "time" - - influx "github.com/influxdata/influxdb1-client/v2" -) - -// Points generates Unifi Gateway datapoints for InfluxDB. -// These points can be passed directly to influx. -func (u *UDM) 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 *UDM) PointsAt(now time.Time) ([]*influx.Point, error) { - if u.Stat.gw == nil { - // Disabled devices lack stats. - u.Stat.gw = &gw{} - } - if u.Stat.sw == nil { - // Disabled devices lack stats. - u.Stat.sw = &sw{} - } - tags := map[string]string{ - "id": u.ID, - "mac": u.Mac, - "device_oid": u.Stat.gw.Oid, - "site_id": u.SiteID, - "site_name": u.SiteName, - "adopted": u.Adopted.Txt, - "name": u.Name, - "cfgversion": u.Cfgversion, - "config_network_ip": u.ConfigNetwork.IP, - "config_network_type": u.ConfigNetwork.Type, - "connect_request_ip": u.ConnectRequestIP, - "connect_request_port": u.ConnectRequestPort, - "device_id": u.DeviceID, - "guest_token": u.GuestToken, - "inform_ip": u.InformIP, - "known_cfgversion": u.KnownCfgversion, - "model": u.Model, - "serial": u.Serial, - "type": u.Type, - "usg_caps": u.UsgCaps.Txt, - "speedtest-status-saved": u.SpeedtestStatusSaved.Txt, - "wan1_up": u.Wan1.Up.Txt, - "wan2_up": u.Wan2.Up.Txt, - } - fields := map[string]interface{}{ - "ip": u.IP, - "bytes": u.Bytes.Val, - "last_seen": u.LastSeen.Val, - "license_state": u.LicenseState, - "fw_caps": u.FwCaps.Val, - "guest-num_sta": u.GuestNumSta.Val, - "rx_bytes": u.RxBytes.Val, - "tx_bytes": u.TxBytes.Val, - "uptime": u.Uptime.Val, - "state": u.State.Val, - "user-num_sta": u.UserNumSta.Val, - "version": u.Version, - "num_desktop": u.NumDesktop.Val, - "num_handheld": u.NumHandheld.Val, - "num_mobile": u.NumMobile.Val, - "speedtest-status_latency": u.SpeedtestStatus.Latency.Val, - "speedtest-status_rundate": u.SpeedtestStatus.Rundate.Val, - "speedtest-status_runtime": u.SpeedtestStatus.Runtime.Val, - "speedtest-status_download": u.SpeedtestStatus.StatusDownload.Val, - "speedtest-status_ping": u.SpeedtestStatus.StatusPing.Val, - "speedtest-status_summary": u.SpeedtestStatus.StatusSummary.Val, - "speedtest-status_upload": u.SpeedtestStatus.StatusUpload.Val, - "speedtest-status_xput_download": u.SpeedtestStatus.XputDownload.Val, - "speedtest-status_xput_upload": u.SpeedtestStatus.XputUpload.Val, - "config_network_wan_type": u.ConfigNetwork.Type, - "wan1_bytes-r": u.Wan1.BytesR.Val, - "wan1_enable": u.Wan1.Enable.Val, - "wan1_full_duplex": u.Wan1.FullDuplex.Val, - "wan1_gateway": u.Wan1.Gateway, - "wan1_ifname": u.Wan1.Ifname, - "wan1_ip": u.Wan1.IP, - "wan1_mac": u.Wan1.Mac, - "wan1_max_speed": u.Wan1.MaxSpeed.Val, - "wan1_name": u.Wan1.Name, - "wan1_netmask": u.Wan1.Netmask, - "wan1_rx_bytes": u.Wan1.RxBytes.Val, - "wan1_rx_bytes-r": u.Wan1.RxBytesR.Val, - "wan1_rx_dropped": u.Wan1.RxDropped.Val, - "wan1_rx_errors": u.Wan1.RxErrors.Val, - "wan1_rx_multicast": u.Wan1.RxMulticast.Val, - "wan1_rx_packets": u.Wan1.RxPackets.Val, - "wan1_type": u.Wan1.Type, - "wan1_speed": u.Wan1.Speed.Val, - "wan1_up": u.Wan1.Up.Val, - "wan1_tx_bytes": u.Wan1.TxBytes.Val, - "wan1_tx_bytes-r": u.Wan1.TxBytesR.Val, - "wan1_tx_dropped": u.Wan1.TxDropped.Val, - "wan1_tx_errors": u.Wan1.TxErrors.Val, - "wan1_tx_packets": u.Wan1.TxPackets.Val, - "wan2_bytes-r": u.Wan2.BytesR.Val, - "wan2_enable": u.Wan2.Enable.Val, - "wan2_full_duplex": u.Wan2.FullDuplex.Val, - "wan2_gateway": u.Wan2.Gateway, - "wan2_ifname": u.Wan2.Ifname, - "wan2_ip": u.Wan2.IP, - "wan2_mac": u.Wan2.Mac, - "wan2_max_speed": u.Wan2.MaxSpeed.Val, - "wan2_name": u.Wan2.Name, - "wan2_netmask": u.Wan2.Netmask, - "wan2_rx_bytes": u.Wan2.RxBytes.Val, - "wan2_rx_bytes-r": u.Wan2.RxBytesR.Val, - "wan2_rx_dropped": u.Wan2.RxDropped.Val, - "wan2_rx_errors": u.Wan2.RxErrors.Val, - "wan2_rx_multicast": u.Wan2.RxMulticast.Val, - "wan2_rx_packets": u.Wan2.RxPackets.Val, - "wan2_type": u.Wan2.Type, - "wan2_speed": u.Wan2.Speed.Val, - "wan2_up": u.Wan2.Up.Val, - "wan2_tx_bytes": u.Wan2.TxBytes.Val, - "wan2_tx_bytes-r": u.Wan2.TxBytesR.Val, - "wan2_tx_dropped": u.Wan2.TxDropped.Val, - "wan2_tx_errors": u.Wan2.TxErrors.Val, - "wan2_tx_packets": u.Wan2.TxPackets.Val, - "loadavg_1": u.SysStats.Loadavg1.Val, - "loadavg_5": u.SysStats.Loadavg5.Val, - "loadavg_15": u.SysStats.Loadavg15.Val, - "mem_used": u.SysStats.MemUsed.Val, - "mem_buffer": u.SysStats.MemBuffer.Val, - "mem_total": u.SysStats.MemTotal.Val, - "cpu": u.SystemStats.CPU.Val, - "mem": u.SystemStats.Mem.Val, - "system_uptime": u.SystemStats.Uptime.Val, - "gw": u.Stat.Gw, - "lan-rx_bytes": u.Stat.LanRxBytes.Val, - "lan-rx_packets": u.Stat.LanRxPackets.Val, - "lan-tx_bytes": u.Stat.LanTxBytes.Val, - "lan-tx_packets": u.Stat.LanTxPackets.Val, - "wan-rx_bytes": u.Stat.WanRxBytes.Val, - "wan-rx_dropped": u.Stat.WanRxDropped.Val, - "wan-rx_packets": u.Stat.WanRxPackets.Val, - "wan-tx_bytes": u.Stat.WanTxBytes.Val, - "wan-tx_packets": u.Stat.WanTxPackets.Val, - "uplink_name": u.Uplink.Name, - "uplink_latency": u.Uplink.Latency.Val, - "uplink_speed": u.Uplink.Speed.Val, - "uplink_num_ports": u.Uplink.NumPort.Val, - "uplink_max_speed": u.Uplink.MaxSpeed.Val, - } - pt, err := influx.NewPoint("usg", tags, fields, now) - if err != nil { - return nil, err - } - points := []*influx.Point{pt} - tags = map[string]string{ - "id": u.ID, - "mac": u.Mac, - "device_oid": u.Stat.sw.Oid, - "site_id": u.SiteID, - "site_name": u.SiteName, - "name": u.Name, - "adopted": u.Adopted.Txt, - "cfgversion": u.Cfgversion, - "config_network_ip": u.ConfigNetwork.IP, - "config_network_type": u.ConfigNetwork.Type, - "device_id": u.DeviceID, - "inform_ip": u.InformIP, - "known_cfgversion": u.KnownCfgversion, - "locating": u.Locating.Txt, - "model": u.Model, - "serial": u.Serial, - "type": u.Type, - "dot1x_portctrl_enabled": u.Dot1XPortctrlEnabled.Txt, - "flowctrl_enabled": u.FlowctrlEnabled.Txt, - "has_fan": u.HasFan.Txt, - "has_temperature": u.HasTemperature.Txt, - "jumboframe_enabled": u.JumboframeEnabled.Txt, - "stp_priority": u.StpPriority, - "stp_version": u.StpVersion, - } - fields = map[string]interface{}{ - "fw_caps": u.FwCaps.Val, - "guest-num_sta": u.GuestNumSta.Val, - "ip": u.IP, - "bytes": u.Bytes.Val, - "fan_level": float64(0), - "general_temperature": float64(0), - "last_seen": u.LastSeen.Val, - "license_state": u.LicenseState, - "overheating": u.Overheating.Val, - "rx_bytes": u.RxBytes.Val, - "tx_bytes": u.TxBytes.Val, - "uptime": u.Uptime.Val, - "state": u.State.Val, - "user-num_sta": u.UserNumSta.Val, - "version": u.Version, - "loadavg_1": u.SysStats.Loadavg1.Val, - "loadavg_5": u.SysStats.Loadavg5.Val, - "loadavg_15": u.SysStats.Loadavg15.Val, - "mem_buffer": u.SysStats.MemBuffer.Val, - "mem_used": u.SysStats.MemUsed.Val, - "mem_total": u.SysStats.MemTotal.Val, - "cpu": u.SystemStats.CPU.Val, - "mem": u.SystemStats.Mem.Val, - "system_uptime": u.SystemStats.Uptime.Val, - "stat_bytes": u.Stat.Bytes.Val, - "stat_rx_bytes": u.Stat.RxBytes.Val, - "stat_rx_crypts": u.Stat.RxCrypts.Val, - "stat_rx_dropped": u.Stat.RxDropped.Val, - "stat_rx_errors": u.Stat.RxErrors.Val, - "stat_rx_frags": u.Stat.RxFrags.Val, - "stat_rx_packets": u.Stat.TxPackets.Val, - "stat_tx_bytes": u.Stat.TxBytes.Val, - "stat_tx_dropped": u.Stat.TxDropped.Val, - "stat_tx_errors": u.Stat.TxErrors.Val, - "stat_tx_packets": u.Stat.TxPackets.Val, - "stat_tx_retries": u.Stat.TxRetries.Val, - "uplink_depth": "0", - } - pt, err = influx.NewPoint("usw", tags, fields, now) - if err != nil { - return nil, err - } - points = append(points, pt) - - for _, p := range u.NetworkTable { - tags := map[string]string{ - "device_name": u.Name, - "device_id": u.ID, - "device_mac": u.Mac, - "site_name": u.SiteName, - "up": p.Up.Txt, - "dhcpd_dns_enabled": p.DhcpdDNSEnabled.Txt, - "dhcpd_enabled": p.DhcpdEnabled.Txt, - "dhcpd_time_offset_enabled": p.DhcpdTimeOffsetEnabled.Txt, - "dhcp_relay_enabledy": p.DhcpRelayEnabled.Txt, - "dhcpd_gateway_enabled": p.DhcpdGatewayEnabled.Txt, - "enabled": p.Enabled.Txt, - "vlan_enabled": p.VlanEnabled.Txt, - "attr_no_delete": p.AttrNoDelete.Txt, - "is_guest": p.IsGuest.Txt, - "is_nat": p.IsNat.Txt, - "networkgroup": p.Networkgroup, - "site_id": p.SiteID, - } - fields := map[string]interface{}{ - "domain_name": p.DomainName, - "dhcpd_start": p.DhcpdStart, - "dhcpd_stop": p.DhcpdStop, - "ip": p.IP, - "ip_subnet": p.IPSubnet, - "mac": p.Mac, - "name": p.Name, - "num_sta": p.NumSta.Val, - "purpose": p.Purpose, - "rx_bytes": p.RxBytes.Val, - "rx_packets": p.RxPackets.Val, - "tx_bytes": p.TxBytes.Val, - "tx_packets": p.TxPackets.Val, - "ipv6_interface_type": p.Ipv6InterfaceType, - "attr_hidden_id": p.AttrHiddenID, - } - pt, err = influx.NewPoint("usg_networks", tags, fields, now) - if err != nil { - return points, err - } - points = append(points, pt) - } - - for _, p := range u.PortTable { - tags := map[string]string{ - "site_id": u.SiteID, - "site_name": u.SiteName, - "device_name": u.Name, - "name": p.Name, - "enable": p.Enable.Txt, - "is_uplink": p.IsUplink.Txt, - "up": p.Up.Txt, - "portconf_id": p.PortconfID, - "dot1x_mode": p.Dot1XMode, - "dot1x_status": p.Dot1XStatus, - "stp_state": p.StpState, - "sfp_found": p.SfpFound.Txt, - "op_mode": p.OpMode, - "poe_mode": p.PoeMode, - "port_poe": p.PortPoe.Txt, - "port_idx": p.PortIdx.Txt, - "port_id": u.Name + " Port " + p.PortIdx.Txt, - "poe_enable": p.PoeEnable.Txt, - "flowctrl_rx": p.FlowctrlRx.Txt, - "flowctrl_tx": p.FlowctrlTx.Txt, - "autoneg": p.Autoneg.Txt, - "full_duplex": p.FullDuplex.Txt, - "jumbo": p.Jumbo.Txt, - "masked": p.Masked.Txt, - "poe_good": p.PoeGood.Txt, - "media": p.Media, - "poe_class": p.PoeClass, - "poe_caps": p.PoeCaps.Txt, - "aggregated_by": p.AggregatedBy.Txt, - } - fields := map[string]interface{}{ - "dbytes_r": p.BytesR.Val, - "rx_broadcast": p.RxBroadcast.Val, - "rx_bytes": p.RxBytes.Val, - "rx_bytes-r": p.RxBytesR.Val, - "rx_dropped": p.RxDropped.Val, - "rx_errors": p.RxErrors.Val, - "rx_multicast": p.RxMulticast.Val, - "rx_packets": p.RxPackets.Val, - "speed": p.Speed.Val, - "stp_pathcost": p.StpPathcost.Val, - "tx_broadcast": p.TxBroadcast.Val, - "tx_bytes": p.TxBytes.Val, - "tx_bytes-r": p.TxBytesR.Val, - "tx_dropped": p.TxDropped.Val, - "tx_errors": p.TxErrors.Val, - "tx_multicast": p.TxMulticast.Val, - "tx_packets": p.TxPackets.Val, - "poe_current": p.PoeCurrent.Val, - "poe_power": p.PoePower.Val, - "poe_voltage": p.PoeVoltage.Val, - "full_duplex": p.FullDuplex.Val, - } - pt, err = influx.NewPoint("usw_ports", tags, fields, now) - if err != nil { - return points, err - } - points = append(points, pt) - } - return points, nil -} diff --git a/core/unifi/udm_type.go b/core/unifi/udm_type.go index 8d32027b..1ce60d30 100644 --- a/core/unifi/udm_type.go +++ b/core/unifi/udm_type.go @@ -180,6 +180,6 @@ type UDM struct { // UDMStat holds the "stat" data for a dream machine. // A dream machine is a USG + USW + Controller type UDMStat struct { - *gw - *sw + *Gw + *Sw } diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 0b376248..b682d6c3 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -12,7 +12,6 @@ import ( "fmt" "io" "io/ioutil" - "log" "net/http" "net/http/cookiejar" "strings" @@ -21,26 +20,31 @@ import ( // NewUnifi creates a http.Client with authenticated cookies. // Used to make additional, authenticated requests to the APIs. // Start here. -func NewUnifi(user, pass, url string, verifySSL bool) (*Unifi, error) { +func NewUnifi(config *Config) (*Unifi, error) { jar, err := cookiejar.New(nil) if err != nil { return nil, err } - u := &Unifi{baseURL: strings.TrimRight(url, "/"), + config.URL = strings.TrimRight(config.URL, "/") + u := &Unifi{Config: config, Client: &http.Client{ - Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !verifySSL}}, + Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !config.VerifySSL}}, Jar: jar, }, - ErrorLog: log.Printf, - DebugLog: DiscardLogs, } - return u, u.getController(user, pass) + if err := u.Login(); err != nil { + return u, err + } + if err := u.GetServerData(); err != nil { + return u, fmt.Errorf("unable to get server version: %v", err) + } + return u, nil } -// getController is a helper method to make testsing a bit easier. -func (u *Unifi) getController(user, pass string) error { +// Login is a helper method. It can be called to grab a new authentication cookie. +func (u *Unifi) Login() error { // magic login. - req, err := u.UniReq(LoginPath, fmt.Sprintf(`{"username":"%s","password":"%s"}`, user, pass)) + req, err := u.UniReq(LoginPath, fmt.Sprintf(`{"username":"%s","password":"%s"}`, u.User, u.Pass)) if err != nil { return err } @@ -54,16 +58,14 @@ func (u *Unifi) getController(user, pass string) error { }() if resp.StatusCode != http.StatusOK { return fmt.Errorf("authentication failed (user: %s): %s (status: %s)", - user, u.baseURL+LoginPath, resp.Status) - } - if err := u.getServer(); err != nil { - return fmt.Errorf("unable to get server version: %v", err) + u.User, u.URL+LoginPath, resp.Status) } return nil } -// getServer sets the controller's version and UUID. -func (u *Unifi) getServer() error { +// GetServerData sets the controller's version and UUID. Only call this if you +// previously called Login and suspect the controller version has changed. +func (u *Unifi) GetServerData() error { var response struct { Data server `json:"meta"` } @@ -148,7 +150,7 @@ func (u *Unifi) GetData(methodPath string, v interface{}) error { // And if you're doing that... sumbut a pull request with your new struct. :) // This is a helper method that is exposed for convenience. func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err error) { - switch path := u.baseURL + apiPath; { + switch path := u.URL + apiPath; { case params == "": req, err = http.NewRequest("GET", path, nil) default: diff --git a/core/unifi/unifi_test.go b/core/unifi/unifi_test.go index b399995d..0f3748b1 100644 --- a/core/unifi/unifi_test.go +++ b/core/unifi/unifi_test.go @@ -11,11 +11,17 @@ import ( func TestNewUnifi(t *testing.T) { t.Parallel() a := assert.New(t) - url := "http://127.0.0.1:64431" - authReq, err := NewUnifi("user1", "pass2", url, false) + u := "http://127.0.0.1:64431" + c := &Config{ + User: "user1", + Pass: "pass2", + URL: u, + VerifySSL: false, + } + authReq, err := NewUnifi(c) a.NotNil(err) - a.EqualValues(url, authReq.baseURL) - a.Contains(err.Error(), "connection refused", "an invalid destination should product a connection error.") + a.EqualValues(u, authReq.URL) + a.Contains(err.Error(), "connection refused", "an invalid destination should produce a connection error.") /* TODO: OPEN web server, check parameters posted, more. This test is incomplete. a.EqualValues(`{"username": "user1","password": "pass2"}`, string(post_params), "user/pass json parameters improperly encoded") @@ -25,30 +31,30 @@ func TestNewUnifi(t *testing.T) { func TestUniReq(t *testing.T) { t.Parallel() a := assert.New(t) - u := "/test/path" - url := "http://some.url:8443" + p := "/test/path" + u := "http://some.url:8443" // Test empty parameters. - authReq := &Unifi{Client: &http.Client{}, baseURL: url} - r, err := authReq.UniReq(u, "") + authReq := &Unifi{Client: &http.Client{}, Config: &Config{URL: u}} + r, err := authReq.UniReq(p, "") a.Nil(err, "newrequest must not produce an error") - a.EqualValues(u, r.URL.Path, + a.EqualValues(p, r.URL.Path, "the provided apiPath was not added to http request") - a.EqualValues(url, r.URL.Scheme+"://"+r.URL.Host, "URL improperly encoded") + a.EqualValues(u, r.URL.Scheme+"://"+r.URL.Host, "URL improperly encoded") a.EqualValues("GET", r.Method, "without parameters the method must be GET") a.EqualValues("application/json", r.Header.Get("Accept"), "Accept header must be set to application/json") // Test with parameters - p := "key1=value9&key2=value7" - authReq = &Unifi{Client: &http.Client{}, baseURL: "http://some.url:8443"} - r, err = authReq.UniReq(u, p) + k := "key1=value9&key2=value7" + authReq = &Unifi{Client: &http.Client{}, Config: &Config{URL: "http://some.url:8443"}} + r, err = authReq.UniReq(p, k) a.Nil(err, "newrequest must not produce an error") - a.EqualValues(u, r.URL.Path, + a.EqualValues(p, r.URL.Path, "the provided apiPath was not added to http request") - a.EqualValues(url, r.URL.Scheme+"://"+r.URL.Host, "URL improperly encoded") + a.EqualValues(u, r.URL.Scheme+"://"+r.URL.Host, "URL improperly encoded") a.EqualValues("POST", r.Method, "with parameters the method must be POST") a.EqualValues("application/json", r.Header.Get("Accept"), "Accept header must be set to application/json") // Check the parameters. d, err := ioutil.ReadAll(r.Body) a.Nil(err, "problem reading request body, POST parameters may be malformed") - a.EqualValues(p, string(d), "POST parameters improperly encoded") + a.EqualValues(k, string(d), "POST parameters improperly encoded") } diff --git a/core/unifi/usg_influx.go b/core/unifi/usg_influx.go deleted file mode 100644 index 11df9260..00000000 --- a/core/unifi/usg_influx.go +++ /dev/null @@ -1,238 +0,0 @@ -package unifi - -import ( - "strings" - "time" - - influx "github.com/influxdata/influxdb1-client/v2" -) - -// Points generates Unifi Gateway datapoints for InfluxDB. -// These points can be passed directly to influx. -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) { - if u.Stat.gw == nil { - // Disabled devices lack stats. - u.Stat.gw = &gw{} - } - tags := map[string]string{ - "id": u.ID, - "mac": u.Mac, - "device_type": u.Stat.O, - "device_oid": u.Stat.Oid, - "site_id": u.SiteID, - "site_name": u.SiteName, - "adopted": u.Adopted.Txt, - "name": u.Name, - "cfgversion": u.Cfgversion, - "config_network_ip": u.ConfigNetwork.IP, - "config_network_type": u.ConfigNetwork.Type, - "connect_request_ip": u.ConnectRequestIP, - "connect_request_port": u.ConnectRequestPort, - "device_id": u.DeviceID, - "guest_token": u.GuestToken, - "inform_ip": u.InformIP, - "known_cfgversion": u.KnownCfgversion, - "led_override": u.LedOverride, - "locating": u.Locating.Txt, - "model": u.Model, - "outdoor_mode_override": u.OutdoorModeOverride, - "serial": u.Serial, - "type": u.Type, - "usg_caps": u.UsgCaps.Txt, - "speedtest-status-saved": u.SpeedtestStatusSaved.Txt, - "wan1_up": u.Wan1.Up.Txt, - "wan2_up": u.Wan2.Up.Txt, - } - fields := map[string]interface{}{ - "ip": u.IP, - "bytes": u.Bytes.Val, - "last_seen": u.LastSeen.Val, - "license_state": u.LicenseState, - "fw_caps": u.FwCaps.Val, - "guest-num_sta": u.GuestNumSta.Val, - "rx_bytes": u.RxBytes.Val, - "tx_bytes": u.TxBytes.Val, - "uptime": u.Uptime.Val, - "roll_upgrade": u.Rollupgrade.Val, - "state": u.State.Val, - "upgradable": u.Upgradable.Val, - "user-num_sta": u.UserNumSta.Val, - "version": u.Version, - "num_desktop": u.NumDesktop.Val, - "num_handheld": u.NumHandheld.Val, - "num_mobile": u.NumMobile.Val, - "speedtest-status_latency": u.SpeedtestStatus.Latency.Val, - "speedtest-status_rundate": u.SpeedtestStatus.Rundate.Val, - "speedtest-status_runtime": u.SpeedtestStatus.Runtime.Val, - "speedtest-status_download": u.SpeedtestStatus.StatusDownload.Val, - "speedtest-status_ping": u.SpeedtestStatus.StatusPing.Val, - "speedtest-status_summary": u.SpeedtestStatus.StatusSummary.Val, - "speedtest-status_upload": u.SpeedtestStatus.StatusUpload.Val, - "speedtest-status_xput_download": u.SpeedtestStatus.XputDownload.Val, - "speedtest-status_xput_upload": u.SpeedtestStatus.XputUpload.Val, - "config_network_wan_type": u.ConfigNetwork.Type, - "wan1_bytes-r": u.Wan1.BytesR.Val, - "wan1_enable": u.Wan1.Enable.Val, - "wan1_full_duplex": u.Wan1.FullDuplex.Val, - "wan1_gateway": u.Wan1.Gateway, - "wan1_ifname": u.Wan1.Ifname, - "wan1_ip": u.Wan1.IP, - "wan1_mac": u.Wan1.Mac, - "wan1_max_speed": u.Wan1.MaxSpeed.Val, - "wan1_name": u.Wan1.Name, - "wan1_netmask": u.Wan1.Netmask, - "wan1_rx_bytes": u.Wan1.RxBytes.Val, - "wan1_rx_bytes-r": u.Wan1.RxBytesR.Val, - "wan1_rx_dropped": u.Wan1.RxDropped.Val, - "wan1_rx_errors": u.Wan1.RxErrors.Val, - "wan1_rx_multicast": u.Wan1.RxMulticast.Val, - "wan1_rx_packets": u.Wan1.RxPackets.Val, - "wan1_type": u.Wan1.Type, - "wan1_speed": u.Wan1.Speed.Val, - "wan1_up": u.Wan1.Up.Val, - "wan1_tx_bytes": u.Wan1.TxBytes.Val, - "wan1_tx_bytes-r": u.Wan1.TxBytesR.Val, - "wan1_tx_dropped": u.Wan1.TxDropped.Val, - "wan1_tx_errors": u.Wan1.TxErrors.Val, - "wan1_tx_packets": u.Wan1.TxPackets.Val, - "wan2_bytes-r": u.Wan2.BytesR.Val, - "wan2_enable": u.Wan2.Enable.Val, - "wan2_full_duplex": u.Wan2.FullDuplex.Val, - "wan2_gateway": u.Wan2.Gateway, - "wan2_ifname": u.Wan2.Ifname, - "wan2_ip": u.Wan2.IP, - "wan2_mac": u.Wan2.Mac, - "wan2_max_speed": u.Wan2.MaxSpeed.Val, - "wan2_name": u.Wan2.Name, - "wan2_netmask": u.Wan2.Netmask, - "wan2_rx_bytes": u.Wan2.RxBytes.Val, - "wan2_rx_bytes-r": u.Wan2.RxBytesR.Val, - "wan2_rx_dropped": u.Wan2.RxDropped.Val, - "wan2_rx_errors": u.Wan2.RxErrors.Val, - "wan2_rx_multicast": u.Wan2.RxMulticast.Val, - "wan2_rx_packets": u.Wan2.RxPackets.Val, - "wan2_type": u.Wan2.Type, - "wan2_speed": u.Wan2.Speed.Val, - "wan2_up": u.Wan2.Up.Val, - "wan2_tx_bytes": u.Wan2.TxBytes.Val, - "wan2_tx_bytes-r": u.Wan2.TxBytesR.Val, - "wan2_tx_dropped": u.Wan2.TxDropped.Val, - "wan2_tx_errors": u.Wan2.TxErrors.Val, - "wan2_tx_packets": u.Wan2.TxPackets.Val, - "loadavg_1": u.SysStats.Loadavg1.Val, - "loadavg_5": u.SysStats.Loadavg5.Val, - "loadavg_15": u.SysStats.Loadavg15.Val, - "mem_used": u.SysStats.MemUsed.Val, - "mem_buffer": u.SysStats.MemBuffer.Val, - "mem_total": u.SysStats.MemTotal.Val, - "cpu": u.SystemStats.CPU.Val, - "mem": u.SystemStats.Mem.Val, - "system_uptime": u.SystemStats.Uptime.Val, - "stat_duration": u.Stat.Duration.Val, - "stat_datetime": u.Stat.Datetime, - "gw": u.Stat.Gw, - "lan-rx_bytes": u.Stat.LanRxBytes.Val, - "lan-rx_packets": u.Stat.LanRxPackets.Val, - "lan-tx_bytes": u.Stat.LanTxBytes.Val, - "lan-tx_packets": u.Stat.LanTxPackets.Val, - "wan-rx_bytes": u.Stat.WanRxBytes.Val, - "wan-rx_dropped": u.Stat.WanRxDropped.Val, - "wan-rx_packets": u.Stat.WanRxPackets.Val, - "wan-tx_bytes": u.Stat.WanTxBytes.Val, - "wan-tx_packets": u.Stat.WanTxPackets.Val, - "uplink_name": u.Uplink.Name, - "uplink_latency": u.Uplink.Latency.Val, - "uplink_speed": u.Uplink.Speed.Val, - "uplink_num_ports": u.Uplink.NumPort.Val, - "uplink_max_speed": u.Uplink.MaxSpeed.Val, - } - pt, err := influx.NewPoint("usg", tags, fields, now) - if err != nil { - return nil, err - } - points := []*influx.Point{pt} - for _, p := range u.NetworkTable { - tags := map[string]string{ - "device_name": u.Name, - "device_id": u.ID, - "device_mac": u.Mac, - "site_name": u.SiteName, - "up": p.Up.Txt, - "dhcpd_dns_enabled": p.DhcpdDNSEnabled.Txt, - "dhcpd_enabled": p.DhcpdEnabled.Txt, - "dhcpd_time_offset_enabled": p.DhcpdTimeOffsetEnabled.Txt, - "dhcp_relay_enabledy": p.DhcpRelayEnabled.Txt, - "dhcpd_gateway_enabled": p.DhcpdGatewayEnabled.Txt, - "enabled": p.Enabled.Txt, - "vlan_enabled": p.VlanEnabled.Txt, - "attr_no_delete": p.AttrNoDelete.Txt, - "is_guest": p.IsGuest.Txt, - "is_nat": p.IsNat.Txt, - "networkgroup": p.Networkgroup, - "site_id": p.SiteID, - } - fields := map[string]interface{}{ - "domain_name": p.DomainName, - "dhcpd_start": p.DhcpdStart, - "dhcpd_stop": p.DhcpdStop, - "ip": p.IP, - "ip_subnet": p.IPSubnet, - "mac": p.Mac, - "name": p.Name, - "num_sta": p.NumSta.Val, - "purpose": p.Purpose, - "rx_bytes": p.RxBytes.Val, - "rx_packets": p.RxPackets.Val, - "tx_bytes": p.TxBytes.Val, - "tx_packets": p.TxPackets.Val, - "ipv6_interface_type": p.Ipv6InterfaceType, - "attr_hidden_id": p.AttrHiddenID, - } - pt, err = influx.NewPoint("usg_networks", tags, fields, now) - if err != nil { - return points, err - } - points = append(points, pt) - } - for _, p := range u.PortTable { - tags := map[string]string{ - "device_name": u.Name, - "device_id": u.ID, - "device_mac": u.Mac, - "site_name": u.SiteName, - "name": p.Name, - "ifname": p.Ifname, - "ip": p.IP, - "mac": p.Mac, - "up": p.Up.Txt, - "speed": p.Speed.Txt, - "full_duplex": p.FullDuplex.Txt, - "enable": p.Enable.Txt, - } - fields := map[string]interface{}{ - "rx_bytes": p.RxBytes.Val, - "rx_dropped": p.RxDropped.Val, - "rx_errors": p.RxErrors.Val, - "rx_packets": p.RxBytes.Val, - "tx_bytes": p.TxBytes.Val, - "tx_dropped": p.TxDropped.Val, - "tx_errors": p.TxErrors.Val, - "tx_packets": p.TxPackets.Val, - "rx_multicast": p.RxMulticast.Val, - "dns_servers": strings.Join(p.DNS, ","), - } - pt, err = influx.NewPoint("usg_ports", tags, fields, now) - if err != nil { - return points, err - } - points = append(points, pt) - } - return points, nil -} diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index c92bd426..5db8db43 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -249,10 +249,11 @@ type SysStats struct { // USGStat holds the "stat" data for a gateway. // This is split out because of a JSON data format change from 5.10 to 5.11. type USGStat struct { - *gw + *Gw } -type gw struct { +// Gw is a subtype of USGStat to make unmarshalling of different controller versions possible. +type Gw struct { SiteID string `json:"site_id"` O string `json:"o"` Oid string `json:"oid"` @@ -276,10 +277,10 @@ type gw struct { // UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Gateway Stat data. func (v *USGStat) UnmarshalJSON(data []byte) error { var n struct { - gw `json:"gw"` + Gw `json:"gw"` } - v.gw = &n.gw - err := json.Unmarshal(data, v.gw) // controller version 5.10. + v.Gw = &n.Gw + err := json.Unmarshal(data, v.Gw) // controller version 5.10. if err != nil { return json.Unmarshal(data, &n) // controller version 5.11. } diff --git a/core/unifi/usw_influx.go b/core/unifi/usw_influx.go deleted file mode 100644 index 0797783a..00000000 --- a/core/unifi/usw_influx.go +++ /dev/null @@ -1,155 +0,0 @@ -package unifi - -import ( - "time" - - influx "github.com/influxdata/influxdb1-client/v2" -) - -// Points generates Unifi Switch datapoints for InfluxDB. -// These points can be passed directly to influx. -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) { - if u.Stat.sw == nil { - // Disabled devices lack stats. - u.Stat.sw = &sw{} - } - tags := map[string]string{ - "id": u.ID, - "mac": u.Mac, - "device_oid": u.Stat.Oid, - "site_id": u.SiteID, - "site_name": u.SiteName, - "name": u.Name, - "adopted": u.Adopted.Txt, - "cfgversion": u.Cfgversion, - "config_network_ip": u.ConfigNetwork.IP, - "config_network_type": u.ConfigNetwork.Type, - "device_id": u.DeviceID, - "inform_ip": u.InformIP, - "known_cfgversion": u.KnownCfgversion, - "locating": u.Locating.Txt, - "model": u.Model, - "serial": u.Serial, - "type": u.Type, - "dot1x_portctrl_enabled": u.Dot1XPortctrlEnabled.Txt, - "flowctrl_enabled": u.FlowctrlEnabled.Txt, - "has_fan": u.HasFan.Txt, - "has_temperature": u.HasTemperature.Txt, - "jumboframe_enabled": u.JumboframeEnabled.Txt, - "stp_priority": u.StpPriority, - "stp_version": u.StpVersion, - } - fields := map[string]interface{}{ - "fw_caps": u.FwCaps.Val, - "guest-num_sta": u.GuestNumSta.Val, - "ip": u.IP, - "bytes": u.Bytes.Val, - "fan_level": u.FanLevel.Val, - "general_temperature": u.GeneralTemperature.Val, - "last_seen": u.LastSeen.Val, - "license_state": u.LicenseState, - "overheating": u.Overheating.Val, - "rx_bytes": u.RxBytes.Val, - "tx_bytes": u.TxBytes.Val, - "uptime": u.Uptime.Val, - "state": u.State.Val, - "user-num_sta": u.UserNumSta.Val, - "version": u.Version, - "loadavg_1": u.SysStats.Loadavg1.Val, - "loadavg_5": u.SysStats.Loadavg5.Val, - "loadavg_15": u.SysStats.Loadavg15.Val, - "mem_buffer": u.SysStats.MemBuffer.Val, - "mem_used": u.SysStats.MemUsed.Val, - "mem_total": u.SysStats.MemTotal.Val, - "cpu": u.SystemStats.CPU.Val, - "mem": u.SystemStats.Mem.Val, - "system_uptime": u.SystemStats.Uptime.Val, - "stat_bytes": u.Stat.Bytes.Val, - "stat_rx_bytes": u.Stat.RxBytes.Val, - "stat_rx_crypts": u.Stat.RxCrypts.Val, - "stat_rx_dropped": u.Stat.RxDropped.Val, - "stat_rx_errors": u.Stat.RxErrors.Val, - "stat_rx_frags": u.Stat.RxFrags.Val, - "stat_rx_packets": u.Stat.TxPackets.Val, - "stat_tx_bytes": u.Stat.TxBytes.Val, - "stat_tx_dropped": u.Stat.TxDropped.Val, - "stat_tx_errors": u.Stat.TxErrors.Val, - "stat_tx_packets": u.Stat.TxPackets.Val, - "stat_tx_retries": u.Stat.TxRetries.Val, - "uplink_depth": u.UplinkDepth.Txt, - } - pt, err := influx.NewPoint("usw", tags, fields, now) - if err != nil { - return nil, err - } - points := []*influx.Point{pt} - for _, p := range u.PortTable { - tags := map[string]string{ - "site_id": u.SiteID, - "site_name": u.SiteName, - "device_name": u.Name, - "name": p.Name, - "enable": p.Enable.Txt, - "is_uplink": p.IsUplink.Txt, - "up": p.Up.Txt, - "portconf_id": p.PortconfID, - "dot1x_mode": p.Dot1XMode, - "dot1x_status": p.Dot1XStatus, - "stp_state": p.StpState, - "sfp_found": p.SfpFound.Txt, - "op_mode": p.OpMode, - "poe_mode": p.PoeMode, - "port_poe": p.PortPoe.Txt, - "port_idx": p.PortIdx.Txt, - "port_id": u.Name + " Port " + p.PortIdx.Txt, - "poe_enable": p.PoeEnable.Txt, - "flowctrl_rx": p.FlowctrlRx.Txt, - "flowctrl_tx": p.FlowctrlTx.Txt, - "autoneg": p.Autoneg.Txt, - "full_duplex": p.FullDuplex.Txt, - "jumbo": p.Jumbo.Txt, - "masked": p.Masked.Txt, - "poe_good": p.PoeGood.Txt, - "media": p.Media, - "poe_class": p.PoeClass, - "poe_caps": p.PoeCaps.Txt, - "aggregated_by": p.AggregatedBy.Txt, - } - fields := map[string]interface{}{ - "dbytes_r": p.BytesR.Val, - "rx_broadcast": p.RxBroadcast.Val, - "rx_bytes": p.RxBytes.Val, - "rx_bytes-r": p.RxBytesR.Val, - "rx_dropped": p.RxDropped.Val, - "rx_errors": p.RxErrors.Val, - "rx_multicast": p.RxMulticast.Val, - "rx_packets": p.RxPackets.Val, - "speed": p.Speed.Val, - "stp_pathcost": p.StpPathcost.Val, - "tx_broadcast": p.TxBroadcast.Val, - "tx_bytes": p.TxBytes.Val, - "tx_bytes-r": p.TxBytesR.Val, - "tx_dropped": p.TxDropped.Val, - "tx_errors": p.TxErrors.Val, - "tx_multicast": p.TxMulticast.Val, - "tx_packets": p.TxPackets.Val, - "poe_current": p.PoeCurrent.Val, - "poe_power": p.PoePower.Val, - "poe_voltage": p.PoeVoltage.Val, - "full_duplex": p.FullDuplex.Val, - } - pt, err = influx.NewPoint("usw_ports", tags, fields, now) - if err != nil { - return points, err - } - points = append(points, pt) - } - return points, nil -} diff --git a/core/unifi/usw_type.go b/core/unifi/usw_type.go index a6c94d25..47516d43 100644 --- a/core/unifi/usw_type.go +++ b/core/unifi/usw_type.go @@ -160,10 +160,11 @@ type Port struct { // USWStat holds the "stat" data for a switch. // This is split out because of a JSON data format change from 5.10 to 5.11. type USWStat struct { - *sw + *Sw } -type sw struct { +// GS is a subtype of USWStat to make unmarshalling of different controller versions possible. +type Sw struct { SiteID string `json:"site_id"` O string `json:"o"` Oid string `json:"oid"` @@ -358,10 +359,10 @@ type sw struct { // UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Switch Stat data. func (v *USWStat) UnmarshalJSON(data []byte) error { var n struct { - sw `json:"sw"` + Sw `json:"sw"` } - v.sw = &n.sw - err := json.Unmarshal(data, v.sw) // controller version 5.10. + v.Sw = &n.Sw + err := json.Unmarshal(data, v.Sw) // controller version 5.10. if err != nil { return json.Unmarshal(data, &n) // controller version 5.11. } From 976bc9f72c3e7dfbb1c32cdbd7e89ccad3127d3d Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 25 Aug 2019 03:23:36 -0700 Subject: [PATCH 095/194] fix these --- core/unifi/unifi.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index b682d6c3..b9ba0b8a 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -25,6 +25,12 @@ func NewUnifi(config *Config) (*Unifi, error) { if err != nil { return nil, err } + if config.ErrorLog == nil { + config.ErrorLog = DiscardLogs + } + if config.DebugLog == nil { + config.DebugLog = DiscardLogs + } config.URL = strings.TrimRight(config.URL, "/") u := &Unifi{Config: config, Client: &http.Client{ From 6de7c4cae5a595b88d392a171774d228ce7081a0 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 25 Aug 2019 03:29:26 -0700 Subject: [PATCH 096/194] Update readme --- core/unifi/README.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/core/unifi/README.md b/core/unifi/README.md index edc355f6..e3570381 100644 --- a/core/unifi/README.md +++ b/core/unifi/README.md @@ -5,9 +5,6 @@ an authenticated http Client you may use to query the device for data. Also contains some built-in methods for de-serializing common client and device data. The data is provided in a large struct you can consume in your application. -This library also contains methods to export the Unifi data in InfluxDB format, -and this can be used as an example to base your own metrics collection methods. - If more features are requested, I'll certainly consider them. Do you need to do more than just collect data? [Let me know](https://github.com/golift/unifi/issues/new)! Pull requests and feedback are welcomed! @@ -20,16 +17,18 @@ import "log" import "golift.io/unifi" func main() { - username := "admin" - password := "superSecret1234" - URL := "https://127.0.0.1:8443/" - uni, err := unifi.NewUnifi(username, password, URL, false) + c := *unifi.Config{ + User: "admin", + Pass: "superSecret1234", + URL: "https://127.0.0.1:8443/", + // Log with log.Printf or make your own interface that accepts (msg, fmt) + ErrorLog: log.Printf, + DebugLog: log.Printf, + } + uni, err := unifi.NewUnifi(c) if err != nil { log.Fatalln("Error:", err) } - // Log with log.Printf or make your own interface that accepts (msg, fmt) - uni.ErrorLog = log.Printf - uni.DebugLog = log.Printf sites, err := uni.GetSites() if err != nil { From 7f4245de59c0c64b222b5604fff4c5fcb1a2bd70 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Tue, 27 Aug 2019 21:08:22 -0700 Subject: [PATCH 097/194] UDM fix. --- core/unifi/udm_type.go | 4 ++-- core/unifi/usw_type.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/unifi/udm_type.go b/core/unifi/udm_type.go index 1ce60d30..5d4b1858 100644 --- a/core/unifi/udm_type.go +++ b/core/unifi/udm_type.go @@ -180,6 +180,6 @@ type UDM struct { // UDMStat holds the "stat" data for a dream machine. // A dream machine is a USG + USW + Controller type UDMStat struct { - *Gw - *Sw + *Gw `json:"gw"` + *Sw `json:"sw"` } diff --git a/core/unifi/usw_type.go b/core/unifi/usw_type.go index 47516d43..04b4c070 100644 --- a/core/unifi/usw_type.go +++ b/core/unifi/usw_type.go @@ -163,7 +163,7 @@ type USWStat struct { *Sw } -// GS is a subtype of USWStat to make unmarshalling of different controller versions possible. +// Sw is a subtype of USWStat to make unmarshalling of different controller versions possible. type Sw struct { SiteID string `json:"site_id"` O string `json:"o"` From c0c9e4825ee8c37c7d7f6e8663eb17b9cc2979c1 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Wed, 28 Aug 2019 12:16:24 -0700 Subject: [PATCH 098/194] Actually make UDM work.... --- core/unifi/udm_type.go | 2 +- core/unifi/unifi.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/unifi/udm_type.go b/core/unifi/udm_type.go index 5d4b1858..e7a21c39 100644 --- a/core/unifi/udm_type.go +++ b/core/unifi/udm_type.go @@ -12,7 +12,7 @@ type UDM struct { Uptime FlexInt `json:"uptime"` Model string `json:"model"` Version string `json:"version"` - Name string `json:"hostname"` + Name string `json:"name"` Default FlexBool `json:"default"` Locating FlexBool `json:"locating"` Type string `json:"type"` diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index b9ba0b8a..c30c4510 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -118,6 +118,7 @@ func (u *Unifi) GetDevices(sites Sites) (*Devices, error) { devices.UAPs = append(devices.UAPs, loopDevices.UAPs...) devices.USGs = append(devices.USGs, loopDevices.USGs...) devices.USWs = append(devices.USWs, loopDevices.USWs...) + devices.UDMs = append(devices.UDMs, loopDevices.UDMs...) } return devices, nil } From 06ae401e53a7103f804dd86d4ae6389ce5a3238e Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Mon, 2 Sep 2019 23:58:27 -0700 Subject: [PATCH 099/194] Re-do structs to support UDM w/ UAP. --- core/unifi/.travis.yml | 2 +- core/unifi/{clients_type.go => clients.go} | 0 core/unifi/{site_type.go => site.go} | 0 core/unifi/uap.go | 564 +++++++++++++++++++ core/unifi/{uap_type_test.go => uap_test.go} | 0 core/unifi/uap_type.go | 449 --------------- core/unifi/udm.go | 208 +++++++ core/unifi/udm_type.go | 185 ------ core/unifi/{usg_type.go => usg.go} | 64 +-- core/unifi/{usg_type_test.go => usg_test.go} | 0 core/unifi/usw.go | 373 ++++++++++++ core/unifi/{usw_type_test.go => usw_test.go} | 0 core/unifi/usw_type.go | 370 ------------ 13 files changed, 1158 insertions(+), 1057 deletions(-) rename core/unifi/{clients_type.go => clients.go} (100%) rename core/unifi/{site_type.go => site.go} (100%) create mode 100644 core/unifi/uap.go rename core/unifi/{uap_type_test.go => uap_test.go} (100%) delete mode 100644 core/unifi/uap_type.go create mode 100644 core/unifi/udm.go delete mode 100644 core/unifi/udm_type.go rename core/unifi/{usg_type.go => usg.go} (77%) rename core/unifi/{usg_type_test.go => usg_test.go} (100%) create mode 100644 core/unifi/usw.go rename core/unifi/{usw_type_test.go => usw_test.go} (100%) delete mode 100644 core/unifi/usw_type.go diff --git a/core/unifi/.travis.yml b/core/unifi/.travis.yml index 5266b77c..a05c4c9f 100644 --- a/core/unifi/.travis.yml +++ b/core/unifi/.travis.yml @@ -11,5 +11,5 @@ before_install: install: - dep ensure script: -- golangci-lint run --enable-all -e G402 -e dupl +- golangci-lint run --enable-all -e G402 - go test ./... diff --git a/core/unifi/clients_type.go b/core/unifi/clients.go similarity index 100% rename from core/unifi/clients_type.go rename to core/unifi/clients.go diff --git a/core/unifi/site_type.go b/core/unifi/site.go similarity index 100% rename from core/unifi/site_type.go rename to core/unifi/site.go diff --git a/core/unifi/uap.go b/core/unifi/uap.go new file mode 100644 index 00000000..d94b60e4 --- /dev/null +++ b/core/unifi/uap.go @@ -0,0 +1,564 @@ +package unifi + +import ( + "encoding/json" + "time" +) + +// UAP represents all the data from the Ubiquiti 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. + */ + ID string `json:"_id"` + Adopted FlexBool `json:"adopted"` + AntennaTable []struct { + Default FlexBool `json:"default"` + ID FlexInt `json:"id"` + Name string `json:"name"` + Wifi0Gain FlexInt `json:"wifi0_gain"` + Wifi1Gain FlexInt `json:"wifi1_gain"` + } `json:"antenna_table"` + BandsteeringMode string `json:"bandsteering_mode,omitempty"` + BoardRev int `json:"board_rev"` + Cfgversion string `json:"cfgversion"` + ConfigNetwork struct { + Type string `json:"type"` + IP string `json:"ip"` + } `json:"config_network"` + CountrycodeTable []int `json:"countrycode_table"` + EthernetTable []struct { + Mac string `json:"mac"` + NumPort FlexInt `json:"num_port"` + Name string `json:"name"` + } `json:"ethernet_table"` + FwCaps int `json:"fw_caps"` + HasEth1 FlexBool `json:"has_eth1"` + HasSpeaker FlexBool `json:"has_speaker"` + InformIP string `json:"inform_ip"` + InformURL string `json:"inform_url"` + IP string `json:"ip"` + LedOverride string `json:"led_override"` + Mac string `json:"mac"` + MeshStaVapEnabled FlexBool `json:"mesh_sta_vap_enabled"` + Model string `json:"model"` + Name string `json:"name"` + OutdoorModeOverride string `json:"outdoor_mode_override"` + PortTable []Port `json:"port_table"` + RadioTable RadioTable `json:"radio_table"` + ScanRadioTable []interface{} `json:"scan_radio_table"` + Serial string `json:"serial"` + SiteID string `json:"site_id"` + SiteName string `json:"-"` + Type string `json:"type"` + Version string `json:"version"` + VwireTable []interface{} `json:"vwire_table"` + WifiCaps int `json:"wifi_caps"` + WlangroupIDNa string `json:"wlangroup_id_na"` + WlangroupIDNg string `json:"wlangroup_id_ng"` + RequiredVersion string `json:"required_version"` + HwCaps int `json:"hw_caps"` + Unsupported FlexBool `json:"unsupported"` + UnsupportedReason FlexInt `json:"unsupported_reason"` + SysErrorCaps int `json:"sys_error_caps"` + HasFan FlexBool `json:"has_fan"` + HasTemperature FlexBool `json:"has_temperature"` + DeviceID string `json:"device_id"` + State int `json:"state"` + LastSeen FlexInt `json:"last_seen"` + Upgradable FlexBool `json:"upgradable"` + AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` + Rollupgrade FlexBool `json:"rollupgrade"` + KnownCfgversion string `json:"known_cfgversion"` + Uptime FlexInt `json:"uptime"` + UUptime FlexInt `json:"_uptime"` + Locating FlexBool `json:"locating"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + SysStats SysStats `json:"sys_stats"` + SystemStats SystemStats `json:"system-stats"` + SSHSessionTable []interface{} `json:"ssh_session_table"` + Scanning FlexBool `json:"scanning"` + SpectrumScanning FlexBool `json:"spectrum_scanning"` + GuestToken string `json:"guest_token"` + Meshv3PeerMac string `json:"meshv3_peer_mac"` + Satisfaction FlexInt `json:"satisfaction"` + Isolated FlexBool `json:"isolated"` + RadioTableStats RadioTableStats `json:"radio_table_stats"` + Uplink struct { + FullDuplex FlexBool `json:"full_duplex"` + IP string `json:"ip"` + Mac string `json:"mac"` + MaxVlan int `json:"max_vlan"` + Name string `json:"name"` + Netmask string `json:"netmask"` + NumPort int `json:"num_port"` + RxBytes FlexInt `json:"rx_bytes"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxMulticast FlexInt `json:"rx_multicast"` + RxPackets FlexInt `json:"rx_packets"` + Speed FlexInt `json:"speed"` + TxBytes FlexInt `json:"tx_bytes"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxPackets FlexInt `json:"tx_packets"` + Up FlexBool `json:"up"` + MaxSpeed FlexInt `json:"max_speed"` + Type string `json:"type"` + TxBytesR FlexInt `json:"tx_bytes-r"` + RxBytesR FlexInt `json:"rx_bytes-r"` + UplinkMac string `json:"uplink_mac"` + UplinkRemotePort int `json:"uplink_remote_port"` + } `json:"uplink"` + VapTable VapTable `json:"vap_table"` + DownlinkTable []struct { + PortIdx int `json:"port_idx"` + Speed int `json:"speed"` + FullDuplex bool `json:"full_duplex"` + Mac string `json:"mac"` + } `json:"downlink_table,omitempty"` + VwireVapTable []interface{} `json:"vwire_vap_table"` + BytesD FlexInt `json:"bytes-d"` + TxBytesD FlexInt `json:"tx_bytes-d"` + RxBytesD FlexInt `json:"rx_bytes-d"` + BytesR FlexInt `json:"bytes-r"` + LastUplink struct { + UplinkMac string `json:"uplink_mac"` + UplinkRemotePort int `json:"uplink_remote_port"` + } `json:"last_uplink"` + Stat UAPStat `json:"stat"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + VwireEnabled FlexBool `json:"vwireEnabled"` + UplinkTable []interface{} `json:"uplink_table"` + NumSta int `json:"num_sta"` + UserNumSta int `json:"user-num_sta"` + GuestNumSta int `json:"guest-num_sta"` + TwoPhaseAdopt FlexBool `json:"two_phase_adopt,omitempty"` +} + +// UAPStat holds the "stat" data for an access point. +// This is split out because of a JSON data format change from 5.10 to 5.11. +type UAPStat struct { + *Ap +} + +// Ap is a subtype of UAPStat to make unmarshalling of different controller versions possible. +type Ap struct { + SiteID string `json:"site_id"` + O string `json:"o"` + Oid string `json:"oid"` + Ap string `json:"ap"` + Time FlexInt `json:"time"` + Datetime time.Time `json:"datetime"` + Bytes FlexInt `json:"bytes"` + Duration FlexInt `json:"duration"` + WifiTxDropped FlexInt `json:"wifi_tx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxDropped FlexInt `json:"rx_dropped"` + RxFrags FlexInt `json:"rx_frags"` + RxCrypts FlexInt `json:"rx_crypts"` + TxPackets FlexInt `json:"tx_packets"` + TxBytes FlexInt `json:"tx_bytes"` + TxErrors FlexInt `json:"tx_errors"` + TxDropped FlexInt `json:"tx_dropped"` + TxRetries FlexInt `json:"tx_retries"` + RxPackets FlexInt `json:"rx_packets"` + RxBytes FlexInt `json:"rx_bytes"` + UserRxDropped FlexInt `json:"user-rx_dropped"` + GuestRxDropped FlexInt `json:"guest-rx_dropped"` + UserRxErrors FlexInt `json:"user-rx_errors"` + GuestRxErrors FlexInt `json:"guest-rx_errors"` + UserRxPackets FlexInt `json:"user-rx_packets"` + GuestRxPackets FlexInt `json:"guest-rx_packets"` + UserRxBytes FlexInt `json:"user-rx_bytes"` + GuestRxBytes FlexInt `json:"guest-rx_bytes"` + UserRxCrypts FlexInt `json:"user-rx_crypts"` + GuestRxCrypts FlexInt `json:"guest-rx_crypts"` + UserRxFrags FlexInt `json:"user-rx_frags"` + GuestRxFrags FlexInt `json:"guest-rx_frags"` + UserTxPackets FlexInt `json:"user-tx_packets"` + GuestTxPackets FlexInt `json:"guest-tx_packets"` + UserTxBytes FlexInt `json:"user-tx_bytes"` + GuestTxBytes FlexInt `json:"guest-tx_bytes"` + UserTxErrors FlexInt `json:"user-tx_errors"` + GuestTxErrors FlexInt `json:"guest-tx_errors"` + UserTxDropped FlexInt `json:"user-tx_dropped"` + GuestTxDropped FlexInt `json:"guest-tx_dropped"` + UserTxRetries FlexInt `json:"user-tx_retries"` + GuestTxRetries FlexInt `json:"guest-tx_retries"` + MacFilterRejections FlexInt `json:"mac_filter_rejections"` + UserMacFilterRejections FlexInt `json:"user-mac_filter_rejections"` + GuestMacFilterRejections FlexInt `json:"guest-mac_filter_rejections"` + WifiTxAttempts FlexInt `json:"wifi_tx_attempts"` + UserWifiTxDropped FlexInt `json:"user-wifi_tx_dropped"` + GuestWifiTxDropped FlexInt `json:"guest-wifi_tx_dropped"` + UserWifiTxAttempts FlexInt `json:"user-wifi_tx_attempts"` + GuestWifiTxAttempts FlexInt `json:"guest-wifi_tx_attempts"` + + // UAP-AC-PRO names, others may differ. + /* These are all in VAP TABLE */ + /* + GuestWifi0RxPackets FlexInt `json:"guest-wifi0-rx_packets"` + GuestWifi1RxPackets FlexInt `json:"guest-wifi1-rx_packets"` + UserWifi1RxPackets FlexInt `json:"user-wifi1-rx_packets"` + UserWifi0RxPackets FlexInt `json:"user-wifi0-rx_packets"` + Wifi0RxPackets FlexInt `json:"wifi0-rx_packets"` + Wifi1RxPackets FlexInt `json:"wifi1-rx_packets"` + GuestWifi0RxBytes FlexInt `json:"guest-wifi0-rx_bytes"` + GuestWifi1RxBytes FlexInt `json:"guest-wifi1-rx_bytes"` + UserWifi1RxBytes FlexInt `json:"user-wifi1-rx_bytes"` + UserWifi0RxBytes FlexInt `json:"user-wifi0-rx_bytes"` + Wifi0RxBytes FlexInt `json:"wifi0-rx_bytes"` + Wifi1RxBytes FlexInt `json:"wifi1-rx_bytes"` + GuestWifi0RxErrors FlexInt `json:"guest-wifi0-rx_errors"` + GuestWifi1RxErrors FlexInt `json:"guest-wifi1-rx_errors"` + UserWifi1RxErrors FlexInt `json:"user-wifi1-rx_errors"` + UserWifi0RxErrors FlexInt `json:"user-wifi0-rx_errors"` + Wifi0RxErrors FlexInt `json:"wifi0-rx_errors"` + Wifi1RxErrors FlexInt `json:"wifi1-rx_errors"` + GuestWifi0RxDropped FlexInt `json:"guest-wifi0-rx_dropped"` + GuestWifi1RxDropped FlexInt `json:"guest-wifi1-rx_dropped"` + UserWifi1RxDropped FlexInt `json:"user-wifi1-rx_dropped"` + UserWifi0RxDropped FlexInt `json:"user-wifi0-rx_dropped"` + Wifi0RxDropped FlexInt `json:"wifi0-rx_dropped"` + Wifi1RxDropped FlexInt `json:"wifi1-rx_dropped"` + GuestWifi0RxCrypts FlexInt `json:"guest-wifi0-rx_crypts"` + GuestWifi1RxCrypts FlexInt `json:"guest-wifi1-rx_crypts"` + UserWifi1RxCrypts FlexInt `json:"user-wifi1-rx_crypts"` + UserWifi0RxCrypts FlexInt `json:"user-wifi0-rx_crypts"` + Wifi0RxCrypts FlexInt `json:"wifi0-rx_crypts"` + Wifi1RxCrypts FlexInt `json:"wifi1-rx_crypts"` + GuestWifi0RxFrags FlexInt `json:"guest-wifi0-rx_frags"` + GuestWifi1RxFrags FlexInt `json:"guest-wifi1-rx_frags"` + UserWifi1RxFrags FlexInt `json:"user-wifi1-rx_frags"` + UserWifi0RxFrags FlexInt `json:"user-wifi0-rx_frags"` + Wifi0RxFrags FlexInt `json:"wifi0-rx_frags"` + Wifi1RxFrags FlexInt `json:"wifi1-rx_frags"` + GuestWifi0TxPackets FlexInt `json:"guest-wifi0-tx_packets"` + GuestWifi1TxPackets FlexInt `json:"guest-wifi1-tx_packets"` + UserWifi1TxPackets FlexInt `json:"user-wifi1-tx_packets"` + UserWifi0TxPackets FlexInt `json:"user-wifi0-tx_packets"` + Wifi0TxPackets FlexInt `json:"wifi0-tx_packets"` + Wifi1TxPackets FlexInt `json:"wifi1-tx_packets"` + GuestWifi0TxBytes FlexInt `json:"guest-wifi0-tx_bytes"` + GuestWifi1TxBytes FlexInt `json:"guest-wifi1-tx_bytes"` + UserWifi1TxBytes FlexInt `json:"user-wifi1-tx_bytes"` + UserWifi0TxBytes FlexInt `json:"user-wifi0-tx_bytes"` + Wifi0TxBytes FlexInt `json:"wifi0-tx_bytes"` + Wifi1TxBytes FlexInt `json:"wifi1-tx_bytes"` + GuestWifi0TxErrors FlexInt `json:"guest-wifi0-tx_errors"` + GuestWifi1TxErrors FlexInt `json:"guest-wifi1-tx_errors"` + UserWifi1TxErrors FlexInt `json:"user-wifi1-tx_errors"` + UserWifi0TxErrors FlexInt `json:"user-wifi0-tx_errors"` + Wifi0TxErrors FlexInt `json:"wifi0-tx_errors"` + Wifi1TxErrors FlexInt `json:"wifi1-tx_errors"` + GuestWifi0TxDropped FlexInt `json:"guest-wifi0-tx_dropped"` + GuestWifi1TxDropped FlexInt `json:"guest-wifi1-tx_dropped"` + UserWifi1TxDropped FlexInt `json:"user-wifi1-tx_dropped"` + UserWifi0TxDropped FlexInt `json:"user-wifi0-tx_dropped"` + Wifi0TxDropped FlexInt `json:"wifi0-tx_dropped"` + Wifi1TxDropped FlexInt `json:"wifi1-tx_dropped"` + GuestWifi0TxRetries FlexInt `json:"guest-wifi0-tx_retries"` + GuestWifi1TxRetries FlexInt `json:"guest-wifi1-tx_retries"` + UserWifi1TxRetries FlexInt `json:"user-wifi1-tx_retries"` + UserWifi0TxRetries FlexInt `json:"user-wifi0-tx_retries"` + Wifi0TxRetries FlexInt `json:"wifi0-tx_retries"` + Wifi1TxRetries FlexInt `json:"wifi1-tx_retries"` + GuestWifi0MacFilterRejections FlexInt `json:"guest-wifi0-mac_filter_rejections"` + GuestWifi1MacFilterRejections FlexInt `json:"guest-wifi1-mac_filter_rejections"` + UserWifi1MacFilterRejections FlexInt `json:"user-wifi1-mac_filter_rejections"` + UserWifi0MacFilterRejections FlexInt `json:"user-wifi0-mac_filter_rejections"` + Wifi0MacFilterRejections FlexInt `json:"wifi0-mac_filter_rejections"` + Wifi1MacFilterRejections FlexInt `json:"wifi1-mac_filter_rejections"` + GuestWifi0WifiTxAttempts FlexInt `json:"guest-wifi0-wifi_tx_attempts"` + GuestWifi1WifiTxAttempts FlexInt `json:"guest-wifi1-wifi_tx_attempts"` + UserWifi1WifiTxAttempts FlexInt `json:"user-wifi1-wifi_tx_attempts"` + UserWifi0WifiTxAttempts FlexInt `json:"user-wifi0-wifi_tx_attempts"` + Wifi0WifiTxAttempts FlexInt `json:"wifi0-wifi_tx_attempts"` + Wifi1WifiTxAttempts FlexInt `json:"wifi1-wifi_tx_attempts"` + GuestWifi0WifiTxDropped FlexInt `json:"guest-wifi0-wifi_tx_dropped"` + GuestWifi1WifiTxDropped FlexInt `json:"guest-wifi1-wifi_tx_dropped"` + UserWifi1WifiTxDropped FlexInt `json:"user-wifi1-wifi_tx_dropped"` + UserWifi0WifiTxDropped FlexInt `json:"user-wifi0-wifi_tx_dropped"` + Wifi0WifiTxDropped FlexInt `json:"wifi0-wifi_tx_dropped"` + Wifi1WifiTxDropped FlexInt `json:"wifi1-wifi_tx_dropped"` + // UDM Names + GuestRa0RxPackets FlexInt `json:"guest-ra0-rx_packets"` + UserRa0RxPackets FlexInt `json:"user-ra0-rx_packets"` + Ra0RxPackets FlexInt `json:"ra0-rx_packets"` + GuestRa0RxBytes FlexInt `json:"guest-ra0-rx_bytes"` + UserRa0RxBytes FlexInt `json:"user-ra0-rx_bytes"` + Ra0RxBytes FlexInt `json:"ra0-rx_bytes"` + GuestRa0RxErrors FlexInt `json:"guest-ra0-rx_errors"` + UserRa0RxErrors FlexInt `json:"user-ra0-rx_errors"` + Ra0RxErrors FlexInt `json:"ra0-rx_errors"` + GuestRa0RxDropped FlexInt `json:"guest-ra0-rx_dropped"` + UserRa0RxDropped FlexInt `json:"user-ra0-rx_dropped"` + Ra0RxDropped FlexInt `json:"ra0-rx_dropped"` + GuestRa0RxCrypts FlexInt `json:"guest-ra0-rx_crypts"` + UserRa0RxCrypts FlexInt `json:"user-ra0-rx_crypts"` + Ra0RxCrypts FlexInt `json:"ra0-rx_crypts"` + GuestRa0RxFrags FlexInt `json:"guest-ra0-rx_frags"` + UserRa0RxFrags FlexInt `json:"user-ra0-rx_frags"` + Ra0RxFrags FlexInt `json:"ra0-rx_frags"` + GuestRa0TxPackets FlexInt `json:"guest-ra0-tx_packets"` + UserRa0TxPackets FlexInt `json:"user-ra0-tx_packets"` + Ra0TxPackets FlexInt `json:"ra0-tx_packets"` + GuestRa0TxBytes FlexInt `json:"guest-ra0-tx_bytes"` + UserRa0TxBytes FlexInt `json:"user-ra0-tx_bytes"` + Ra0TxBytes FlexInt `json:"ra0-tx_bytes"` + GuestRa0TxErrors FlexInt `json:"guest-ra0-tx_errors"` + UserRa0TxErrors FlexInt `json:"user-ra0-tx_errors"` + Ra0TxErrors FlexInt `json:"ra0-tx_errors"` + GuestRa0TxDropped FlexInt `json:"guest-ra0-tx_dropped"` + UserRa0TxDropped FlexInt `json:"user-ra0-tx_dropped"` + Ra0TxDropped FlexInt `json:"ra0-tx_dropped"` + GuestRa0TxRetries FlexInt `json:"guest-ra0-tx_retries"` + UserRa0TxRetries FlexInt `json:"user-ra0-tx_retries"` + Ra0TxRetries FlexInt `json:"ra0-tx_retries"` + GuestRa0MacFilterRejections FlexInt `json:"guest-ra0-mac_filter_rejections"` + UserRa0MacFilterRejections FlexInt `json:"user-ra0-mac_filter_rejections"` + Ra0MacFilterRejections FlexInt `json:"ra0-mac_filter_rejections"` + GuestRa0WifiTxAttempts FlexInt `json:"guest-ra0-wifi_tx_attempts"` + UserRa0WifiTxAttempts FlexInt `json:"user-ra0-wifi_tx_attempts"` + Ra0WifiTxAttempts FlexInt `json:"ra0-wifi_tx_attempts"` + GuestRa0WifiTxDropped FlexInt `json:"guest-ra0-wifi_tx_dropped"` + UserRa0WifiTxDropped FlexInt `json:"user-ra0-wifi_tx_dropped"` + Ra0WifiTxDropped FlexInt `json:"ra0-wifi_tx_dropped"` + GuestRai0RxPackets FlexInt `json:"guest-rai0-rx_packets"` + UserRai0RxPackets FlexInt `json:"user-rai0-rx_packets"` + Rai0RxPackets FlexInt `json:"rai0-rx_packets"` + GuestRai0RxBytes FlexInt `json:"guest-rai0-rx_bytes"` + UserRai0RxBytes FlexInt `json:"user-rai0-rx_bytes"` + Rai0RxBytes FlexInt `json:"rai0-rx_bytes"` + GuestRai0RxErrors FlexInt `json:"guest-rai0-rx_errors"` + UserRai0RxErrors FlexInt `json:"user-rai0-rx_errors"` + Rai0RxErrors FlexInt `json:"rai0-rx_errors"` + GuestRai0RxDropped FlexInt `json:"guest-rai0-rx_dropped"` + UserRai0RxDropped FlexInt `json:"user-rai0-rx_dropped"` + Rai0RxDropped FlexInt `json:"rai0-rx_dropped"` + GuestRai0RxCrypts FlexInt `json:"guest-rai0-rx_crypts"` + UserRai0RxCrypts FlexInt `json:"user-rai0-rx_crypts"` + Rai0RxCrypts FlexInt `json:"rai0-rx_crypts"` + GuestRai0RxFrags FlexInt `json:"guest-rai0-rx_frags"` + UserRai0RxFrags FlexInt `json:"user-rai0-rx_frags"` + Rai0RxFrags FlexInt `json:"rai0-rx_frags"` + GuestRai0TxPackets FlexInt `json:"guest-rai0-tx_packets"` + UserRai0TxPackets FlexInt `json:"user-rai0-tx_packets"` + Rai0TxPackets FlexInt `json:"rai0-tx_packets"` + GuestRai0TxBytes FlexInt `json:"guest-rai0-tx_bytes"` + UserRai0TxBytes FlexInt `json:"user-rai0-tx_bytes"` + Rai0TxBytes FlexInt `json:"rai0-tx_bytes"` + GuestRai0TxErrors FlexInt `json:"guest-rai0-tx_errors"` + UserRai0TxErrors FlexInt `json:"user-rai0-tx_errors"` + Rai0TxErrors FlexInt `json:"rai0-tx_errors"` + GuestRai0TxDropped FlexInt `json:"guest-rai0-tx_dropped"` + UserRai0TxDropped FlexInt `json:"user-rai0-tx_dropped"` + Rai0TxDropped FlexInt `json:"rai0-tx_dropped"` + GuestRai0TxRetries FlexInt `json:"guest-rai0-tx_retries"` + UserRai0TxRetries FlexInt `json:"user-rai0-tx_retries"` + Rai0TxRetries FlexInt `json:"rai0-tx_retries"` + GuestRai0MacFilterRejections FlexInt `json:"guest-rai0-mac_filter_rejections"` + UserRai0MacFilterRejections FlexInt `json:"user-rai0-mac_filter_rejections"` + Rai0MacFilterRejections FlexInt `json:"rai0-mac_filter_rejections"` + GuestRai0WifiTxAttempts FlexInt `json:"guest-rai0-wifi_tx_attempts"` + UserRai0WifiTxAttempts FlexInt `json:"user-rai0-wifi_tx_attempts"` + Rai0WifiTxAttempts FlexInt `json:"rai0-wifi_tx_attempts"` + GuestRai0WifiTxDropped FlexInt `json:"guest-rai0-wifi_tx_dropped"` + UserRai0WifiTxDropped FlexInt `json:"user-rai0-wifi_tx_dropped"` + Rai0WifiTxDropped FlexInt `json:"rai0-wifi_tx_dropped"` + */ +} + +// RadioTable is part of the data for UAPs and UDMs. +type RadioTable []struct { + AntennaGain FlexInt `json:"antenna_gain"` + BuiltinAntGain FlexInt `json:"builtin_ant_gain"` + BuiltinAntenna FlexBool `json:"builtin_antenna"` + Channel FlexInt `json:"channel"` + CurrentAntennaGain FlexInt `json:"current_antenna_gain"` + HasDfs FlexBool `json:"has_dfs"` + HasFccdfs FlexBool `json:"has_fccdfs"` + HasHt160 FlexBool `json:"has_ht160"` + Ht string `json:"ht"` + Is11Ac FlexBool `json:"is_11ac"` + MaxTxpower FlexInt `json:"max_txpower"` + MinRssi FlexInt `json:"min_rssi,omitempty"` + MinRssiEnabled FlexBool `json:"min_rssi_enabled"` + MinTxpower FlexInt `json:"min_txpower"` + Name string `json:"name"` + Nss FlexInt `json:"nss"` + Radio string `json:"radio"` + RadioCaps FlexInt `json:"radio_caps"` + SensLevelEnabled FlexBool `json:"sens_level_enabled"` + TxPower FlexInt `json:"tx_power"` + TxPowerMode string `json:"tx_power_mode"` + VwireEnabled FlexBool `json:"vwire_enabled"` + WlangroupID string `json:"wlangroup_id"` +} + +// RadioTableStats is part of the data shared between UAP and UDM +type RadioTableStats []struct { + Name string `json:"name"` + Channel FlexInt `json:"channel"` + Radio string `json:"radio"` + AstTxto interface{} `json:"ast_txto"` + AstCst interface{} `json:"ast_cst"` + AstBeXmit FlexInt `json:"ast_be_xmit"` + CuTotal FlexInt `json:"cu_total"` + CuSelfRx FlexInt `json:"cu_self_rx"` + CuSelfTx FlexInt `json:"cu_self_tx"` + Gain FlexInt `json:"gain"` + Satisfaction FlexInt `json:"satisfaction"` + State string `json:"state"` + Extchannel FlexInt `json:"extchannel"` + TxPower FlexInt `json:"tx_power"` + TxPackets FlexInt `json:"tx_packets"` + TxRetries FlexInt `json:"tx_retries"` + NumSta FlexInt `json:"num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` +} + +// VapTable holds much of the UAP wireless data. Shared by UDM. +type VapTable []struct { + AnomaliesBarChart struct { + HighDNSLatency FlexInt `json:"high_dns_latency"` + HighTCPLatency FlexInt `json:"high_tcp_latency"` + HighTCPPacketLoss FlexInt `json:"high_tcp_packet_loss"` + HighWifiLatency FlexInt `json:"high_wifi_latency"` + HighWifiRetries FlexInt `json:"high_wifi_retries"` + LowPhyRate FlexInt `json:"low_phy_rate"` + PoorStreamEff FlexInt `json:"poor_stream_eff"` + SleepyClient FlexInt `json:"sleepy_client"` + StaArpTimeout FlexInt `json:"sta_arp_timeout"` + StaDNSTimeout FlexInt `json:"sta_dns_timeout"` + StaIPTimeout FlexInt `json:"sta_ip_timeout"` + WeakSignal FlexInt `json:"weak_signal"` + } `json:"anomalies_bar_chart"` + AnomaliesBarChartNow struct { + HighDNSLatency FlexInt `json:"high_dns_latency"` + HighTCPLatency FlexInt `json:"high_tcp_latency"` + HighTCPPacketLoss FlexInt `json:"high_tcp_packet_loss"` + HighWifiLatency FlexInt `json:"high_wifi_latency"` + HighWifiRetries FlexInt `json:"high_wifi_retries"` + LowPhyRate FlexInt `json:"low_phy_rate"` + PoorStreamEff FlexInt `json:"poor_stream_eff"` + SleepyClient FlexInt `json:"sleepy_client"` + StaArpTimeout FlexInt `json:"sta_arp_timeout"` + StaDNSTimeout FlexInt `json:"sta_dns_timeout"` + StaIPTimeout FlexInt `json:"sta_ip_timeout"` + WeakSignal FlexInt `json:"weak_signal"` + } `json:"anomalies_bar_chart_now"` + ReasonsBarChart struct { + PhyRate FlexInt `json:"phy_rate"` + Signal FlexInt `json:"signal"` + SleepyClient FlexInt `json:"sleepy_client"` + StaArpTimeout FlexInt `json:"sta_arp_timeout"` + StaDNSLatency FlexInt `json:"sta_dns_latency"` + StaDNSTimeout FlexInt `json:"sta_dns_timeout"` + StaIPTimeout FlexInt `json:"sta_ip_timeout"` + StreamEff FlexInt `json:"stream_eff"` + TCPLatency FlexInt `json:"tcp_latency"` + TCPPacketLoss FlexInt `json:"tcp_packet_loss"` + WifiLatency FlexInt `json:"wifi_latency"` + WifiRetries FlexInt `json:"wifi_retries"` + } `json:"reasons_bar_chart"` + ReasonsBarChartNow struct { + PhyRate FlexInt `json:"phy_rate"` + Signal FlexInt `json:"signal"` + SleepyClient FlexInt `json:"sleepy_client"` + StaArpTimeout FlexInt `json:"sta_arp_timeout"` + StaDNSLatency FlexInt `json:"sta_dns_latency"` + StaDNSTimeout FlexInt `json:"sta_dns_timeout"` + StaIPTimeout FlexInt `json:"sta_ip_timeout"` + StreamEff FlexInt `json:"stream_eff"` + TCPLatency FlexInt `json:"tcp_latency"` + TCPPacketLoss FlexInt `json:"tcp_packet_loss"` + WifiLatency FlexInt `json:"wifi_latency"` + WifiRetries FlexInt `json:"wifi_retries"` + } `json:"reasons_bar_chart_now"` + RxTCPStats struct { + Goodbytes FlexInt `json:"goodbytes"` + LatAvg FlexInt `json:"lat_avg"` + LatMax FlexInt `json:"lat_max"` + LatMin FlexInt `json:"lat_min"` + Stalls FlexInt `json:"stalls"` + } `json:"rx_tcp_stats"` + TxTCPStats struct { + Goodbytes FlexInt `json:"goodbytes"` + LatAvg FlexInt `json:"lat_avg"` + LatMax FlexInt `json:"lat_max"` + LatMin FlexInt `json:"lat_min"` + Stalls FlexInt `json:"stalls"` + } `json:"tx_tcp_stats"` + WifiTxLatencyMov struct { + Avg FlexInt `json:"avg"` + Max FlexInt `json:"max"` + Min FlexInt `json:"min"` + Total FlexInt `json:"total"` + TotalCount FlexInt `json:"total_count"` + } `json:"wifi_tx_latency_mov"` + ApMac string `json:"ap_mac"` + AvgClientSignal FlexInt `json:"avg_client_signal"` + Bssid string `json:"bssid"` + Ccq int `json:"ccq"` + Channel int `json:"channel"` + DNSAvgLatency FlexInt `json:"dns_avg_latency"` + Essid string `json:"essid"` + Extchannel int `json:"extchannel"` + ID string `json:"id"` + IsGuest FlexBool `json:"is_guest"` + IsWep FlexBool `json:"is_wep"` + MacFilterRejections int `json:"mac_filter_rejections"` + MapID interface{} `json:"map_id"` + Name string `json:"name"` + NumSatisfactionSta FlexInt `json:"num_satisfaction_sta"` + NumSta int `json:"num_sta"` + Radio string `json:"radio"` + RadioName string `json:"radio_name"` + RxBytes FlexInt `json:"rx_bytes"` + RxCrypts FlexInt `json:"rx_crypts"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxFrags FlexInt `json:"rx_frags"` + RxNwids FlexInt `json:"rx_nwids"` + RxPackets FlexInt `json:"rx_packets"` + Satisfaction FlexInt `json:"satisfaction"` + SatisfactionNow FlexInt `json:"satisfaction_now"` + SiteID string `json:"site_id"` + State string `json:"state"` + T string `json:"t"` + TxBytes FlexInt `json:"tx_bytes"` + TxCombinedRetries FlexInt `json:"tx_combined_retries"` + TxDataMpduBytes FlexInt `json:"tx_data_mpdu_bytes"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxPackets FlexInt `json:"tx_packets"` + TxPower FlexInt `json:"tx_power"` + TxRetries FlexInt `json:"tx_retries"` + TxRtsRetries FlexInt `json:"tx_rts_retries"` + TxSuccess FlexInt `json:"tx_success"` + TxTotal FlexInt `json:"tx_total"` + Up FlexBool `json:"up"` + Usage string `json:"usage"` + WifiTxAttempts FlexInt `json:"wifi_tx_attempts"` + WifiTxDropped FlexInt `json:"wifi_tx_dropped"` + WlanconfID string `json:"wlanconf_id"` +} + +// UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Access Point Stat data. +func (v *UAPStat) UnmarshalJSON(data []byte) error { + var n struct { + Ap `json:"ap"` + } + v.Ap = &n.Ap + err := json.Unmarshal(data, v.Ap) // controller version 5.10. + if err != nil { + return json.Unmarshal(data, &n) // controller version 5.11. + } + return nil +} diff --git a/core/unifi/uap_type_test.go b/core/unifi/uap_test.go similarity index 100% rename from core/unifi/uap_type_test.go rename to core/unifi/uap_test.go diff --git a/core/unifi/uap_type.go b/core/unifi/uap_type.go deleted file mode 100644 index a83657b7..00000000 --- a/core/unifi/uap_type.go +++ /dev/null @@ -1,449 +0,0 @@ -package unifi - -import ( - "encoding/json" - "time" -) - -// UAP represents all the data from the Ubiquiti 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. - */ - ID string `json:"_id"` - Adopted FlexBool `json:"adopted"` - AntennaTable []struct { - Default FlexBool `json:"default"` - ID FlexInt `json:"id"` - Name string `json:"name"` - Wifi0Gain FlexInt `json:"wifi0_gain"` - Wifi1Gain FlexInt `json:"wifi1_gain"` - } `json:"antenna_table"` - BandsteeringMode string `json:"bandsteering_mode,omitempty"` - BoardRev int `json:"board_rev"` - Cfgversion string `json:"cfgversion"` - ConfigNetwork struct { - Type string `json:"type"` - IP string `json:"ip"` - } `json:"config_network"` - CountrycodeTable []int `json:"countrycode_table"` - EthernetTable []struct { - Mac string `json:"mac"` - NumPort FlexInt `json:"num_port"` - Name string `json:"name"` - } `json:"ethernet_table"` - FwCaps int `json:"fw_caps"` - HasEth1 FlexBool `json:"has_eth1"` - HasSpeaker FlexBool `json:"has_speaker"` - InformIP string `json:"inform_ip"` - InformURL string `json:"inform_url"` - IP string `json:"ip"` - LedOverride string `json:"led_override"` - Mac string `json:"mac"` - MeshStaVapEnabled FlexBool `json:"mesh_sta_vap_enabled"` - Model string `json:"model"` - Name string `json:"name"` - OutdoorModeOverride string `json:"outdoor_mode_override"` - PortTable []Port `json:"port_table"` - RadioTable []struct { - Radio string `json:"radio"` - Name string `json:"name"` - Channel FlexInt `json:"channel"` - Ht string `json:"ht"` - TxPowerMode string `json:"tx_power_mode"` - TxPower FlexInt `json:"tx_power"` - MaxTxpower FlexInt `json:"max_txpower"` - MinTxpower FlexInt `json:"min_txpower"` - Nss FlexInt `json:"nss"` - MinRssiEnabled FlexBool `json:"min_rssi_enabled"` - BuiltinAntenna FlexBool `json:"builtin_antenna"` - BuiltinAntGain FlexInt `json:"builtin_ant_gain"` - CurrentAntennaGain FlexInt `json:"current_antenna_gain"` - RadioCaps FlexInt `json:"radio_caps"` - WlangroupID string `json:"wlangroup_id"` - Is11Ac FlexBool `json:"is_11ac,omitempty"` - HasDfs FlexBool `json:"has_dfs,omitempty"` - HasFccdfs FlexBool `json:"has_fccdfs,omitempty"` - } `json:"radio_table"` - ScanRadioTable []interface{} `json:"scan_radio_table"` - Serial string `json:"serial"` - SiteID string `json:"site_id"` - SiteName string `json:"-"` - Type string `json:"type"` - Version string `json:"version"` - VwireTable []interface{} `json:"vwire_table"` - WifiCaps int `json:"wifi_caps"` - WlangroupIDNa string `json:"wlangroup_id_na"` - WlangroupIDNg string `json:"wlangroup_id_ng"` - RequiredVersion string `json:"required_version"` - HwCaps int `json:"hw_caps"` - Unsupported FlexBool `json:"unsupported"` - UnsupportedReason FlexInt `json:"unsupported_reason"` - SysErrorCaps int `json:"sys_error_caps"` - HasFan FlexBool `json:"has_fan"` - HasTemperature FlexBool `json:"has_temperature"` - DeviceID string `json:"device_id"` - State int `json:"state"` - LastSeen FlexInt `json:"last_seen"` - Upgradable FlexBool `json:"upgradable"` - AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` - Rollupgrade FlexBool `json:"rollupgrade"` - KnownCfgversion string `json:"known_cfgversion"` - Uptime FlexInt `json:"uptime"` - UUptime FlexInt `json:"_uptime"` - Locating FlexBool `json:"locating"` - ConnectRequestIP string `json:"connect_request_ip"` - ConnectRequestPort string `json:"connect_request_port"` - SysStats SysStats `json:"sys_stats"` - SystemStats SystemStats `json:"system-stats"` - SSHSessionTable []interface{} `json:"ssh_session_table"` - Scanning FlexBool `json:"scanning"` - SpectrumScanning FlexBool `json:"spectrum_scanning"` - GuestToken string `json:"guest_token"` - Meshv3PeerMac string `json:"meshv3_peer_mac"` - Satisfaction FlexInt `json:"satisfaction"` - Isolated FlexBool `json:"isolated"` - RadioTableStats []struct { - Name string `json:"name"` - Channel FlexInt `json:"channel"` - Radio string `json:"radio"` - AstTxto interface{} `json:"ast_txto"` - AstCst interface{} `json:"ast_cst"` - AstBeXmit FlexInt `json:"ast_be_xmit"` - CuTotal FlexInt `json:"cu_total"` - CuSelfRx FlexInt `json:"cu_self_rx"` - CuSelfTx FlexInt `json:"cu_self_tx"` - Gain FlexInt `json:"gain"` - State string `json:"state"` - Extchannel FlexInt `json:"extchannel"` - TxPower FlexInt `json:"tx_power"` - TxPackets FlexInt `json:"tx_packets"` - TxRetries FlexInt `json:"tx_retries"` - NumSta FlexInt `json:"num_sta"` - GuestNumSta FlexInt `json:"guest-num_sta"` - UserNumSta FlexInt `json:"user-num_sta"` - } `json:"radio_table_stats"` - Uplink struct { - FullDuplex FlexBool `json:"full_duplex"` - IP string `json:"ip"` - Mac string `json:"mac"` - MaxVlan int `json:"max_vlan"` - Name string `json:"name"` - Netmask string `json:"netmask"` - NumPort int `json:"num_port"` - RxBytes FlexInt `json:"rx_bytes"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxMulticast FlexInt `json:"rx_multicast"` - RxPackets FlexInt `json:"rx_packets"` - Speed FlexInt `json:"speed"` - TxBytes FlexInt `json:"tx_bytes"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxPackets FlexInt `json:"tx_packets"` - Up FlexBool `json:"up"` - MaxSpeed FlexInt `json:"max_speed"` - Type string `json:"type"` - TxBytesR FlexInt `json:"tx_bytes-r"` - RxBytesR FlexInt `json:"rx_bytes-r"` - UplinkMac string `json:"uplink_mac"` - UplinkRemotePort int `json:"uplink_remote_port"` - } `json:"uplink"` - VapTable []struct { - AnomaliesBarChart struct { - HighTCPLatency FlexInt `json:"high_tcp_latency"` - HighTCPPacketLoss FlexInt `json:"high_tcp_packet_loss"` - HighWifiLatency FlexInt `json:"high_wifi_latency"` - HighWifiRetries FlexInt `json:"high_wifi_retries"` - LowPhyRate FlexInt `json:"low_phy_rate"` - PoorStreamEff FlexInt `json:"poor_stream_eff"` - SleepyClient FlexInt `json:"sleepy_client"` - StaArpTimeout FlexInt `json:"sta_arp_timeout"` - StaDNSTimeout FlexInt `json:"sta_dns_timeout"` - StaIPTimeout FlexInt `json:"sta_ip_timeout"` - WeakSignal FlexInt `json:"weak_signal"` - } `json:"anomalies_bar_chart"` - AnomaliesBarChartNow struct { - HighTCPLatency FlexInt `json:"high_tcp_latency"` - HighTCPPacketLoss FlexInt `json:"high_tcp_packet_loss"` - HighWifiLatency FlexInt `json:"high_wifi_latency"` - HighWifiRetries FlexInt `json:"high_wifi_retries"` - LowPhyRate FlexInt `json:"low_phy_rate"` - PoorStreamEff FlexInt `json:"poor_stream_eff"` - SleepyClient FlexInt `json:"sleepy_client"` - StaArpTimeout FlexInt `json:"sta_arp_timeout"` - StaDNSTimeout FlexInt `json:"sta_dns_timeout"` - StaIPTimeout FlexInt `json:"sta_ip_timeout"` - WeakSignal FlexInt `json:"weak_signal"` - } `json:"anomalies_bar_chart_now"` - AvgClientSignal FlexInt `json:"avg_client_signal"` - Bssid string `json:"bssid"` - Ccq int `json:"ccq"` - Channel int `json:"channel"` - Essid string `json:"essid"` - Extchannel int `json:"extchannel"` - ID string `json:"id"` - MacFilterRejections int `json:"mac_filter_rejections"` - Name string `json:"name"` - NumSatisfactionSta FlexInt `json:"num_satisfaction_sta"` - NumSta int `json:"num_sta"` - Radio string `json:"radio"` - RadioName string `json:"radio_name"` - ReasonsBarChart struct { - PhyRate FlexInt `json:"phy_rate"` - Signal FlexInt `json:"signal"` - SleepyClient FlexInt `json:"sleepy_client"` - StaArpTimeout FlexInt `json:"sta_arp_timeout"` - StaDNSTimeout FlexInt `json:"sta_dns_timeout"` - StaIPTimeout FlexInt `json:"sta_ip_timeout"` - StreamEff FlexInt `json:"stream_eff"` - TCPLatency FlexInt `json:"tcp_latency"` - TCPPacketLoss FlexInt `json:"tcp_packet_loss"` - WifiLatency FlexInt `json:"wifi_latency"` - WifiRetries FlexInt `json:"wifi_retries"` - } `json:"reasons_bar_chart"` - ReasonsBarChartNow struct { - PhyRate FlexInt `json:"phy_rate"` - Signal FlexInt `json:"signal"` - SleepyClient FlexInt `json:"sleepy_client"` - StaArpTimeout FlexInt `json:"sta_arp_timeout"` - StaDNSTimeout FlexInt `json:"sta_dns_timeout"` - StaIPTimeout FlexInt `json:"sta_ip_timeout"` - StreamEff FlexInt `json:"stream_eff"` - TCPLatency FlexInt `json:"tcp_latency"` - TCPPacketLoss FlexInt `json:"tcp_packet_loss"` - WifiLatency FlexInt `json:"wifi_latency"` - WifiRetries FlexInt `json:"wifi_retries"` - } `json:"reasons_bar_chart_now"` - RxBytes FlexInt `json:"rx_bytes"` - RxCrypts FlexInt `json:"rx_crypts"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxFrags FlexInt `json:"rx_frags"` - RxNwids FlexInt `json:"rx_nwids"` - RxPackets FlexInt `json:"rx_packets"` - RxTCPStats struct { - Goodbytes FlexInt `json:"goodbytes"` - LatAvg FlexInt `json:"lat_avg"` - LatMax FlexInt `json:"lat_max"` - LatMin FlexInt `json:"lat_min"` - Stalls FlexInt `json:"stalls"` - } `json:"rx_tcp_stats"` - Satisfaction FlexInt `json:"satisfaction"` - SatisfactionNow FlexInt `json:"satisfaction_now"` - State string `json:"state"` - TxBytes FlexInt `json:"tx_bytes"` - TxCombinedRetries FlexInt `json:"tx_combined_retries"` - TxDataMpduBytes FlexInt `json:"tx_data_mpdu_bytes"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxPackets FlexInt `json:"tx_packets"` - TxPower FlexInt `json:"tx_power"` - TxRetries FlexInt `json:"tx_retries"` - TxRtsRetries FlexInt `json:"tx_rts_retries"` - TxSuccess FlexInt `json:"tx_success"` - TxTCPStats struct { - Goodbytes FlexInt `json:"goodbytes"` - LatAvg FlexInt `json:"lat_avg"` - LatMax FlexInt `json:"lat_max"` - LatMin FlexInt `json:"lat_min"` - Stalls FlexInt `json:"stalls"` - } `json:"tx_tcp_stats"` - TxTotal FlexInt `json:"tx_total"` - Up FlexBool `json:"up"` - Usage string `json:"usage"` - WifiTxAttempts FlexInt `json:"wifi_tx_attempts"` - WifiTxDropped FlexInt `json:"wifi_tx_dropped"` - WifiTxLatencyMov struct { - Avg FlexInt `json:"avg"` - Max FlexInt `json:"max"` - Min FlexInt `json:"min"` - Total FlexInt `json:"total"` - TotalCount FlexInt `json:"total_count"` - } `json:"wifi_tx_latency_mov"` - T string `json:"t"` - WlanconfID string `json:"wlanconf_id"` - IsGuest FlexBool `json:"is_guest"` - IsWep FlexBool `json:"is_wep"` - ApMac string `json:"ap_mac"` - MapID interface{} `json:"map_id"` - SiteID string `json:"site_id"` - } `json:"vap_table"` - DownlinkTable []interface{} `json:"downlink_table"` - VwireVapTable []interface{} `json:"vwire_vap_table"` - BytesD FlexInt `json:"bytes-d"` - TxBytesD FlexInt `json:"tx_bytes-d"` - RxBytesD FlexInt `json:"rx_bytes-d"` - BytesR FlexInt `json:"bytes-r"` - LastUplink struct { - UplinkMac string `json:"uplink_mac"` - UplinkRemotePort int `json:"uplink_remote_port"` - } `json:"last_uplink"` - Stat UAPStat `json:"stat"` - TxBytes FlexInt `json:"tx_bytes"` - RxBytes FlexInt `json:"rx_bytes"` - Bytes FlexInt `json:"bytes"` - VwireEnabled FlexBool `json:"vwireEnabled"` - UplinkTable []interface{} `json:"uplink_table"` - NumSta int `json:"num_sta"` - UserNumSta int `json:"user-num_sta"` - GuestNumSta int `json:"guest-num_sta"` - TwoPhaseAdopt FlexBool `json:"two_phase_adopt,omitempty"` -} - -// UAPStat holds the "stat" data for an access point. -// This is split out because of a JSON data format change from 5.10 to 5.11. -type UAPStat struct { - *Ap -} - -// Ap is a subtype of UAPStat to make unmarshalling of different controller versions possible. -type Ap struct { - SiteID string `json:"site_id"` - O string `json:"o"` - Oid string `json:"oid"` - Ap string `json:"ap"` - Time FlexInt `json:"time"` - Datetime time.Time `json:"datetime"` - GuestWifi0RxPackets FlexInt `json:"guest-wifi0-rx_packets"` - GuestWifi1RxPackets FlexInt `json:"guest-wifi1-rx_packets"` - UserWifi1RxPackets FlexInt `json:"user-wifi1-rx_packets"` - UserWifi0RxPackets FlexInt `json:"user-wifi0-rx_packets"` - UserRxPackets FlexInt `json:"user-rx_packets"` - GuestRxPackets FlexInt `json:"guest-rx_packets"` - Wifi0RxPackets FlexInt `json:"wifi0-rx_packets"` - Wifi1RxPackets FlexInt `json:"wifi1-rx_packets"` - RxPackets FlexInt `json:"rx_packets"` - GuestWifi0RxBytes FlexInt `json:"guest-wifi0-rx_bytes"` - GuestWifi1RxBytes FlexInt `json:"guest-wifi1-rx_bytes"` - UserWifi1RxBytes FlexInt `json:"user-wifi1-rx_bytes"` - UserWifi0RxBytes FlexInt `json:"user-wifi0-rx_bytes"` - UserRxBytes FlexInt `json:"user-rx_bytes"` - GuestRxBytes FlexInt `json:"guest-rx_bytes"` - Wifi0RxBytes FlexInt `json:"wifi0-rx_bytes"` - Wifi1RxBytes FlexInt `json:"wifi1-rx_bytes"` - RxBytes FlexInt `json:"rx_bytes"` - GuestWifi0RxErrors FlexInt `json:"guest-wifi0-rx_errors"` - GuestWifi1RxErrors FlexInt `json:"guest-wifi1-rx_errors"` - UserWifi1RxErrors FlexInt `json:"user-wifi1-rx_errors"` - UserWifi0RxErrors FlexInt `json:"user-wifi0-rx_errors"` - UserRxErrors FlexInt `json:"user-rx_errors"` - GuestRxErrors FlexInt `json:"guest-rx_errors"` - Wifi0RxErrors FlexInt `json:"wifi0-rx_errors"` - Wifi1RxErrors FlexInt `json:"wifi1-rx_errors"` - RxErrors FlexInt `json:"rx_errors"` - GuestWifi0RxDropped FlexInt `json:"guest-wifi0-rx_dropped"` - GuestWifi1RxDropped FlexInt `json:"guest-wifi1-rx_dropped"` - UserWifi1RxDropped FlexInt `json:"user-wifi1-rx_dropped"` - UserWifi0RxDropped FlexInt `json:"user-wifi0-rx_dropped"` - UserRxDropped FlexInt `json:"user-rx_dropped"` - GuestRxDropped FlexInt `json:"guest-rx_dropped"` - Wifi0RxDropped FlexInt `json:"wifi0-rx_dropped"` - Wifi1RxDropped FlexInt `json:"wifi1-rx_dropped"` - RxDropped FlexInt `json:"rx_dropped"` - GuestWifi0RxCrypts FlexInt `json:"guest-wifi0-rx_crypts"` - GuestWifi1RxCrypts FlexInt `json:"guest-wifi1-rx_crypts"` - UserWifi1RxCrypts FlexInt `json:"user-wifi1-rx_crypts"` - UserWifi0RxCrypts FlexInt `json:"user-wifi0-rx_crypts"` - UserRxCrypts FlexInt `json:"user-rx_crypts"` - GuestRxCrypts FlexInt `json:"guest-rx_crypts"` - Wifi0RxCrypts FlexInt `json:"wifi0-rx_crypts"` - Wifi1RxCrypts FlexInt `json:"wifi1-rx_crypts"` - RxCrypts FlexInt `json:"rx_crypts"` - GuestWifi0RxFrags FlexInt `json:"guest-wifi0-rx_frags"` - GuestWifi1RxFrags FlexInt `json:"guest-wifi1-rx_frags"` - UserWifi1RxFrags FlexInt `json:"user-wifi1-rx_frags"` - UserWifi0RxFrags FlexInt `json:"user-wifi0-rx_frags"` - UserRxFrags FlexInt `json:"user-rx_frags"` - GuestRxFrags FlexInt `json:"guest-rx_frags"` - Wifi0RxFrags FlexInt `json:"wifi0-rx_frags"` - Wifi1RxFrags FlexInt `json:"wifi1-rx_frags"` - RxFrags FlexInt `json:"rx_frags"` - GuestWifi0TxPackets FlexInt `json:"guest-wifi0-tx_packets"` - GuestWifi1TxPackets FlexInt `json:"guest-wifi1-tx_packets"` - UserWifi1TxPackets FlexInt `json:"user-wifi1-tx_packets"` - UserWifi0TxPackets FlexInt `json:"user-wifi0-tx_packets"` - UserTxPackets FlexInt `json:"user-tx_packets"` - GuestTxPackets FlexInt `json:"guest-tx_packets"` - Wifi0TxPackets FlexInt `json:"wifi0-tx_packets"` - Wifi1TxPackets FlexInt `json:"wifi1-tx_packets"` - TxPackets FlexInt `json:"tx_packets"` - GuestWifi0TxBytes FlexInt `json:"guest-wifi0-tx_bytes"` - GuestWifi1TxBytes FlexInt `json:"guest-wifi1-tx_bytes"` - UserWifi1TxBytes FlexInt `json:"user-wifi1-tx_bytes"` - UserWifi0TxBytes FlexInt `json:"user-wifi0-tx_bytes"` - UserTxBytes FlexInt `json:"user-tx_bytes"` - GuestTxBytes FlexInt `json:"guest-tx_bytes"` - Wifi0TxBytes FlexInt `json:"wifi0-tx_bytes"` - Wifi1TxBytes FlexInt `json:"wifi1-tx_bytes"` - TxBytes FlexInt `json:"tx_bytes"` - GuestWifi0TxErrors FlexInt `json:"guest-wifi0-tx_errors"` - GuestWifi1TxErrors FlexInt `json:"guest-wifi1-tx_errors"` - UserWifi1TxErrors FlexInt `json:"user-wifi1-tx_errors"` - UserWifi0TxErrors FlexInt `json:"user-wifi0-tx_errors"` - UserTxErrors FlexInt `json:"user-tx_errors"` - GuestTxErrors FlexInt `json:"guest-tx_errors"` - Wifi0TxErrors FlexInt `json:"wifi0-tx_errors"` - Wifi1TxErrors FlexInt `json:"wifi1-tx_errors"` - TxErrors FlexInt `json:"tx_errors"` - GuestWifi0TxDropped FlexInt `json:"guest-wifi0-tx_dropped"` - GuestWifi1TxDropped FlexInt `json:"guest-wifi1-tx_dropped"` - UserWifi1TxDropped FlexInt `json:"user-wifi1-tx_dropped"` - UserWifi0TxDropped FlexInt `json:"user-wifi0-tx_dropped"` - UserTxDropped FlexInt `json:"user-tx_dropped"` - GuestTxDropped FlexInt `json:"guest-tx_dropped"` - Wifi0TxDropped FlexInt `json:"wifi0-tx_dropped"` - Wifi1TxDropped FlexInt `json:"wifi1-tx_dropped"` - TxDropped FlexInt `json:"tx_dropped"` - GuestWifi0TxRetries FlexInt `json:"guest-wifi0-tx_retries"` - GuestWifi1TxRetries FlexInt `json:"guest-wifi1-tx_retries"` - UserWifi1TxRetries FlexInt `json:"user-wifi1-tx_retries"` - UserWifi0TxRetries FlexInt `json:"user-wifi0-tx_retries"` - UserTxRetries FlexInt `json:"user-tx_retries"` - GuestTxRetries FlexInt `json:"guest-tx_retries"` - Wifi0TxRetries FlexInt `json:"wifi0-tx_retries"` - Wifi1TxRetries FlexInt `json:"wifi1-tx_retries"` - TxRetries FlexInt `json:"tx_retries"` - GuestWifi0MacFilterRejections FlexInt `json:"guest-wifi0-mac_filter_rejections"` - GuestWifi1MacFilterRejections FlexInt `json:"guest-wifi1-mac_filter_rejections"` - UserWifi1MacFilterRejections FlexInt `json:"user-wifi1-mac_filter_rejections"` - UserWifi0MacFilterRejections FlexInt `json:"user-wifi0-mac_filter_rejections"` - UserMacFilterRejections FlexInt `json:"user-mac_filter_rejections"` - GuestMacFilterRejections FlexInt `json:"guest-mac_filter_rejections"` - Wifi0MacFilterRejections FlexInt `json:"wifi0-mac_filter_rejections"` - Wifi1MacFilterRejections FlexInt `json:"wifi1-mac_filter_rejections"` - MacFilterRejections FlexInt `json:"mac_filter_rejections"` - GuestWifi0WifiTxAttempts FlexInt `json:"guest-wifi0-wifi_tx_attempts"` - GuestWifi1WifiTxAttempts FlexInt `json:"guest-wifi1-wifi_tx_attempts"` - UserWifi1WifiTxAttempts FlexInt `json:"user-wifi1-wifi_tx_attempts"` - UserWifi0WifiTxAttempts FlexInt `json:"user-wifi0-wifi_tx_attempts"` - UserWifiTxAttempts FlexInt `json:"user-wifi_tx_attempts"` - GuestWifiTxAttempts FlexInt `json:"guest-wifi_tx_attempts"` - Wifi0WifiTxAttempts FlexInt `json:"wifi0-wifi_tx_attempts"` - Wifi1WifiTxAttempts FlexInt `json:"wifi1-wifi_tx_attempts"` - WifiTxAttempts FlexInt `json:"wifi_tx_attempts"` - GuestWifi0WifiTxDropped FlexInt `json:"guest-wifi0-wifi_tx_dropped"` - GuestWifi1WifiTxDropped FlexInt `json:"guest-wifi1-wifi_tx_dropped"` - UserWifi1WifiTxDropped FlexInt `json:"user-wifi1-wifi_tx_dropped"` - UserWifi0WifiTxDropped FlexInt `json:"user-wifi0-wifi_tx_dropped"` - UserWifiTxDropped FlexInt `json:"user-wifi_tx_dropped"` - GuestWifiTxDropped FlexInt `json:"guest-wifi_tx_dropped"` - Wifi0WifiTxDropped FlexInt `json:"wifi0-wifi_tx_dropped"` - Wifi1WifiTxDropped FlexInt `json:"wifi1-wifi_tx_dropped"` - WifiTxDropped FlexInt `json:"wifi_tx_dropped"` - Bytes FlexInt `json:"bytes"` - Duration FlexInt `json:"duration"` -} - -// UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Access Point Stat data. -func (v *UAPStat) UnmarshalJSON(data []byte) error { - var n struct { - Ap `json:"ap"` - } - v.Ap = &n.Ap - err := json.Unmarshal(data, v.Ap) // controller version 5.10. - if err != nil { - return json.Unmarshal(data, &n) // controller version 5.11. - } - return nil -} diff --git a/core/unifi/udm.go b/core/unifi/udm.go new file mode 100644 index 00000000..840b12cd --- /dev/null +++ b/core/unifi/udm.go @@ -0,0 +1,208 @@ +package unifi + +// UDM represents all the data from the Ubiquiti Controller for a Unifi Dream Machine. +// The UDM shares several structs/type-data with USW and USG. +type UDM struct { + SiteID string `json:"site_id"` + SiteName string `json:"-"` + Mac string `json:"mac"` + Adopted FlexBool `json:"adopted"` + Serial string `json:"serial"` + IP string `json:"ip"` + Uptime FlexInt `json:"uptime"` + Model string `json:"model"` + Version string `json:"version"` + Name string `json:"name"` + Default FlexBool `json:"default"` + Locating FlexBool `json:"locating"` + Type string `json:"type"` + Unsupported FlexBool `json:"unsupported"` + UnsupportedReason FlexInt `json:"unsupported_reason"` + DiscoveredVia string `json:"discovered_via"` + AdoptIP string `json:"adopt_ip"` + AdoptURL string `json:"adopt_url"` + State FlexInt `json:"state"` + AdoptStatus FlexInt `json:"adopt_status"` + UpgradeState FlexInt `json:"upgrade_state"` + LastSeen FlexInt `json:"last_seen"` + AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` + Cfgversion string `json:"cfgversion"` + ConfigNetwork struct { + Type string `json:"type"` + IP string `json:"ip"` + } `json:"config_network"` + VwireTable []interface{} `json:"vwire_table"` + Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"` + JumboframeEnabled FlexBool `json:"jumboframe_enabled"` + FlowctrlEnabled FlexBool `json:"flowctrl_enabled"` + StpVersion string `json:"stp_version"` + StpPriority string `json:"stp_priority"` + PowerSourceCtrlEnabled FlexBool `json:"power_source_ctrl_enabled"` + LicenseState string `json:"license_state"` + ID string `json:"_id"` + DeviceID string `json:"device_id"` + AdoptState FlexInt `json:"adopt_state"` + AdoptTries FlexInt `json:"adopt_tries"` + AdoptManual FlexBool `json:"adopt_manual"` + InformURL string `json:"inform_url"` + InformIP string `json:"inform_ip"` + RequiredVersion string `json:"required_version"` + BoardRev FlexInt `json:"board_rev"` + EthernetTable []struct { + Mac string `json:"mac"` + NumPort FlexInt `json:"num_port"` + Name string `json:"name"` + } `json:"ethernet_table"` + PortTable []Port `json:"port_table"` + EthernetOverrides []struct { + Ifname string `json:"ifname"` + Networkgroup string `json:"networkgroup"` + } `json:"ethernet_overrides"` + UsgCaps FlexInt `json:"usg_caps"` + HasSpeaker FlexBool `json:"has_speaker"` + HasEth1 FlexBool `json:"has_eth1"` + FwCaps FlexInt `json:"fw_caps"` + HwCaps FlexInt `json:"hw_caps"` + WifiCaps FlexInt `json:"wifi_caps"` + SwitchCaps struct { + MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` + MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` + } `json:"switch_caps"` + HasFan FlexBool `json:"has_fan"` + HasTemperature FlexBool `json:"has_temperature"` + RulesetInterfaces interface{} `json:"ruleset_interfaces"` + /* struct { + Br0 string `json:"br0"` + Eth0 string `json:"eth0"` + Eth1 string `json:"eth1"` + Eth2 string `json:"eth2"` + Eth3 string `json:"eth3"` + Eth4 string `json:"eth4"` + Eth5 string `json:"eth5"` + Eth6 string `json:"eth6"` + Eth7 string `json:"eth7"` + Eth8 string `json:"eth8"` + } */ + KnownCfgversion string `json:"known_cfgversion"` + SysStats SysStats `json:"sys_stats"` + SystemStats SystemStats `json:"system-stats"` + GuestToken string `json:"guest_token"` + Overheating FlexBool `json:"overheating"` + SpeedtestStatus SpeedtestStatus `json:"speedtest-status"` + SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"` + Wan1 Wan `json:"wan1"` + Wan2 Wan `json:"wan2"` + Uplink Uplink `json:"uplink"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + DownlinkTable []interface{} `json:"downlink_table"` + WlangroupIDNa string `json:"wlangroup_id_na"` + WlangroupIDNg string `json:"wlangroup_id_ng"` + BandsteeringMode string `json:"bandsteering_mode"` + RadioTable *RadioTable `json:"radio_table,omitempty"` + RadioTableStats *RadioTableStats `json:"radio_table_stats,omitempty"` + VapTable *VapTable `json:"vap_table"` + XInformAuthkey string `json:"x_inform_authkey"` + NetworkTable NetworkTable `json:"network_table"` + PortOverrides []struct { + PortIdx FlexInt `json:"port_idx"` + PortconfID string `json:"portconf_id"` + } `json:"port_overrides"` + Stat UDMStat `json:"stat"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + NumSta FlexInt `json:"num_sta"` + WlanNumSta FlexInt `json:"wlan-num_sta"` + LanNumSta FlexInt `json:"lan-num_sta"` + UserWlanNumSta FlexInt `json:"user-wlan-num_sta"` + UserLanNumSta FlexInt `json:"user-lan-num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` + GuestWlanNumSta FlexInt `json:"guest-wlan-num_sta"` + GuestLanNumSta FlexInt `json:"guest-lan-num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` + NumDesktop FlexInt `json:"num_desktop"` + NumMobile FlexInt `json:"num_mobile"` + NumHandheld FlexInt `json:"num_handheld"` +} + +// NetworkTable is the list of networks on a gateway. +type NetworkTable []struct { + ID string `json:"_id"` + AttrNoDelete FlexBool `json:"attr_no_delete"` + AttrHiddenID string `json:"attr_hidden_id"` + Name string `json:"name"` + SiteID string `json:"site_id"` + VlanEnabled FlexBool `json:"vlan_enabled"` + Purpose string `json:"purpose"` + IPSubnet string `json:"ip_subnet"` + Ipv6InterfaceType string `json:"ipv6_interface_type"` + DomainName string `json:"domain_name"` + IsNat FlexBool `json:"is_nat"` + DhcpdEnabled FlexBool `json:"dhcpd_enabled"` + DhcpdStart string `json:"dhcpd_start"` + DhcpdStop string `json:"dhcpd_stop"` + Dhcpdv6Enabled FlexBool `json:"dhcpdv6_enabled"` + Ipv6RaEnabled FlexBool `json:"ipv6_ra_enabled"` + LteLanEnabled FlexBool `json:"lte_lan_enabled"` + Networkgroup string `json:"networkgroup"` + DhcpdLeasetime FlexInt `json:"dhcpd_leasetime"` + DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"` + DhcpdGatewayEnabled FlexBool `json:"dhcpd_gateway_enabled"` + DhcpdTimeOffsetEnabled FlexBool `json:"dhcpd_time_offset_enabled"` + Ipv6PdStart string `json:"ipv6_pd_start"` + Ipv6PdStop string `json:"ipv6_pd_stop"` + DhcpdDNS1 string `json:"dhcpd_dns_1"` + DhcpdDNS2 string `json:"dhcpd_dns_2"` + DhcpdDNS3 string `json:"dhcpd_dns_3"` + DhcpdDNS4 string `json:"dhcpd_dns_4"` + Enabled FlexBool `json:"enabled"` + DhcpRelayEnabled FlexBool `json:"dhcp_relay_enabled"` + Mac string `json:"mac"` + IsGuest FlexBool `json:"is_guest"` + IP string `json:"ip"` + Up FlexBool `json:"up"` + DPIStatsTable DPIStatsTable `json:"dpistats_table,omitempty"` + NumSta FlexInt `json:"num_sta"` + RxBytes FlexInt `json:"rx_bytes"` + RxPackets FlexInt `json:"rx_packets"` + TxBytes FlexInt `json:"tx_bytes"` + TxPackets FlexInt `json:"tx_packets"` +} + +// DPIStatsTable is the Deep Packet Inspection data for each "network" +type DPIStatsTable struct { + LastUpdated FlexInt `json:"last_updated"` + ByCat []struct { + Cat FlexInt `json:"cat"` + Apps []FlexInt `json:"apps"` + RxBytes FlexInt `json:"rx_bytes"` + TxBytes FlexInt `json:"tx_bytes"` + RxPackets FlexInt `json:"rx_packets"` + TxPackets FlexInt `json:"tx_packets"` + } `json:"by_cat"` + ByApp []struct { + App FlexInt `json:"app"` + Cat FlexInt `json:"cat"` + Clients []struct { + Mac string `json:"mac"` + RxBytes FlexInt `json:"rx_bytes"` + TxBytes FlexInt `json:"tx_bytes"` + RxPackets FlexInt `json:"rx_packets"` + TxPackets FlexInt `json:"tx_packets"` + } `json:"clients"` + KnownClients FlexInt `json:"known_clients"` + RxBytes FlexInt `json:"rx_bytes"` + TxBytes FlexInt `json:"tx_bytes"` + RxPackets FlexInt `json:"rx_packets"` + TxPackets FlexInt `json:"tx_packets"` + } `json:"by_app"` +} + +// UDMStat holds the "stat" data for a dream machine. +// A dream machine is a USG + USW + Controller +type UDMStat struct { + *Gw `json:"gw"` + *Sw `json:"sw"` + *Ap `json:"ap,omitempty"` +} diff --git a/core/unifi/udm_type.go b/core/unifi/udm_type.go deleted file mode 100644 index e7a21c39..00000000 --- a/core/unifi/udm_type.go +++ /dev/null @@ -1,185 +0,0 @@ -package unifi - -// UDM represents all the data from the Ubiquiti Controller for a Unifi Dream Machine. -// The UDM shares several structs/type-data with USW and USG. -type UDM struct { - SiteID string `json:"site_id"` - SiteName string `json:"-"` - Mac string `json:"mac"` - Adopted FlexBool `json:"adopted"` - Serial string `json:"serial"` - IP string `json:"ip"` - Uptime FlexInt `json:"uptime"` - Model string `json:"model"` - Version string `json:"version"` - Name string `json:"name"` - Default FlexBool `json:"default"` - Locating FlexBool `json:"locating"` - Type string `json:"type"` - Unsupported FlexBool `json:"unsupported"` - UnsupportedReason FlexInt `json:"unsupported_reason"` - DiscoveredVia string `json:"discovered_via"` - AdoptIP string `json:"adopt_ip"` - AdoptURL string `json:"adopt_url"` - State FlexInt `json:"state"` - AdoptStatus FlexInt `json:"adopt_status"` - UpgradeState FlexInt `json:"upgrade_state"` - LastSeen FlexInt `json:"last_seen"` - AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` - Cfgversion string `json:"cfgversion"` - ConfigNetwork struct { - Type string `json:"type"` - IP string `json:"ip"` - } `json:"config_network"` - VwireTable []interface{} `json:"vwire_table"` - Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"` - JumboframeEnabled FlexBool `json:"jumboframe_enabled"` - FlowctrlEnabled FlexBool `json:"flowctrl_enabled"` - StpVersion string `json:"stp_version"` - StpPriority string `json:"stp_priority"` - PowerSourceCtrlEnabled FlexBool `json:"power_source_ctrl_enabled"` - LicenseState string `json:"license_state"` - ID string `json:"_id"` - DeviceID string `json:"device_id"` - AdoptState FlexInt `json:"adopt_state"` - AdoptTries FlexInt `json:"adopt_tries"` - AdoptManual FlexBool `json:"adopt_manual"` - InformURL string `json:"inform_url"` - InformIP string `json:"inform_ip"` - RequiredVersion string `json:"required_version"` - BoardRev FlexInt `json:"board_rev"` - EthernetTable []struct { - Mac string `json:"mac"` - NumPort FlexInt `json:"num_port"` - Name string `json:"name"` - } `json:"ethernet_table"` - PortTable []Port `json:"port_table"` - EthernetOverrides []struct { - Ifname string `json:"ifname"` - Networkgroup string `json:"networkgroup"` - } `json:"ethernet_overrides"` - UsgCaps FlexInt `json:"usg_caps"` - HasSpeaker FlexBool `json:"has_speaker"` - HasEth1 FlexBool `json:"has_eth1"` - FwCaps FlexInt `json:"fw_caps"` - HwCaps FlexInt `json:"hw_caps"` - SwitchCaps struct { - MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` - MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` - } `json:"switch_caps"` - HasFan FlexBool `json:"has_fan"` - HasTemperature FlexBool `json:"has_temperature"` - RulesetInterfaces struct { - Br0 string `json:"br0"` - Eth8 string `json:"eth8"` - Eth9 string `json:"eth9"` - } `json:"ruleset_interfaces"` - KnownCfgversion string `json:"known_cfgversion"` - SysStats SysStats `json:"sys_stats"` - SystemStats SystemStats `json:"system-stats"` - GuestToken string `json:"guest_token"` - Overheating FlexBool `json:"overheating"` - SpeedtestStatus SpeedtestStatus `json:"speedtest-status"` - SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"` - Wan1 Wan `json:"wan1"` - Wan2 Wan `json:"wan2"` - Uplink Uplink `json:"uplink"` - ConnectRequestIP string `json:"connect_request_ip"` - ConnectRequestPort string `json:"connect_request_port"` - DownlinkTable []interface{} `json:"downlink_table"` - NetworkTable []struct { - ID string `json:"_id"` - AttrNoDelete FlexBool `json:"attr_no_delete"` - AttrHiddenID string `json:"attr_hidden_id"` - Name string `json:"name"` - SiteID string `json:"site_id"` - VlanEnabled FlexBool `json:"vlan_enabled"` - Purpose string `json:"purpose"` - IPSubnet string `json:"ip_subnet"` - Ipv6InterfaceType string `json:"ipv6_interface_type"` - DomainName string `json:"domain_name"` - IsNat FlexBool `json:"is_nat"` - DhcpdEnabled FlexBool `json:"dhcpd_enabled"` - DhcpdStart string `json:"dhcpd_start"` - DhcpdStop string `json:"dhcpd_stop"` - Dhcpdv6Enabled FlexBool `json:"dhcpdv6_enabled"` - Ipv6RaEnabled FlexBool `json:"ipv6_ra_enabled"` - LteLanEnabled FlexBool `json:"lte_lan_enabled"` - Networkgroup string `json:"networkgroup"` - DhcpdLeasetime FlexInt `json:"dhcpd_leasetime"` - DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"` - DhcpdGatewayEnabled FlexBool `json:"dhcpd_gateway_enabled"` - DhcpdTimeOffsetEnabled FlexBool `json:"dhcpd_time_offset_enabled"` - Ipv6PdStart string `json:"ipv6_pd_start"` - Ipv6PdStop string `json:"ipv6_pd_stop"` - DhcpdDNS1 string `json:"dhcpd_dns_1"` - DhcpdDNS2 string `json:"dhcpd_dns_2"` - DhcpdDNS3 string `json:"dhcpd_dns_3"` - DhcpdDNS4 string `json:"dhcpd_dns_4"` - Enabled FlexBool `json:"enabled"` - DhcpRelayEnabled FlexBool `json:"dhcp_relay_enabled"` - Mac string `json:"mac"` - IsGuest FlexBool `json:"is_guest"` - IP string `json:"ip"` - Up FlexBool `json:"up"` - DpistatsTable struct { - LastUpdated FlexInt `json:"last_updated"` - ByCat []struct { - Cat FlexInt `json:"cat"` - Apps []FlexInt `json:"apps"` - RxBytes FlexInt `json:"rx_bytes"` - TxBytes FlexInt `json:"tx_bytes"` - RxPackets FlexInt `json:"rx_packets"` - TxPackets FlexInt `json:"tx_packets"` - } `json:"by_cat"` - ByApp []struct { - App FlexInt `json:"app"` - Cat FlexInt `json:"cat"` - Clients []struct { - Mac string `json:"mac"` - RxBytes FlexInt `json:"rx_bytes"` - TxBytes FlexInt `json:"tx_bytes"` - RxPackets FlexInt `json:"rx_packets"` - TxPackets FlexInt `json:"tx_packets"` - } `json:"clients"` - KnownClients FlexInt `json:"known_clients"` - RxBytes FlexInt `json:"rx_bytes"` - TxBytes FlexInt `json:"tx_bytes"` - RxPackets FlexInt `json:"rx_packets"` - TxPackets FlexInt `json:"tx_packets"` - } `json:"by_app"` - } `json:"dpistats_table,omitempty"` - NumSta FlexInt `json:"num_sta"` - RxBytes FlexInt `json:"rx_bytes"` - RxPackets FlexInt `json:"rx_packets"` - TxBytes FlexInt `json:"tx_bytes"` - TxPackets FlexInt `json:"tx_packets"` - } `json:"network_table"` - PortOverrides []struct { - PortIdx FlexInt `json:"port_idx"` - PortconfID string `json:"portconf_id"` - } `json:"port_overrides"` - Stat UDMStat `json:"stat"` - TxBytes FlexInt `json:"tx_bytes"` - RxBytes FlexInt `json:"rx_bytes"` - Bytes FlexInt `json:"bytes"` - NumSta FlexInt `json:"num_sta"` - WlanNumSta FlexInt `json:"wlan-num_sta"` - LanNumSta FlexInt `json:"lan-num_sta"` - UserWlanNumSta FlexInt `json:"user-wlan-num_sta"` - UserLanNumSta FlexInt `json:"user-lan-num_sta"` - UserNumSta FlexInt `json:"user-num_sta"` - GuestWlanNumSta FlexInt `json:"guest-wlan-num_sta"` - GuestLanNumSta FlexInt `json:"guest-lan-num_sta"` - GuestNumSta FlexInt `json:"guest-num_sta"` - NumDesktop FlexInt `json:"num_desktop"` - NumMobile FlexInt `json:"num_mobile"` - NumHandheld FlexInt `json:"num_handheld"` -} - -// UDMStat holds the "stat" data for a dream machine. -// A dream machine is a USG + USW + Controller -type UDMStat struct { - *Gw `json:"gw"` - *Sw `json:"sw"` -} diff --git a/core/unifi/usg_type.go b/core/unifi/usg.go similarity index 77% rename from core/unifi/usg_type.go rename to core/unifi/usg.go index 5db8db43..d5cc7a21 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg.go @@ -84,58 +84,18 @@ type USG struct { DNS []string `json:"dns,omitempty"` Gateway string `json:"gateway,omitempty"` } `json:"port_table"` - NetworkTable []struct { - ID string `json:"_id"` - IsNat FlexBool `json:"is_nat"` - DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"` - Purpose string `json:"purpose"` - DhcpdLeasetime FlexInt `json:"dhcpd_leasetime"` - IgmpSnooping FlexBool `json:"igmp_snooping"` - DhcpguardEnabled FlexBool `json:"dhcpguard_enabled,omitempty"` - DhcpdStart string `json:"dhcpd_start"` - Enabled FlexBool `json:"enabled"` - DhcpdStop string `json:"dhcpd_stop"` - DhcpdWinsEnabled FlexBool `json:"dhcpd_wins_enabled,omitempty"` - DomainName string `json:"domain_name"` - DhcpdEnabled FlexBool `json:"dhcpd_enabled"` - IPSubnet string `json:"ip_subnet"` - Vlan FlexInt `json:"vlan,omitempty"` - Networkgroup string `json:"networkgroup"` - Name string `json:"name"` - SiteID string `json:"site_id"` - DhcpdIP1 string `json:"dhcpd_ip_1,omitempty"` - VlanEnabled FlexBool `json:"vlan_enabled"` - DhcpdGatewayEnabled FlexBool `json:"dhcpd_gateway_enabled"` - DhcpdTimeOffsetEnabled FlexBool `json:"dhcpd_time_offset_enabled"` - Ipv6InterfaceType string `json:"ipv6_interface_type"` - DhcpRelayEnabled FlexBool `json:"dhcp_relay_enabled"` - Mac string `json:"mac"` - IsGuest FlexBool `json:"is_guest"` - IP string `json:"ip"` - Up FlexBool `json:"up"` - NumSta FlexInt `json:"num_sta"` - RxBytes FlexInt `json:"rx_bytes"` - RxPackets FlexInt `json:"rx_packets"` - TxBytes FlexInt `json:"tx_bytes"` - TxPackets FlexInt `json:"tx_packets"` - DhcpdNtp1 string `json:"dhcpd_ntp_1,omitempty"` - DhcpdNtpEnabled FlexBool `json:"dhcpd_ntp_enabled,omitempty"` - DhcpdUnifiController string `json:"dhcpd_unifi_controller,omitempty"` - UpnpLanEnabled FlexBool `json:"upnp_lan_enabled,omitempty"` - AttrNoDelete FlexBool `json:"attr_no_delete,omitempty"` - AttrHiddenID string `json:"attr_hidden_id,omitempty"` - } `json:"network_table"` - Uplink Uplink `json:"uplink"` - Stat USGStat `json:"stat"` - TxBytes FlexInt `json:"tx_bytes"` - RxBytes FlexInt `json:"rx_bytes"` - Bytes FlexInt `json:"bytes"` - NumSta FlexInt `json:"num_sta"` - UserNumSta FlexInt `json:"user-num_sta"` - GuestNumSta FlexInt `json:"guest-num_sta"` - NumDesktop FlexInt `json:"num_desktop"` - NumMobile FlexInt `json:"num_mobile"` - NumHandheld FlexInt `json:"num_handheld"` + NetworkTable NetworkTable `json:"network_table"` + Uplink Uplink `json:"uplink"` + Stat USGStat `json:"stat"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + NumSta FlexInt `json:"num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` + NumDesktop FlexInt `json:"num_desktop"` + NumMobile FlexInt `json:"num_mobile"` + NumHandheld FlexInt `json:"num_handheld"` } // Uplink is the Internet connection (or uplink) on a UniFi device. diff --git a/core/unifi/usg_type_test.go b/core/unifi/usg_test.go similarity index 100% rename from core/unifi/usg_type_test.go rename to core/unifi/usg_test.go diff --git a/core/unifi/usw.go b/core/unifi/usw.go new file mode 100644 index 00000000..62a5cd48 --- /dev/null +++ b/core/unifi/usw.go @@ -0,0 +1,373 @@ +package unifi + +import ( + "encoding/json" + "time" +) + +// USW represents all the data from the Ubiquiti Controller for a Unifi Switch. +type USW struct { + SiteName string `json:"-"` + ID string `json:"_id"` + Adopted FlexBool `json:"adopted"` + BoardRev FlexInt `json:"board_rev"` + Cfgversion string `json:"cfgversion"` + ConfigNetwork struct { + Type string `json:"type"` + IP string `json:"ip"` + } `json:"config_network"` + Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"` + EthernetTable []struct { + Mac string `json:"mac"` + NumPort FlexInt `json:"num_port,omitempty"` + Name string `json:"name"` + } `json:"ethernet_table"` + FlowctrlEnabled FlexBool `json:"flowctrl_enabled"` + FwCaps FlexInt `json:"fw_caps"` + HasFan FlexBool `json:"has_fan"` + HasTemperature FlexBool `json:"has_temperature"` + InformIP string `json:"inform_ip"` + InformURL string `json:"inform_url"` + IP string `json:"ip"` + JumboframeEnabled FlexBool `json:"jumboframe_enabled"` + LedOverride string `json:"led_override"` + LicenseState string `json:"license_state"` + Mac string `json:"mac"` + Model string `json:"model"` + Name string `json:"name"` + OutdoorModeOverride string `json:"outdoor_mode_override"` + PortOverrides []struct { + Name string `json:"name,omitempty"` + PoeMode string `json:"poe_mode,omitempty"` + PortIdx FlexInt `json:"port_idx"` + PortconfID string `json:"portconf_id"` + } `json:"port_overrides"` + PortTable []Port `json:"port_table"` + Serial string `json:"serial"` + SiteID string `json:"site_id"` + StpPriority string `json:"stp_priority"` + StpVersion string `json:"stp_version"` + Type string `json:"type"` + Version string `json:"version"` + RequiredVersion string `json:"required_version"` + SwitchCaps struct { + FeatureCaps FlexInt `json:"feature_caps"` + MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` + MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` + } `json:"switch_caps"` + HwCaps FlexInt `json:"hw_caps"` + Unsupported FlexBool `json:"unsupported"` + UnsupportedReason FlexInt `json:"unsupported_reason"` + SysErrorCaps FlexInt `json:"sys_error_caps"` + DeviceID string `json:"device_id"` + State FlexInt `json:"state"` + LastSeen FlexInt `json:"last_seen"` + Upgradable FlexBool `json:"upgradable,omitempty"` + AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded,omitempty"` + Rollupgrade FlexBool `json:"rollupgrade,omitempty"` + KnownCfgversion string `json:"known_cfgversion"` + Uptime FlexInt `json:"uptime"` + Locating FlexBool `json:"locating"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + SysStats SysStats `json:"sys_stats"` + SystemStats SystemStats `json:"system-stats"` + FanLevel FlexInt `json:"fan_level"` + GeneralTemperature FlexInt `json:"general_temperature"` + Overheating FlexBool `json:"overheating"` + TotalMaxPower FlexInt `json:"total_max_power"` + DownlinkTable []struct { + PortIdx FlexInt `json:"port_idx"` + Speed FlexInt `json:"speed"` + FullDuplex FlexBool `json:"full_duplex"` + Mac string `json:"mac"` + } `json:"downlink_table"` + Uplink Uplink `json:"uplink"` + LastUplink struct { + UplinkMac string `json:"uplink_mac"` + } `json:"last_uplink"` + UplinkDepth FlexInt `json:"uplink_depth"` + Stat USWStat `json:"stat"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + NumSta FlexInt `json:"num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` +} + +// Port is a physical connection on a USW or UDM. +type Port struct { + AggregatedBy FlexBool `json:"aggregated_by"` + Autoneg FlexBool `json:"autoneg,omitempty"` + BytesR FlexInt `json:"bytes-r"` + DNS []string `json:"dns,omitempty"` + Dot1XMode string `json:"dot1x_mode"` + Dot1XStatus string `json:"dot1x_status"` + Enable FlexBool `json:"enable"` + FlowctrlRx FlexBool `json:"flowctrl_rx"` + FlowctrlTx FlexBool `json:"flowctrl_tx"` + FullDuplex FlexBool `json:"full_duplex"` + IP string `json:"ip,omitempty"` + Ifname string `json:"ifname,omitempty"` + IsUplink FlexBool `json:"is_uplink"` + Mac string `json:"mac,omitempty"` + Jumbo FlexBool `json:"jumbo,omitempty"` + Masked FlexBool `json:"masked"` + Media string `json:"media"` + Name string `json:"name"` + NetworkName string `json:"network_name,omitempty"` + NumPort int `json:"num_port,omitempty"` + OpMode string `json:"op_mode"` + PoeCaps FlexInt `json:"poe_caps"` + PoeClass string `json:"poe_class,omitempty"` + PoeCurrent FlexInt `json:"poe_current,omitempty"` + PoeEnable FlexBool `json:"poe_enable,omitempty"` + PoeGood FlexBool `json:"poe_good,omitempty"` + PoeMode string `json:"poe_mode,omitempty"` + PoePower FlexInt `json:"poe_power,omitempty"` + PoeVoltage FlexInt `json:"poe_voltage,omitempty"` + PortDelta struct { + TimeDelta int64 `json:"time_delta"` + } `json:"port_delta,omitempty"` + PortIdx FlexInt `json:"port_idx"` + PortPoe FlexBool `json:"port_poe"` + PortconfID string `json:"portconf_id"` + RxBroadcast FlexInt `json:"rx_broadcast"` + RxBytes FlexInt `json:"rx_bytes"` + RxBytesR FlexInt `json:"rx_bytes-r"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxMulticast FlexInt `json:"rx_multicast"` + RxPackets FlexInt `json:"rx_packets"` + Satisfaction FlexInt `json:"satisfaction,omitempty"` + SfpFound FlexBool `json:"sfp_found,omitempty"` + Speed FlexInt `json:"speed"` + SpeedCaps FlexInt `json:"speed_caps"` + StpPathcost FlexInt `json:"stp_pathcost"` + StpState string `json:"stp_state"` + TxBroadcast FlexInt `json:"tx_broadcast"` + TxBytes FlexInt `json:"tx_bytes"` + TxBytesR FlexInt `json:"tx_bytes-r"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxMulticast FlexInt `json:"tx_multicast"` + TxPackets FlexInt `json:"tx_packets"` + Type string `json:"type,omitempty"` + Up FlexBool `json:"up"` +} + +// USWStat holds the "stat" data for a switch. +// This is split out because of a JSON data format change from 5.10 to 5.11. +type USWStat struct { + *Sw +} + +// Sw is a subtype of USWStat to make unmarshalling of different controller versions possible. +type Sw struct { + SiteID string `json:"site_id"` + O string `json:"o"` + Oid string `json:"oid"` + Sw string `json:"sw"` + Time FlexInt `json:"time"` + Datetime time.Time `json:"datetime"` + RxPackets FlexInt `json:"rx_packets"` + RxBytes FlexInt `json:"rx_bytes"` + RxErrors FlexInt `json:"rx_errors"` + RxDropped FlexInt `json:"rx_dropped"` + RxCrypts FlexInt `json:"rx_crypts"` + RxFrags FlexInt `json:"rx_frags"` + TxPackets FlexInt `json:"tx_packets"` + TxBytes FlexInt `json:"tx_bytes"` + TxErrors FlexInt `json:"tx_errors"` + TxDropped FlexInt `json:"tx_dropped"` + TxRetries FlexInt `json:"tx_retries"` + RxMulticast FlexInt `json:"rx_multicast"` + RxBroadcast FlexInt `json:"rx_broadcast"` + TxMulticast FlexInt `json:"tx_multicast"` + TxBroadcast FlexInt `json:"tx_broadcast"` + Bytes FlexInt `json:"bytes"` + Duration FlexInt `json:"duration"` + /* These are all in port table */ + /* + Port1RxPackets FlexInt `json:"port_1-rx_packets,omitempty"` + Port1RxBytes FlexInt `json:"port_1-rx_bytes,omitempty"` + Port1TxPackets FlexInt `json:"port_1-tx_packets,omitempty"` + Port1TxBytes FlexInt `json:"port_1-tx_bytes,omitempty"` + Port1TxMulticast FlexInt `json:"port_1-tx_multicast"` + Port1TxBroadcast FlexInt `json:"port_1-tx_broadcast"` + Port3RxPackets FlexInt `json:"port_3-rx_packets,omitempty"` + Port3RxBytes FlexInt `json:"port_3-rx_bytes,omitempty"` + Port3TxPackets FlexInt `json:"port_3-tx_packets,omitempty"` + Port3TxBytes FlexInt `json:"port_3-tx_bytes,omitempty"` + Port3RxBroadcast FlexInt `json:"port_3-rx_broadcast"` + Port3TxMulticast FlexInt `json:"port_3-tx_multicast"` + Port3TxBroadcast FlexInt `json:"port_3-tx_broadcast"` + Port6RxPackets FlexInt `json:"port_6-rx_packets,omitempty"` + Port6RxBytes FlexInt `json:"port_6-rx_bytes,omitempty"` + Port6TxPackets FlexInt `json:"port_6-tx_packets,omitempty"` + Port6TxBytes FlexInt `json:"port_6-tx_bytes,omitempty"` + Port6RxMulticast FlexInt `json:"port_6-rx_multicast"` + Port6TxMulticast FlexInt `json:"port_6-tx_multicast"` + Port6TxBroadcast FlexInt `json:"port_6-tx_broadcast"` + Port7RxPackets FlexInt `json:"port_7-rx_packets,omitempty"` + Port7RxBytes FlexInt `json:"port_7-rx_bytes,omitempty"` + Port7TxPackets FlexInt `json:"port_7-tx_packets,omitempty"` + Port7TxBytes FlexInt `json:"port_7-tx_bytes,omitempty"` + Port7TxMulticast FlexInt `json:"port_7-tx_multicast"` + Port7TxBroadcast FlexInt `json:"port_7-tx_broadcast"` + Port9RxPackets FlexInt `json:"port_9-rx_packets,omitempty"` + Port9RxBytes FlexInt `json:"port_9-rx_bytes,omitempty"` + Port9TxPackets FlexInt `json:"port_9-tx_packets,omitempty"` + Port9TxBytes FlexInt `json:"port_9-tx_bytes,omitempty"` + Port9TxMulticast FlexInt `json:"port_9-tx_multicast"` + Port9TxBroadcast FlexInt `json:"port_9-tx_broadcast"` + Port10RxPackets FlexInt `json:"port_10-rx_packets,omitempty"` + Port10RxBytes FlexInt `json:"port_10-rx_bytes,omitempty"` + Port10TxPackets FlexInt `json:"port_10-tx_packets,omitempty"` + Port10TxBytes FlexInt `json:"port_10-tx_bytes,omitempty"` + Port10RxMulticast FlexInt `json:"port_10-rx_multicast"` + Port10TxMulticast FlexInt `json:"port_10-tx_multicast"` + Port10TxBroadcast FlexInt `json:"port_10-tx_broadcast"` + Port11RxPackets FlexInt `json:"port_11-rx_packets,omitempty"` + Port11RxBytes FlexInt `json:"port_11-rx_bytes,omitempty"` + Port11TxPackets FlexInt `json:"port_11-tx_packets,omitempty"` + Port11TxBytes FlexInt `json:"port_11-tx_bytes,omitempty"` + Port11TxMulticast FlexInt `json:"port_11-tx_multicast"` + Port11TxBroadcast FlexInt `json:"port_11-tx_broadcast"` + Port12RxPackets FlexInt `json:"port_12-rx_packets,omitempty"` + Port12RxBytes FlexInt `json:"port_12-rx_bytes,omitempty"` + Port12TxPackets FlexInt `json:"port_12-tx_packets,omitempty"` + Port12TxBytes FlexInt `json:"port_12-tx_bytes,omitempty"` + Port12TxMulticast FlexInt `json:"port_12-tx_multicast"` + Port12TxBroadcast FlexInt `json:"port_12-tx_broadcast"` + Port13RxPackets FlexInt `json:"port_13-rx_packets,omitempty"` + Port13RxBytes FlexInt `json:"port_13-rx_bytes,omitempty"` + Port13TxPackets FlexInt `json:"port_13-tx_packets,omitempty"` + Port13TxBytes FlexInt `json:"port_13-tx_bytes,omitempty"` + Port13RxMulticast FlexInt `json:"port_13-rx_multicast"` + Port13RxBroadcast FlexInt `json:"port_13-rx_broadcast"` + Port13TxMulticast FlexInt `json:"port_13-tx_multicast"` + Port13TxBroadcast FlexInt `json:"port_13-tx_broadcast"` + Port15RxPackets FlexInt `json:"port_15-rx_packets,omitempty"` + Port15RxBytes FlexInt `json:"port_15-rx_bytes,omitempty"` + Port15TxPackets FlexInt `json:"port_15-tx_packets,omitempty"` + Port15TxBytes FlexInt `json:"port_15-tx_bytes,omitempty"` + Port15RxBroadcast FlexInt `json:"port_15-rx_broadcast"` + Port15TxMulticast FlexInt `json:"port_15-tx_multicast"` + Port15TxBroadcast FlexInt `json:"port_15-tx_broadcast"` + Port16RxPackets FlexInt `json:"port_16-rx_packets,omitempty"` + Port16RxBytes FlexInt `json:"port_16-rx_bytes,omitempty"` + Port16TxPackets FlexInt `json:"port_16-tx_packets,omitempty"` + Port16TxBytes FlexInt `json:"port_16-tx_bytes,omitempty"` + Port16TxMulticast FlexInt `json:"port_16-tx_multicast"` + Port16TxBroadcast FlexInt `json:"port_16-tx_broadcast"` + Port17RxPackets FlexInt `json:"port_17-rx_packets,omitempty"` + Port17RxBytes FlexInt `json:"port_17-rx_bytes,omitempty"` + Port17TxPackets FlexInt `json:"port_17-tx_packets,omitempty"` + Port17TxBytes FlexInt `json:"port_17-tx_bytes,omitempty"` + Port17TxMulticast FlexInt `json:"port_17-tx_multicast"` + Port17TxBroadcast FlexInt `json:"port_17-tx_broadcast"` + Port18RxPackets FlexInt `json:"port_18-rx_packets,omitempty"` + Port18RxBytes FlexInt `json:"port_18-rx_bytes,omitempty"` + Port18TxPackets FlexInt `json:"port_18-tx_packets,omitempty"` + Port18TxBytes FlexInt `json:"port_18-tx_bytes,omitempty"` + Port18RxMulticast FlexInt `json:"port_18-rx_multicast"` + Port18TxMulticast FlexInt `json:"port_18-tx_multicast"` + Port18TxBroadcast FlexInt `json:"port_18-tx_broadcast"` + Port19RxPackets FlexInt `json:"port_19-rx_packets,omitempty"` + Port19RxBytes FlexInt `json:"port_19-rx_bytes,omitempty"` + Port19TxPackets FlexInt `json:"port_19-tx_packets,omitempty"` + Port19TxBytes FlexInt `json:"port_19-tx_bytes,omitempty"` + Port19TxMulticast FlexInt `json:"port_19-tx_multicast"` + Port19TxBroadcast FlexInt `json:"port_19-tx_broadcast"` + Port21RxPackets FlexInt `json:"port_21-rx_packets,omitempty"` + Port21RxBytes FlexInt `json:"port_21-rx_bytes,omitempty"` + Port21TxPackets FlexInt `json:"port_21-tx_packets,omitempty"` + Port21TxBytes FlexInt `json:"port_21-tx_bytes,omitempty"` + Port21RxBroadcast FlexInt `json:"port_21-rx_broadcast"` + Port21TxMulticast FlexInt `json:"port_21-tx_multicast"` + Port21TxBroadcast FlexInt `json:"port_21-tx_broadcast"` + Port22RxPackets FlexInt `json:"port_22-rx_packets,omitempty"` + Port22RxBytes FlexInt `json:"port_22-rx_bytes,omitempty"` + Port22TxPackets FlexInt `json:"port_22-tx_packets,omitempty"` + Port22TxBytes FlexInt `json:"port_22-tx_bytes,omitempty"` + Port22RxMulticast FlexInt `json:"port_22-rx_multicast"` + Port22TxMulticast FlexInt `json:"port_22-tx_multicast"` + Port22TxBroadcast FlexInt `json:"port_22-tx_broadcast"` + Port23RxPackets FlexInt `json:"port_23-rx_packets,omitempty"` + Port23RxBytes FlexInt `json:"port_23-rx_bytes,omitempty"` + Port23RxDropped FlexInt `json:"port_23-rx_dropped"` + Port23TxPackets FlexInt `json:"port_23-tx_packets,omitempty"` + Port23TxBytes FlexInt `json:"port_23-tx_bytes,omitempty"` + Port23RxMulticast FlexInt `json:"port_23-rx_multicast"` + Port23RxBroadcast FlexInt `json:"port_23-rx_broadcast"` + Port23TxMulticast FlexInt `json:"port_23-tx_multicast"` + Port23TxBroadcast FlexInt `json:"port_23-tx_broadcast"` + Port24RxPackets FlexInt `json:"port_24-rx_packets,omitempty"` + Port24RxBytes FlexInt `json:"port_24-rx_bytes,omitempty"` + Port24TxPackets FlexInt `json:"port_24-tx_packets,omitempty"` + Port24TxBytes FlexInt `json:"port_24-tx_bytes,omitempty"` + Port24RxMulticast FlexInt `json:"port_24-rx_multicast"` + Port24TxMulticast FlexInt `json:"port_24-tx_multicast"` + Port24TxBroadcast FlexInt `json:"port_24-tx_broadcast"` + Port1RxMulticast FlexInt `json:"port_1-rx_multicast"` + Port3RxDropped FlexInt `json:"port_3-rx_dropped"` + Port3RxMulticast FlexInt `json:"port_3-rx_multicast"` + Port6RxDropped FlexInt `json:"port_6-rx_dropped"` + Port7RxDropped FlexInt `json:"port_7-rx_dropped"` + Port7RxMulticast FlexInt `json:"port_7-rx_multicast"` + Port9RxDropped FlexInt `json:"port_9-rx_dropped"` + Port9RxMulticast FlexInt `json:"port_9-rx_multicast"` + Port9RxBroadcast FlexInt `json:"port_9-rx_broadcast"` + Port10RxBroadcast FlexInt `json:"port_10-rx_broadcast"` + Port12RxDropped FlexInt `json:"port_12-rx_dropped"` + Port12RxMulticast FlexInt `json:"port_12-rx_multicast"` + Port13RxDropped FlexInt `json:"port_13-rx_dropped"` + Port17RxDropped FlexInt `json:"port_17-rx_dropped"` + Port17RxMulticast FlexInt `json:"port_17-rx_multicast"` + Port17RxBroadcast FlexInt `json:"port_17-rx_broadcast"` + Port19RxDropped FlexInt `json:"port_19-rx_dropped"` + Port19RxMulticast FlexInt `json:"port_19-rx_multicast"` + Port19RxBroadcast FlexInt `json:"port_19-rx_broadcast"` + Port21RxDropped FlexInt `json:"port_21-rx_dropped"` + Port21RxMulticast FlexInt `json:"port_21-rx_multicast"` + Port7RxBroadcast FlexInt `json:"port_7-rx_broadcast"` + Port18RxBroadcast FlexInt `json:"port_18-rx_broadcast"` + Port16RxMulticast FlexInt `json:"port_16-rx_multicast"` + Port15RxDropped FlexInt `json:"port_15-rx_dropped"` + Port15RxMulticast FlexInt `json:"port_15-rx_multicast"` + Port16RxBroadcast FlexInt `json:"port_16-rx_broadcast"` + Port11RxBroadcast FlexInt `json:"port_11-rx_broadcast"` + Port12RxBroadcast FlexInt `json:"port_12-rx_broadcast"` + Port6RxBroadcast FlexInt `json:"port_6-rx_broadcast"` + Port24RxBroadcast FlexInt `json:"port_24-rx_broadcast"` + Port22RxBroadcast FlexInt `json:"port_22-rx_broadcast"` + Port10TxDropped FlexInt `json:"port_10-tx_dropped"` + Port16TxDropped FlexInt `json:"port_16-tx_dropped"` + Port1RxBroadcast FlexInt `json:"port_1-rx_broadcast"` + Port4RxPackets FlexInt `json:"port_4-rx_packets,omitempty"` + Port4RxBytes FlexInt `json:"port_4-rx_bytes,omitempty"` + Port4RxDropped FlexInt `json:"port_4-rx_dropped"` + Port4TxPackets FlexInt `json:"port_4-tx_packets,omitempty"` + Port4TxBytes FlexInt `json:"port_4-tx_bytes,omitempty"` + Port4TxDropped FlexInt `json:"port_4-tx_dropped"` + Port4RxMulticast FlexInt `json:"port_4-rx_multicast"` + Port4RxBroadcast FlexInt `json:"port_4-rx_broadcast"` + Port4TxMulticast FlexInt `json:"port_4-tx_multicast"` + Port4TxBroadcast FlexInt `json:"port_4-tx_broadcast"` + */ +} + +// UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Switch Stat data. +func (v *USWStat) UnmarshalJSON(data []byte) error { + var n struct { + Sw `json:"sw"` + } + v.Sw = &n.Sw + err := json.Unmarshal(data, v.Sw) // controller version 5.10. + if err != nil { + return json.Unmarshal(data, &n) // controller version 5.11. + } + return nil +} diff --git a/core/unifi/usw_type_test.go b/core/unifi/usw_test.go similarity index 100% rename from core/unifi/usw_type_test.go rename to core/unifi/usw_test.go diff --git a/core/unifi/usw_type.go b/core/unifi/usw_type.go deleted file mode 100644 index 04b4c070..00000000 --- a/core/unifi/usw_type.go +++ /dev/null @@ -1,370 +0,0 @@ -package unifi - -import ( - "encoding/json" - "time" -) - -// USW represents all the data from the Ubiquiti Controller for a Unifi Switch. -type USW struct { - SiteName string `json:"-"` - ID string `json:"_id"` - Adopted FlexBool `json:"adopted"` - BoardRev FlexInt `json:"board_rev"` - Cfgversion string `json:"cfgversion"` - ConfigNetwork struct { - Type string `json:"type"` - IP string `json:"ip"` - } `json:"config_network"` - Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"` - EthernetTable []struct { - Mac string `json:"mac"` - NumPort FlexInt `json:"num_port,omitempty"` - Name string `json:"name"` - } `json:"ethernet_table"` - FlowctrlEnabled FlexBool `json:"flowctrl_enabled"` - FwCaps FlexInt `json:"fw_caps"` - HasFan FlexBool `json:"has_fan"` - HasTemperature FlexBool `json:"has_temperature"` - InformIP string `json:"inform_ip"` - InformURL string `json:"inform_url"` - IP string `json:"ip"` - JumboframeEnabled FlexBool `json:"jumboframe_enabled"` - LedOverride string `json:"led_override"` - LicenseState string `json:"license_state"` - Mac string `json:"mac"` - Model string `json:"model"` - Name string `json:"name"` - OutdoorModeOverride string `json:"outdoor_mode_override"` - PortOverrides []struct { - Name string `json:"name,omitempty"` - PoeMode string `json:"poe_mode,omitempty"` - PortIdx FlexInt `json:"port_idx"` - PortconfID string `json:"portconf_id"` - } `json:"port_overrides"` - PortTable []Port `json:"port_table"` - Serial string `json:"serial"` - SiteID string `json:"site_id"` - StpPriority string `json:"stp_priority"` - StpVersion string `json:"stp_version"` - Type string `json:"type"` - Version string `json:"version"` - RequiredVersion string `json:"required_version"` - SwitchCaps struct { - FeatureCaps FlexInt `json:"feature_caps"` - MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` - MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` - } `json:"switch_caps"` - HwCaps FlexInt `json:"hw_caps"` - Unsupported FlexBool `json:"unsupported"` - UnsupportedReason FlexInt `json:"unsupported_reason"` - SysErrorCaps FlexInt `json:"sys_error_caps"` - DeviceID string `json:"device_id"` - State FlexInt `json:"state"` - LastSeen FlexInt `json:"last_seen"` - Upgradable FlexBool `json:"upgradable,omitempty"` - AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded,omitempty"` - Rollupgrade FlexBool `json:"rollupgrade,omitempty"` - KnownCfgversion string `json:"known_cfgversion"` - Uptime FlexInt `json:"uptime"` - Locating FlexBool `json:"locating"` - ConnectRequestIP string `json:"connect_request_ip"` - ConnectRequestPort string `json:"connect_request_port"` - SysStats SysStats `json:"sys_stats"` - SystemStats SystemStats `json:"system-stats"` - FanLevel FlexInt `json:"fan_level"` - GeneralTemperature FlexInt `json:"general_temperature"` - Overheating FlexBool `json:"overheating"` - TotalMaxPower FlexInt `json:"total_max_power"` - DownlinkTable []struct { - PortIdx FlexInt `json:"port_idx"` - Speed FlexInt `json:"speed"` - FullDuplex FlexBool `json:"full_duplex"` - Mac string `json:"mac"` - } `json:"downlink_table"` - Uplink Uplink `json:"uplink"` - LastUplink struct { - UplinkMac string `json:"uplink_mac"` - } `json:"last_uplink"` - UplinkDepth FlexInt `json:"uplink_depth"` - Stat USWStat `json:"stat"` - TxBytes FlexInt `json:"tx_bytes"` - RxBytes FlexInt `json:"rx_bytes"` - Bytes FlexInt `json:"bytes"` - NumSta FlexInt `json:"num_sta"` - UserNumSta FlexInt `json:"user-num_sta"` - GuestNumSta FlexInt `json:"guest-num_sta"` -} - -// Port is a physical connection on a USW or UDM. -type Port struct { - AggregatedBy FlexBool `json:"aggregated_by"` - Autoneg FlexBool `json:"autoneg,omitempty"` - BytesR FlexInt `json:"bytes-r"` - DNS []string `json:"dns,omitempty"` - Dot1XMode string `json:"dot1x_mode"` - Dot1XStatus string `json:"dot1x_status"` - Enable FlexBool `json:"enable"` - FlowctrlRx FlexBool `json:"flowctrl_rx"` - FlowctrlTx FlexBool `json:"flowctrl_tx"` - FullDuplex FlexBool `json:"full_duplex"` - IP string `json:"ip,omitempty"` - Ifname string `json:"ifname,omitempty"` - IsUplink FlexBool `json:"is_uplink"` - Mac string `json:"mac,omitempty"` - Jumbo FlexBool `json:"jumbo,omitempty"` - Masked FlexBool `json:"masked"` - Media string `json:"media"` - Name string `json:"name"` - NetworkName string `json:"network_name,omitempty"` - NumPort int `json:"num_port,omitempty"` - OpMode string `json:"op_mode"` - PoeCaps FlexInt `json:"poe_caps"` - PoeClass string `json:"poe_class,omitempty"` - PoeCurrent FlexInt `json:"poe_current,omitempty"` - PoeEnable FlexBool `json:"poe_enable,omitempty"` - PoeGood FlexBool `json:"poe_good,omitempty"` - PoeMode string `json:"poe_mode,omitempty"` - PoePower FlexInt `json:"poe_power,omitempty"` - PoeVoltage FlexInt `json:"poe_voltage,omitempty"` - PortDelta struct { - TimeDelta int64 `json:"time_delta"` - } `json:"port_delta,omitempty"` - PortIdx FlexInt `json:"port_idx"` - PortPoe FlexBool `json:"port_poe"` - PortconfID string `json:"portconf_id"` - RxBroadcast FlexInt `json:"rx_broadcast"` - RxBytes FlexInt `json:"rx_bytes"` - RxBytesR FlexInt `json:"rx_bytes-r"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxMulticast FlexInt `json:"rx_multicast"` - RxPackets FlexInt `json:"rx_packets"` - Satisfaction FlexInt `json:"satisfaction,omitempty"` - SfpFound FlexBool `json:"sfp_found,omitempty"` - Speed FlexInt `json:"speed"` - SpeedCaps FlexInt `json:"speed_caps"` - StpPathcost FlexInt `json:"stp_pathcost"` - StpState string `json:"stp_state"` - TxBroadcast FlexInt `json:"tx_broadcast"` - TxBytes FlexInt `json:"tx_bytes"` - TxBytesR FlexInt `json:"tx_bytes-r"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxMulticast FlexInt `json:"tx_multicast"` - TxPackets FlexInt `json:"tx_packets"` - Type string `json:"type,omitempty"` - Up FlexBool `json:"up"` -} - -// USWStat holds the "stat" data for a switch. -// This is split out because of a JSON data format change from 5.10 to 5.11. -type USWStat struct { - *Sw -} - -// Sw is a subtype of USWStat to make unmarshalling of different controller versions possible. -type Sw struct { - SiteID string `json:"site_id"` - O string `json:"o"` - Oid string `json:"oid"` - Sw string `json:"sw"` - Time FlexInt `json:"time"` - Datetime time.Time `json:"datetime"` - RxPackets FlexInt `json:"rx_packets"` - RxBytes FlexInt `json:"rx_bytes"` - RxErrors FlexInt `json:"rx_errors"` - RxDropped FlexInt `json:"rx_dropped"` - RxCrypts FlexInt `json:"rx_crypts"` - RxFrags FlexInt `json:"rx_frags"` - TxPackets FlexInt `json:"tx_packets"` - TxBytes FlexInt `json:"tx_bytes"` - TxErrors FlexInt `json:"tx_errors"` - TxDropped FlexInt `json:"tx_dropped"` - TxRetries FlexInt `json:"tx_retries"` - RxMulticast FlexInt `json:"rx_multicast"` - RxBroadcast FlexInt `json:"rx_broadcast"` - TxMulticast FlexInt `json:"tx_multicast"` - TxBroadcast FlexInt `json:"tx_broadcast"` - Bytes FlexInt `json:"bytes"` - Duration FlexInt `json:"duration"` - Port1RxPackets FlexInt `json:"port_1-rx_packets,omitempty"` - Port1RxBytes FlexInt `json:"port_1-rx_bytes,omitempty"` - Port1TxPackets FlexInt `json:"port_1-tx_packets,omitempty"` - Port1TxBytes FlexInt `json:"port_1-tx_bytes,omitempty"` - Port1TxMulticast FlexInt `json:"port_1-tx_multicast"` - Port1TxBroadcast FlexInt `json:"port_1-tx_broadcast"` - Port3RxPackets FlexInt `json:"port_3-rx_packets,omitempty"` - Port3RxBytes FlexInt `json:"port_3-rx_bytes,omitempty"` - Port3TxPackets FlexInt `json:"port_3-tx_packets,omitempty"` - Port3TxBytes FlexInt `json:"port_3-tx_bytes,omitempty"` - Port3RxBroadcast FlexInt `json:"port_3-rx_broadcast"` - Port3TxMulticast FlexInt `json:"port_3-tx_multicast"` - Port3TxBroadcast FlexInt `json:"port_3-tx_broadcast"` - Port6RxPackets FlexInt `json:"port_6-rx_packets,omitempty"` - Port6RxBytes FlexInt `json:"port_6-rx_bytes,omitempty"` - Port6TxPackets FlexInt `json:"port_6-tx_packets,omitempty"` - Port6TxBytes FlexInt `json:"port_6-tx_bytes,omitempty"` - Port6RxMulticast FlexInt `json:"port_6-rx_multicast"` - Port6TxMulticast FlexInt `json:"port_6-tx_multicast"` - Port6TxBroadcast FlexInt `json:"port_6-tx_broadcast"` - Port7RxPackets FlexInt `json:"port_7-rx_packets,omitempty"` - Port7RxBytes FlexInt `json:"port_7-rx_bytes,omitempty"` - Port7TxPackets FlexInt `json:"port_7-tx_packets,omitempty"` - Port7TxBytes FlexInt `json:"port_7-tx_bytes,omitempty"` - Port7TxMulticast FlexInt `json:"port_7-tx_multicast"` - Port7TxBroadcast FlexInt `json:"port_7-tx_broadcast"` - Port9RxPackets FlexInt `json:"port_9-rx_packets,omitempty"` - Port9RxBytes FlexInt `json:"port_9-rx_bytes,omitempty"` - Port9TxPackets FlexInt `json:"port_9-tx_packets,omitempty"` - Port9TxBytes FlexInt `json:"port_9-tx_bytes,omitempty"` - Port9TxMulticast FlexInt `json:"port_9-tx_multicast"` - Port9TxBroadcast FlexInt `json:"port_9-tx_broadcast"` - Port10RxPackets FlexInt `json:"port_10-rx_packets,omitempty"` - Port10RxBytes FlexInt `json:"port_10-rx_bytes,omitempty"` - Port10TxPackets FlexInt `json:"port_10-tx_packets,omitempty"` - Port10TxBytes FlexInt `json:"port_10-tx_bytes,omitempty"` - Port10RxMulticast FlexInt `json:"port_10-rx_multicast"` - Port10TxMulticast FlexInt `json:"port_10-tx_multicast"` - Port10TxBroadcast FlexInt `json:"port_10-tx_broadcast"` - Port11RxPackets FlexInt `json:"port_11-rx_packets,omitempty"` - Port11RxBytes FlexInt `json:"port_11-rx_bytes,omitempty"` - Port11TxPackets FlexInt `json:"port_11-tx_packets,omitempty"` - Port11TxBytes FlexInt `json:"port_11-tx_bytes,omitempty"` - Port11TxMulticast FlexInt `json:"port_11-tx_multicast"` - Port11TxBroadcast FlexInt `json:"port_11-tx_broadcast"` - Port12RxPackets FlexInt `json:"port_12-rx_packets,omitempty"` - Port12RxBytes FlexInt `json:"port_12-rx_bytes,omitempty"` - Port12TxPackets FlexInt `json:"port_12-tx_packets,omitempty"` - Port12TxBytes FlexInt `json:"port_12-tx_bytes,omitempty"` - Port12TxMulticast FlexInt `json:"port_12-tx_multicast"` - Port12TxBroadcast FlexInt `json:"port_12-tx_broadcast"` - Port13RxPackets FlexInt `json:"port_13-rx_packets,omitempty"` - Port13RxBytes FlexInt `json:"port_13-rx_bytes,omitempty"` - Port13TxPackets FlexInt `json:"port_13-tx_packets,omitempty"` - Port13TxBytes FlexInt `json:"port_13-tx_bytes,omitempty"` - Port13RxMulticast FlexInt `json:"port_13-rx_multicast"` - Port13RxBroadcast FlexInt `json:"port_13-rx_broadcast"` - Port13TxMulticast FlexInt `json:"port_13-tx_multicast"` - Port13TxBroadcast FlexInt `json:"port_13-tx_broadcast"` - Port15RxPackets FlexInt `json:"port_15-rx_packets,omitempty"` - Port15RxBytes FlexInt `json:"port_15-rx_bytes,omitempty"` - Port15TxPackets FlexInt `json:"port_15-tx_packets,omitempty"` - Port15TxBytes FlexInt `json:"port_15-tx_bytes,omitempty"` - Port15RxBroadcast FlexInt `json:"port_15-rx_broadcast"` - Port15TxMulticast FlexInt `json:"port_15-tx_multicast"` - Port15TxBroadcast FlexInt `json:"port_15-tx_broadcast"` - Port16RxPackets FlexInt `json:"port_16-rx_packets,omitempty"` - Port16RxBytes FlexInt `json:"port_16-rx_bytes,omitempty"` - Port16TxPackets FlexInt `json:"port_16-tx_packets,omitempty"` - Port16TxBytes FlexInt `json:"port_16-tx_bytes,omitempty"` - Port16TxMulticast FlexInt `json:"port_16-tx_multicast"` - Port16TxBroadcast FlexInt `json:"port_16-tx_broadcast"` - Port17RxPackets FlexInt `json:"port_17-rx_packets,omitempty"` - Port17RxBytes FlexInt `json:"port_17-rx_bytes,omitempty"` - Port17TxPackets FlexInt `json:"port_17-tx_packets,omitempty"` - Port17TxBytes FlexInt `json:"port_17-tx_bytes,omitempty"` - Port17TxMulticast FlexInt `json:"port_17-tx_multicast"` - Port17TxBroadcast FlexInt `json:"port_17-tx_broadcast"` - Port18RxPackets FlexInt `json:"port_18-rx_packets,omitempty"` - Port18RxBytes FlexInt `json:"port_18-rx_bytes,omitempty"` - Port18TxPackets FlexInt `json:"port_18-tx_packets,omitempty"` - Port18TxBytes FlexInt `json:"port_18-tx_bytes,omitempty"` - Port18RxMulticast FlexInt `json:"port_18-rx_multicast"` - Port18TxMulticast FlexInt `json:"port_18-tx_multicast"` - Port18TxBroadcast FlexInt `json:"port_18-tx_broadcast"` - Port19RxPackets FlexInt `json:"port_19-rx_packets,omitempty"` - Port19RxBytes FlexInt `json:"port_19-rx_bytes,omitempty"` - Port19TxPackets FlexInt `json:"port_19-tx_packets,omitempty"` - Port19TxBytes FlexInt `json:"port_19-tx_bytes,omitempty"` - Port19TxMulticast FlexInt `json:"port_19-tx_multicast"` - Port19TxBroadcast FlexInt `json:"port_19-tx_broadcast"` - Port21RxPackets FlexInt `json:"port_21-rx_packets,omitempty"` - Port21RxBytes FlexInt `json:"port_21-rx_bytes,omitempty"` - Port21TxPackets FlexInt `json:"port_21-tx_packets,omitempty"` - Port21TxBytes FlexInt `json:"port_21-tx_bytes,omitempty"` - Port21RxBroadcast FlexInt `json:"port_21-rx_broadcast"` - Port21TxMulticast FlexInt `json:"port_21-tx_multicast"` - Port21TxBroadcast FlexInt `json:"port_21-tx_broadcast"` - Port22RxPackets FlexInt `json:"port_22-rx_packets,omitempty"` - Port22RxBytes FlexInt `json:"port_22-rx_bytes,omitempty"` - Port22TxPackets FlexInt `json:"port_22-tx_packets,omitempty"` - Port22TxBytes FlexInt `json:"port_22-tx_bytes,omitempty"` - Port22RxMulticast FlexInt `json:"port_22-rx_multicast"` - Port22TxMulticast FlexInt `json:"port_22-tx_multicast"` - Port22TxBroadcast FlexInt `json:"port_22-tx_broadcast"` - Port23RxPackets FlexInt `json:"port_23-rx_packets,omitempty"` - Port23RxBytes FlexInt `json:"port_23-rx_bytes,omitempty"` - Port23RxDropped FlexInt `json:"port_23-rx_dropped"` - Port23TxPackets FlexInt `json:"port_23-tx_packets,omitempty"` - Port23TxBytes FlexInt `json:"port_23-tx_bytes,omitempty"` - Port23RxMulticast FlexInt `json:"port_23-rx_multicast"` - Port23RxBroadcast FlexInt `json:"port_23-rx_broadcast"` - Port23TxMulticast FlexInt `json:"port_23-tx_multicast"` - Port23TxBroadcast FlexInt `json:"port_23-tx_broadcast"` - Port24RxPackets FlexInt `json:"port_24-rx_packets,omitempty"` - Port24RxBytes FlexInt `json:"port_24-rx_bytes,omitempty"` - Port24TxPackets FlexInt `json:"port_24-tx_packets,omitempty"` - Port24TxBytes FlexInt `json:"port_24-tx_bytes,omitempty"` - Port24RxMulticast FlexInt `json:"port_24-rx_multicast"` - Port24TxMulticast FlexInt `json:"port_24-tx_multicast"` - Port24TxBroadcast FlexInt `json:"port_24-tx_broadcast"` - Port1RxMulticast FlexInt `json:"port_1-rx_multicast"` - Port3RxDropped FlexInt `json:"port_3-rx_dropped"` - Port3RxMulticast FlexInt `json:"port_3-rx_multicast"` - Port6RxDropped FlexInt `json:"port_6-rx_dropped"` - Port7RxDropped FlexInt `json:"port_7-rx_dropped"` - Port7RxMulticast FlexInt `json:"port_7-rx_multicast"` - Port9RxDropped FlexInt `json:"port_9-rx_dropped"` - Port9RxMulticast FlexInt `json:"port_9-rx_multicast"` - Port9RxBroadcast FlexInt `json:"port_9-rx_broadcast"` - Port10RxBroadcast FlexInt `json:"port_10-rx_broadcast"` - Port12RxDropped FlexInt `json:"port_12-rx_dropped"` - Port12RxMulticast FlexInt `json:"port_12-rx_multicast"` - Port13RxDropped FlexInt `json:"port_13-rx_dropped"` - Port17RxDropped FlexInt `json:"port_17-rx_dropped"` - Port17RxMulticast FlexInt `json:"port_17-rx_multicast"` - Port17RxBroadcast FlexInt `json:"port_17-rx_broadcast"` - Port19RxDropped FlexInt `json:"port_19-rx_dropped"` - Port19RxMulticast FlexInt `json:"port_19-rx_multicast"` - Port19RxBroadcast FlexInt `json:"port_19-rx_broadcast"` - Port21RxDropped FlexInt `json:"port_21-rx_dropped"` - Port21RxMulticast FlexInt `json:"port_21-rx_multicast"` - Port7RxBroadcast FlexInt `json:"port_7-rx_broadcast"` - Port18RxBroadcast FlexInt `json:"port_18-rx_broadcast"` - Port16RxMulticast FlexInt `json:"port_16-rx_multicast"` - Port15RxDropped FlexInt `json:"port_15-rx_dropped"` - Port15RxMulticast FlexInt `json:"port_15-rx_multicast"` - Port16RxBroadcast FlexInt `json:"port_16-rx_broadcast"` - Port11RxBroadcast FlexInt `json:"port_11-rx_broadcast"` - Port12RxBroadcast FlexInt `json:"port_12-rx_broadcast"` - Port6RxBroadcast FlexInt `json:"port_6-rx_broadcast"` - Port24RxBroadcast FlexInt `json:"port_24-rx_broadcast"` - Port22RxBroadcast FlexInt `json:"port_22-rx_broadcast"` - Port10TxDropped FlexInt `json:"port_10-tx_dropped"` - Port16TxDropped FlexInt `json:"port_16-tx_dropped"` - Port1RxBroadcast FlexInt `json:"port_1-rx_broadcast"` - Port4RxPackets FlexInt `json:"port_4-rx_packets,omitempty"` - Port4RxBytes FlexInt `json:"port_4-rx_bytes,omitempty"` - Port4RxDropped FlexInt `json:"port_4-rx_dropped"` - Port4TxPackets FlexInt `json:"port_4-tx_packets,omitempty"` - Port4TxBytes FlexInt `json:"port_4-tx_bytes,omitempty"` - Port4TxDropped FlexInt `json:"port_4-tx_dropped"` - Port4RxMulticast FlexInt `json:"port_4-rx_multicast"` - Port4RxBroadcast FlexInt `json:"port_4-rx_broadcast"` - Port4TxMulticast FlexInt `json:"port_4-tx_multicast"` - Port4TxBroadcast FlexInt `json:"port_4-tx_broadcast"` -} - -// UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Switch Stat data. -func (v *USWStat) UnmarshalJSON(data []byte) error { - var n struct { - Sw `json:"sw"` - } - v.Sw = &n.Sw - err := json.Unmarshal(data, v.Sw) // controller version 5.10. - if err != nil { - return json.Unmarshal(data, &n) // controller version 5.11. - } - return nil -} From e5d9ebd82d0c13c2be46d71046b2b0efca634396 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Tue, 3 Sep 2019 01:01:37 -0700 Subject: [PATCH 100/194] Add two debug messages, fix tests, and move methods verbatim. --- core/unifi/clients.go | 26 +++++++++++++++ core/unifi/devices.go | 25 ++++++++++++++- core/unifi/site.go | 22 +++++++++++++ core/unifi/unifi.go | 69 +++------------------------------------- core/unifi/unifi_test.go | 5 +-- 5 files changed, 79 insertions(+), 68 deletions(-) diff --git a/core/unifi/clients.go b/core/unifi/clients.go index 3d37b30c..f001ffb8 100644 --- a/core/unifi/clients.go +++ b/core/unifi/clients.go @@ -1,5 +1,31 @@ package unifi +import "fmt" + +// GetClients returns a response full of clients' data from the UniFi Controller. +func (u *Unifi) GetClients(sites Sites) (Clients, error) { + data := make([]*Client, 0) + for _, site := range sites { + var response struct { + Data []*Client `json:"data"` + } + u.DebugLog("Polling Controller, retreiving UniFi Clients, site %s (%s) ", site.Name, site.Desc) + clientPath := fmt.Sprintf(ClientPath, site.Name) + if err := u.GetData(clientPath, &response); err != nil { + return nil, err + } + for i, d := range response.Data { + // Add the special "Site Name" to each client. This becomes a Grafana filter somewhere. + response.Data[i].SiteName = site.Desc + " (" + site.Name + ")" + // Fix name and hostname fields. Sometimes one or the other is blank. + response.Data[i].Hostname = pick(d.Hostname, d.Name, d.Mac) + response.Data[i].Name = pick(d.Name, d.Hostname) + } + data = append(data, response.Data...) + } + return data, nil +} + // Clients contains a list that contains all of the unifi clients from a controller. type Clients []*Client diff --git a/core/unifi/devices.go b/core/unifi/devices.go index bc7bb593..79c140f9 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -1,6 +1,29 @@ package unifi -import "encoding/json" +import ( + "encoding/json" + "fmt" +) + +// GetDevices returns a response full of devices' data from the UniFi Controller. +func (u *Unifi) GetDevices(sites Sites) (*Devices, error) { + devices := new(Devices) + for _, site := range sites { + var response struct { + Data []json.RawMessage `json:"data"` + } + devicePath := fmt.Sprintf(DevicePath, site.Name) + if err := u.GetData(devicePath, &response); err != nil { + return nil, err + } + loopDevices := u.parseDevices(response.Data, site.SiteName) + devices.UAPs = append(devices.UAPs, loopDevices.UAPs...) + devices.USGs = append(devices.USGs, loopDevices.USGs...) + devices.USWs = append(devices.USWs, loopDevices.USWs...) + devices.UDMs = append(devices.UDMs, loopDevices.UDMs...) + } + return devices, nil +} // parseDevices parses the raw JSON from the Unifi Controller into device structures. func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { diff --git a/core/unifi/site.go b/core/unifi/site.go index 08213757..a6760f26 100644 --- a/core/unifi/site.go +++ b/core/unifi/site.go @@ -1,5 +1,27 @@ package unifi +import "strings" + +// GetSites returns a list of configured sites on the UniFi controller. +func (u *Unifi) GetSites() (Sites, error) { + var response struct { + Data []*Site `json:"data"` + } + if err := u.GetData(SiteList, &response); err != nil { + return nil, err + } + sites := []string{} // used for debug log only + for i, d := range response.Data { + // If the human name is missing (description), set it to the cryptic name. + response.Data[i].Desc = pick(d.Desc, d.Name) + // Add the custom site name to each site. used as a Grafana filter somewhere. + response.Data[i].SiteName = d.Desc + " (" + d.Name + ")" + sites = append(sites, d.Name) // used for debug log only + } + u.DebugLog("Found %d site(s): %s", len(sites), strings.Join(sites, ",")) + return response.Data, nil +} + // Sites is a struct to match Devices and Clients. type Sites []*Site diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index c30c4510..37ae69c3 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -79,76 +79,13 @@ func (u *Unifi) GetServerData() error { return u.GetData(StatusPath, &response) } -// GetClients returns a response full of clients' data from the UniFi Controller. -func (u *Unifi) GetClients(sites Sites) (Clients, error) { - data := make([]*Client, 0) - for _, site := range sites { - var response struct { - Data []*Client `json:"data"` - } - u.DebugLog("Polling Controller, retreiving UniFi Clients, site %s (%s) ", site.Name, site.Desc) - clientPath := fmt.Sprintf(ClientPath, site.Name) - if err := u.GetData(clientPath, &response); err != nil { - return nil, err - } - for i, d := range response.Data { - // Add the special "Site Name" to each client. This becomes a Grafana filter somewhere. - response.Data[i].SiteName = site.Desc + " (" + site.Name + ")" - // Fix name and hostname fields. Sometimes one or the other is blank. - response.Data[i].Hostname = pick(d.Hostname, d.Name, d.Mac) - response.Data[i].Name = pick(d.Name, d.Hostname) - } - data = append(data, response.Data...) - } - return data, nil -} - -// GetDevices returns a response full of devices' data from the UniFi Controller. -func (u *Unifi) GetDevices(sites Sites) (*Devices, error) { - devices := new(Devices) - for _, site := range sites { - var response struct { - Data []json.RawMessage `json:"data"` - } - devicePath := fmt.Sprintf(DevicePath, site.Name) - if err := u.GetData(devicePath, &response); err != nil { - return nil, err - } - loopDevices := u.parseDevices(response.Data, site.SiteName) - devices.UAPs = append(devices.UAPs, loopDevices.UAPs...) - devices.USGs = append(devices.USGs, loopDevices.USGs...) - devices.USWs = append(devices.USWs, loopDevices.USWs...) - devices.UDMs = append(devices.UDMs, loopDevices.UDMs...) - } - return devices, nil -} - -// GetSites returns a list of configured sites on the UniFi controller. -func (u *Unifi) GetSites() (Sites, error) { - var response struct { - Data []*Site `json:"data"` - } - if err := u.GetData(SiteList, &response); err != nil { - return nil, err - } - sites := []string{} // used for debug log only - for i, d := range response.Data { - // If the human name is missing (description), set it to the cryptic name. - response.Data[i].Desc = pick(d.Desc, d.Name) - // Add the custom site name to each site. used as a Grafana filter somewhere. - response.Data[i].SiteName = d.Desc + " (" + d.Name + ")" - sites = append(sites, d.Name) // used for debug log only - } - u.DebugLog("Found %d site(s): %s", len(sites), strings.Join(sites, ",")) - return response.Data, nil -} - // GetData makes a unifi request and unmarshal the response into a provided pointer. func (u *Unifi) GetData(methodPath string, v interface{}) error { body, err := u.GetJSON(methodPath) if err != nil { return err } + u.DebugLog("Unmarshaling %s", methodPath) return json.Unmarshal(body, v) } @@ -157,7 +94,8 @@ func (u *Unifi) GetData(methodPath string, v interface{}) error { // And if you're doing that... sumbut a pull request with your new struct. :) // This is a helper method that is exposed for convenience. func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err error) { - switch path := u.URL + apiPath; { + path := u.URL + apiPath + switch { case params == "": req, err = http.NewRequest("GET", path, nil) default: @@ -166,6 +104,7 @@ func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err er if err == nil { req.Header.Add("Accept", "application/json") } + u.DebugLog("Downloading %s (params: %v, error: %v)", path, params != "", err != nil) return } diff --git a/core/unifi/unifi_test.go b/core/unifi/unifi_test.go index 0f3748b1..9dc4a852 100644 --- a/core/unifi/unifi_test.go +++ b/core/unifi/unifi_test.go @@ -17,6 +17,7 @@ func TestNewUnifi(t *testing.T) { Pass: "pass2", URL: u, VerifySSL: false, + DebugLog: DiscardLogs, } authReq, err := NewUnifi(c) a.NotNil(err) @@ -34,7 +35,7 @@ func TestUniReq(t *testing.T) { p := "/test/path" u := "http://some.url:8443" // Test empty parameters. - authReq := &Unifi{Client: &http.Client{}, Config: &Config{URL: u}} + authReq := &Unifi{Client: &http.Client{}, Config: &Config{URL: u, DebugLog: DiscardLogs}} r, err := authReq.UniReq(p, "") a.Nil(err, "newrequest must not produce an error") a.EqualValues(p, r.URL.Path, @@ -45,7 +46,7 @@ func TestUniReq(t *testing.T) { // Test with parameters k := "key1=value9&key2=value7" - authReq = &Unifi{Client: &http.Client{}, Config: &Config{URL: "http://some.url:8443"}} + authReq = &Unifi{Client: &http.Client{}, Config: &Config{URL: "http://some.url:8443", DebugLog: DiscardLogs}} r, err = authReq.UniReq(p, k) a.Nil(err, "newrequest must not produce an error") a.EqualValues(p, r.URL.Path, From ddc809cd06aea0c7cecbf9d81e634b591b6e65b0 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Tue, 3 Sep 2019 01:09:25 -0700 Subject: [PATCH 101/194] Add message length to debug output --- core/unifi/unifi.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 37ae69c3..5ee19543 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -85,7 +85,7 @@ func (u *Unifi) GetData(methodPath string, v interface{}) error { if err != nil { return err } - u.DebugLog("Unmarshaling %s", methodPath) + u.DebugLog("Unmarshaling %s (bytes: %d)", methodPath, len(body)) return json.Unmarshal(body, v) } From 519dbf40f2a598e678f185d531943dd6ab248145 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 8 Sep 2019 02:01:32 -0700 Subject: [PATCH 102/194] UAP is int. weird. --- core/unifi/udm.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/core/unifi/udm.go b/core/unifi/udm.go index 840b12cd..3615cd0b 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -112,18 +112,18 @@ type UDM struct { TxBytes FlexInt `json:"tx_bytes"` RxBytes FlexInt `json:"rx_bytes"` Bytes FlexInt `json:"bytes"` - NumSta FlexInt `json:"num_sta"` - WlanNumSta FlexInt `json:"wlan-num_sta"` - LanNumSta FlexInt `json:"lan-num_sta"` - UserWlanNumSta FlexInt `json:"user-wlan-num_sta"` - UserLanNumSta FlexInt `json:"user-lan-num_sta"` - UserNumSta FlexInt `json:"user-num_sta"` - GuestWlanNumSta FlexInt `json:"guest-wlan-num_sta"` - GuestLanNumSta FlexInt `json:"guest-lan-num_sta"` - GuestNumSta FlexInt `json:"guest-num_sta"` - NumDesktop FlexInt `json:"num_desktop"` - NumMobile FlexInt `json:"num_mobile"` - NumHandheld FlexInt `json:"num_handheld"` + NumSta FlexInt `json:"num_sta"` // USG + WlanNumSta int `json:"wlan-num_sta"` // UAP + LanNumSta FlexInt `json:"lan-num_sta"` // USW + UserWlanNumSta int `json:"user-wlan-num_sta"` // UAP + UserLanNumSta FlexInt `json:"user-lan-num_sta"` // USW + UserNumSta FlexInt `json:"user-num_sta"` // USG + GuestWlanNumSta int `json:"guest-wlan-num_sta"` // UAP + GuestLanNumSta FlexInt `json:"guest-lan-num_sta"` // USW + GuestNumSta FlexInt `json:"guest-num_sta"` // USG + NumDesktop FlexInt `json:"num_desktop"` // USG + NumMobile FlexInt `json:"num_mobile"` // USG + NumHandheld FlexInt `json:"num_handheld"` // USG } // NetworkTable is the list of networks on a gateway. From e7b06b78bbe97575315733a2bf9614df82c43522 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 8 Sep 2019 02:02:54 -0700 Subject: [PATCH 103/194] dont make it different here --- core/unifi/udm.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/unifi/udm.go b/core/unifi/udm.go index 3615cd0b..3ca4759f 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -113,12 +113,12 @@ type UDM struct { RxBytes FlexInt `json:"rx_bytes"` Bytes FlexInt `json:"bytes"` NumSta FlexInt `json:"num_sta"` // USG - WlanNumSta int `json:"wlan-num_sta"` // UAP + WlanNumSta FlexInt `json:"wlan-num_sta"` // UAP LanNumSta FlexInt `json:"lan-num_sta"` // USW - UserWlanNumSta int `json:"user-wlan-num_sta"` // UAP + UserWlanNumSta FlexInt `json:"user-wlan-num_sta"` // UAP UserLanNumSta FlexInt `json:"user-lan-num_sta"` // USW UserNumSta FlexInt `json:"user-num_sta"` // USG - GuestWlanNumSta int `json:"guest-wlan-num_sta"` // UAP + GuestWlanNumSta FlexInt `json:"guest-wlan-num_sta"` // UAP GuestLanNumSta FlexInt `json:"guest-lan-num_sta"` // USW GuestNumSta FlexInt `json:"guest-num_sta"` // USG NumDesktop FlexInt `json:"num_desktop"` // USG From 10304fcda07a0c2225aaf47c175700b15a30168a Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 8 Sep 2019 02:07:36 -0700 Subject: [PATCH 104/194] make UAP like the others --- core/unifi/uap.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/unifi/uap.go b/core/unifi/uap.go index d94b60e4..b1040616 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -133,9 +133,9 @@ type UAP struct { Bytes FlexInt `json:"bytes"` VwireEnabled FlexBool `json:"vwireEnabled"` UplinkTable []interface{} `json:"uplink_table"` - NumSta int `json:"num_sta"` - UserNumSta int `json:"user-num_sta"` - GuestNumSta int `json:"guest-num_sta"` + NumSta FlexInt `json:"num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` TwoPhaseAdopt FlexBool `json:"two_phase_adopt,omitempty"` } From 8ada1bd9cfb36bbde7576347a490e5d77104a5fa Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 8 Sep 2019 02:44:16 -0700 Subject: [PATCH 105/194] Add unused client field --- core/unifi/clients.go | 1 + 1 file changed, 1 insertion(+) diff --git a/core/unifi/clients.go b/core/unifi/clients.go index f001ffb8..77b62cf1 100644 --- a/core/unifi/clients.go +++ b/core/unifi/clients.go @@ -89,6 +89,7 @@ type Client struct { Radio string `json:"radio"` RadioName string `json:"radio_name"` RadioProto string `json:"radio_proto"` + RadioDescription string `json:"-"` RoamCount int64 `json:"roam_count"` Rssi int64 `json:"rssi"` RxBytes int64 `json:"rx_bytes"` From 1a0c62cba57c82aa7301f0d9569dce49a97ca7a5 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sat, 14 Sep 2019 01:43:52 -0700 Subject: [PATCH 106/194] StpPriority -> FlexInt --- core/unifi/udm.go | 2 +- core/unifi/usw.go | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/unifi/udm.go b/core/unifi/udm.go index 3ca4759f..303d8110 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -36,7 +36,7 @@ type UDM struct { JumboframeEnabled FlexBool `json:"jumboframe_enabled"` FlowctrlEnabled FlexBool `json:"flowctrl_enabled"` StpVersion string `json:"stp_version"` - StpPriority string `json:"stp_priority"` + StpPriority FlexInt `json:"stp_priority"` PowerSourceCtrlEnabled FlexBool `json:"power_source_ctrl_enabled"` LicenseState string `json:"license_state"` ID string `json:"_id"` diff --git a/core/unifi/usw.go b/core/unifi/usw.go index 62a5cd48..f0dc88bc 100644 --- a/core/unifi/usw.go +++ b/core/unifi/usw.go @@ -42,14 +42,14 @@ type USW struct { PortIdx FlexInt `json:"port_idx"` PortconfID string `json:"portconf_id"` } `json:"port_overrides"` - PortTable []Port `json:"port_table"` - Serial string `json:"serial"` - SiteID string `json:"site_id"` - StpPriority string `json:"stp_priority"` - StpVersion string `json:"stp_version"` - Type string `json:"type"` - Version string `json:"version"` - RequiredVersion string `json:"required_version"` + PortTable []Port `json:"port_table"` + Serial string `json:"serial"` + SiteID string `json:"site_id"` + StpPriority FlexInt `json:"stp_priority"` + StpVersion string `json:"stp_version"` + Type string `json:"type"` + Version string `json:"version"` + RequiredVersion string `json:"required_version"` SwitchCaps struct { FeatureCaps FlexInt `json:"feature_caps"` MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` From de4eacb269b5bdd85da6cee9c6877af06bf6a667 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 15 Sep 2019 22:32:45 -0700 Subject: [PATCH 107/194] Fix Ht. Sometimes a number, sometimes 'auto' --- core/unifi/uap.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/uap.go b/core/unifi/uap.go index b1040616..db99ae2f 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -383,7 +383,7 @@ type RadioTable []struct { HasDfs FlexBool `json:"has_dfs"` HasFccdfs FlexBool `json:"has_fccdfs"` HasHt160 FlexBool `json:"has_ht160"` - Ht string `json:"ht"` + Ht FlexInt `json:"ht"` Is11Ac FlexBool `json:"is_11ac"` MaxTxpower FlexInt `json:"max_txpower"` MinRssi FlexInt `json:"min_rssi,omitempty"` From 2ce0e76c85e5041c56bd8f069714cdd9d0cfab1a Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Thu, 28 Nov 2019 04:18:28 -0800 Subject: [PATCH 108/194] add missing members --- core/unifi/clients.go | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/core/unifi/clients.go b/core/unifi/clients.go index 77b62cf1..33555a01 100644 --- a/core/unifi/clients.go +++ b/core/unifi/clients.go @@ -31,21 +31,22 @@ type Clients []*Client // Client defines all the data a connected-network client contains. type Client struct { - Anomalies int64 `json:"anomalies,omitempty"` - ApMac string `json:"ap_mac"` - ApName string `json:"-"` - AssocTime int64 `json:"assoc_time"` - Blocked bool `json:"blocked,omitempty"` - Bssid string `json:"bssid"` - BytesR int64 `json:"bytes-r"` - Ccq int64 `json:"ccq"` - Channel FlexInt `json:"channel"` - DevCat FlexInt `json:"dev_cat"` - DevFamily FlexInt `json:"dev_family"` - DevID FlexInt `json:"dev_id"` - DevVendor FlexInt `json:"dev_vendor,omitempty"` - DhcpendTime int `json:"dhcpend_time,omitempty"` - DpiStats struct { + Anomalies int64 `json:"anomalies,omitempty"` + ApMac string `json:"ap_mac"` + ApName string `json:"-"` + AssocTime int64 `json:"assoc_time"` + Blocked bool `json:"blocked,omitempty"` + Bssid string `json:"bssid"` + BytesR int64 `json:"bytes-r"` + Ccq int64 `json:"ccq"` + Channel FlexInt `json:"channel"` + DevCat FlexInt `json:"dev_cat"` + DevFamily FlexInt `json:"dev_family"` + DevID FlexInt `json:"dev_id"` + DevVendor FlexInt `json:"dev_vendor,omitempty"` + DhcpendTime int `json:"dhcpend_time,omitempty"` + Satisfaction FlexInt `json:"satisfaction,omitempty"` + DpiStats struct { App FlexInt Cat FlexInt RxBytes FlexInt @@ -106,6 +107,7 @@ type Client struct { TxBytes int64 `json:"tx_bytes"` TxBytesR int64 `json:"tx_bytes-r"` TxPackets int64 `json:"tx_packets"` + TxRetries int64 `json:"tx_retries"` TxPower int64 `json:"tx_power"` TxRate int64 `json:"tx_rate"` Uptime int64 `json:"uptime"` From d6f1ca10c75bfb070042fbc1d054e31b5019259e Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Fri, 29 Nov 2019 23:00:31 -0800 Subject: [PATCH 109/194] whatever --- core/unifi/types.go | 4 +--- core/unifi/types_test.go | 6 +++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/core/unifi/types.go b/core/unifi/types.go index 571f333b..840b0930 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -93,18 +93,16 @@ func (f *FlexInt) UnmarshalJSON(b []byte) error { case float64: f.Val = i f.Txt = strconv.FormatFloat(i, 'f', -1, 64) - return nil case string: f.Txt = i f.Val, _ = strconv.ParseFloat(i, 64) - return nil case nil: f.Txt = "0" f.Val = 0 - return nil default: return fmt.Errorf("cannot unmarshal to FlexInt: %s", b) } + return nil } // FlexBool provides a container and unmarshalling for fields that may be diff --git a/core/unifi/types_test.go b/core/unifi/types_test.go index 2b62cfcc..cd691158 100644 --- a/core/unifi/types_test.go +++ b/core/unifi/types_test.go @@ -15,10 +15,11 @@ func TestFlexInt(t *testing.T) { Seven FlexInt `json:"seven"` Auto FlexInt `json:"auto"` Channel FlexInt `json:"channel"` + Nil FlexInt `json:"nil"` } var r testReply // test unmarshalling the custom type three times with different values. - a.Nil(json.Unmarshal([]byte(`{"five": "5", "seven": 7, "auto": "auto"}`), &r)) + a.Nil(json.Unmarshal([]byte(`{"five": "5", "seven": 7, "auto": "auto", "nil": null}`), &r)) // test number in string. a.EqualValues(5, r.Five.Val) @@ -33,4 +34,7 @@ func TestFlexInt(t *testing.T) { a.NotNil(json.Unmarshal([]byte(`{"channel": {}}`), &r), "a non-string and non-number must produce an error.") a.EqualValues(0, r.Channel.Val) + // test null. + a.EqualValues(0, r.Nil.Val) + a.EqualValues("0", r.Nil.Txt) } From 0c5d883a207596104f4a551d1d1ab6e56ab5cea7 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Mon, 2 Dec 2019 22:10:25 -0800 Subject: [PATCH 110/194] Add missing items to udm --- core/unifi/udm.go | 4 ++++ core/unifi/unifi.go | 27 +++++++++++++++------------ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/core/unifi/udm.go b/core/unifi/udm.go index 303d8110..51382435 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -112,6 +112,10 @@ type UDM struct { TxBytes FlexInt `json:"tx_bytes"` RxBytes FlexInt `json:"rx_bytes"` Bytes FlexInt `json:"bytes"` + BytesD FlexInt `json:"bytes-d"` + TxBytesD FlexInt `json:"tx_bytes-d"` + RxBytesD FlexInt `json:"rx_bytes-d"` + BytesR FlexInt `json:"bytes-r"` NumSta FlexInt `json:"num_sta"` // USG WlanNumSta FlexInt `json:"wlan-num_sta"` // UAP LanNumSta FlexInt `json:"lan-num_sta"` // USW diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 5ee19543..01bc92d8 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -15,6 +15,7 @@ import ( "net/http" "net/http/cookiejar" "strings" + "time" ) // NewUnifi creates a http.Client with authenticated cookies. @@ -79,13 +80,15 @@ func (u *Unifi) GetServerData() error { return u.GetData(StatusPath, &response) } -// GetData makes a unifi request and unmarshal the response into a provided pointer. -func (u *Unifi) GetData(methodPath string, v interface{}) error { - body, err := u.GetJSON(methodPath) +// GetData makes a unifi request and unmarshals the response into a provided pointer. +func (u *Unifi) GetData(apiPath string, v interface{}) error { + start := time.Now() + body, err := u.GetJSON(apiPath) + dur := time.Since(start) if err != nil { return err } - u.DebugLog("Unmarshaling %s (bytes: %d)", methodPath, len(body)) + u.DebugLog("Requested %s: elapsed %v, returned %d bytes", apiPath, dur.Round(time.Millisecond), len(body)) return json.Unmarshal(body, v) } @@ -94,17 +97,17 @@ func (u *Unifi) GetData(methodPath string, v interface{}) error { // And if you're doing that... sumbut a pull request with your new struct. :) // This is a helper method that is exposed for convenience. func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err error) { - path := u.URL + apiPath - switch { - case params == "": - req, err = http.NewRequest("GET", path, nil) + switch params { + case "": + req, err = http.NewRequest("GET", u.URL+apiPath, nil) default: - req, err = http.NewRequest("POST", path, bytes.NewBufferString(params)) + req, err = http.NewRequest("POST", u.URL+apiPath, bytes.NewBufferString(params)) } - if err == nil { - req.Header.Add("Accept", "application/json") + if err != nil { + return } - u.DebugLog("Downloading %s (params: %v, error: %v)", path, params != "", err != nil) + req.Header.Add("Accept", "application/json") + u.DebugLog("Requesting %s, with params: %v", apiPath, params != "") return } From 83c54b2b629af752704ecd5472e4131b31248b51 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Tue, 3 Dec 2019 12:06:03 -0800 Subject: [PATCH 111/194] change channel to float --- core/unifi/uap.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/uap.go b/core/unifi/uap.go index db99ae2f..f873590b 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -506,7 +506,7 @@ type VapTable []struct { AvgClientSignal FlexInt `json:"avg_client_signal"` Bssid string `json:"bssid"` Ccq int `json:"ccq"` - Channel int `json:"channel"` + Channel FlexInt `json:"channel"` DNSAvgLatency FlexInt `json:"dns_avg_latency"` Essid string `json:"essid"` Extchannel int `json:"extchannel"` From 8a294b617fa10113992e5512a31a2a8b12bbf7d1 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Wed, 11 Dec 2019 01:07:31 -0800 Subject: [PATCH 112/194] some updates --- core/unifi/.travis.yml | 2 +- core/unifi/clients.go | 8 ++++- core/unifi/devices.go | 14 ++++++++- core/unifi/ids.go | 21 +++++++++---- core/unifi/site.go | 7 ++++- core/unifi/types.go | 40 ++++++++++++++----------- core/unifi/types_test.go | 11 +++---- core/unifi/uap.go | 3 ++ core/unifi/uap_test.go | 6 ++-- core/unifi/unifi.go | 64 +++++++++++++++++++++++++++------------- core/unifi/unifi_test.go | 14 ++++----- core/unifi/usg.go | 3 ++ core/unifi/usg_test.go | 5 ++-- core/unifi/usw.go | 3 ++ core/unifi/usw_test.go | 40 +++++++------------------ 15 files changed, 148 insertions(+), 93 deletions(-) diff --git a/core/unifi/.travis.yml b/core/unifi/.travis.yml index a05c4c9f..cdcc5e6b 100644 --- a/core/unifi/.travis.yml +++ b/core/unifi/.travis.yml @@ -7,7 +7,7 @@ before_install: - curl -sLo $GOPATH/bin/dep https://github.com/golang/dep/releases/download/v0.5.3/dep-linux-amd64 - chmod +x $GOPATH/bin/dep # download super-linter: golangci-lint -- curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.16.0 +- curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin latest install: - dep ensure script: diff --git a/core/unifi/clients.go b/core/unifi/clients.go index 33555a01..a6be75c4 100644 --- a/core/unifi/clients.go +++ b/core/unifi/clients.go @@ -5,15 +5,19 @@ import "fmt" // GetClients returns a response full of clients' data from the UniFi Controller. func (u *Unifi) GetClients(sites Sites) (Clients, error) { data := make([]*Client, 0) + for _, site := range sites { var response struct { Data []*Client `json:"data"` } + u.DebugLog("Polling Controller, retreiving UniFi Clients, site %s (%s) ", site.Name, site.Desc) - clientPath := fmt.Sprintf(ClientPath, site.Name) + + clientPath := fmt.Sprintf(APIClientPath, site.Name) if err := u.GetData(clientPath, &response); err != nil { return nil, err } + for i, d := range response.Data { // Add the special "Site Name" to each client. This becomes a Grafana filter somewhere. response.Data[i].SiteName = site.Desc + " (" + site.Name + ")" @@ -21,8 +25,10 @@ func (u *Unifi) GetClients(sites Sites) (Clients, error) { response.Data[i].Hostname = pick(d.Hostname, d.Name, d.Mac) response.Data[i].Name = pick(d.Name, d.Hostname) } + data = append(data, response.Data...) } + return data, nil } diff --git a/core/unifi/devices.go b/core/unifi/devices.go index 79c140f9..f6e77a65 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -8,36 +8,44 @@ import ( // GetDevices returns a response full of devices' data from the UniFi Controller. func (u *Unifi) GetDevices(sites Sites) (*Devices, error) { devices := new(Devices) + for _, site := range sites { var response struct { Data []json.RawMessage `json:"data"` } - devicePath := fmt.Sprintf(DevicePath, site.Name) + + devicePath := fmt.Sprintf(APIDevicePath, site.Name) if err := u.GetData(devicePath, &response); err != nil { return nil, err } + loopDevices := u.parseDevices(response.Data, site.SiteName) devices.UAPs = append(devices.UAPs, loopDevices.UAPs...) devices.USGs = append(devices.USGs, loopDevices.USGs...) devices.USWs = append(devices.USWs, loopDevices.USWs...) devices.UDMs = append(devices.UDMs, loopDevices.UDMs...) } + return devices, nil } // parseDevices parses the raw JSON from the Unifi Controller into device structures. func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { devices := new(Devices) + for _, r := range data { // Loop each item in the raw JSON message, detect its type and unmarshal it. assetType := "" + if o := make(map[string]interface{}); u.unmarshalDevice("map", r, &o) != nil { continue } else if t, ok := o["type"].(string); ok { assetType = t } + u.DebugLog("Unmarshalling Device Type: %v, site %s ", assetType, siteName) // 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} @@ -67,6 +75,7 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { u.ErrorLog("unknown asset type - %v - skipping", assetType) } } + return devices } @@ -75,11 +84,13 @@ func (u *Unifi) unmarshalDevice(dev string, data json.RawMessage, v interface{}) if err = json.Unmarshal(data, v); err != nil { u.ErrorLog("json.Unmarshal(%v): %v", dev, err) u.ErrorLog("Enable Debug Logging to output the failed payload.") + json, err := data.MarshalJSON() u.DebugLog("Failed Payload: %s (marshal err: %v)", json, err) u.DebugLog("The above payload can prove useful during torubleshooting when you open an Issue:") u.DebugLog("==- https://github.com/golift/unifi/issues/new -==") } + return err } @@ -91,5 +102,6 @@ func pick(strings ...string) string { return s } } + return "" } diff --git a/core/unifi/ids.go b/core/unifi/ids.go index dcf22c9f..d28b7246 100644 --- a/core/unifi/ids.go +++ b/core/unifi/ids.go @@ -65,7 +65,7 @@ type IDS struct { UsgipASN string `json:"usgipASN"` Catname string `json:"catname"` InnerAlertAction string `json:"inner_alert_action"` - InnerAlertGid int64 `json:"inner_alert_gid"` + InnerAlertGID int64 `json:"inner_alert_gid"` InnerAlertSignatureID int64 `json:"inner_alert_signature_id"` InnerAlertRev int64 `json:"inner_alert_rev"` InnerAlertSignature string `json:"inner_alert_signature"` @@ -86,14 +86,18 @@ type IDS struct { // Returns all events that happened in site between from and to. 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) if err != nil { return data, err } + data = append(data, ids...) } + return data, nil } @@ -103,31 +107,38 @@ func (u *Unifi) GetSiteIDS(site *Site, from, to time.Time) ([]*IDS, error) { var response struct { Data []*IDS `json:"data"` } - URIpath := fmt.Sprintf(IPSEvents, site.Name) + + URIpath := fmt.Sprintf(APIIPSEvents, site.Name) + params := fmt.Sprintf(`{"start":"%v000","end":"%v000","_limit":50000}`, from.Unix(), to.Unix()) + req, err := u.UniReq(URIpath, params) if err != nil { return nil, err } + resp, err := u.Do(req) if err != nil { return nil, err } - defer func() { - _ = resp.Body.Close() - }() + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } + if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("invalid status code from server %s", resp.Status) } + if err := json.Unmarshal(body, &response); err != nil { return nil, err } + for i := range response.Data { response.Data[i].SiteName = site.SiteName } + return response.Data, nil } diff --git a/core/unifi/site.go b/core/unifi/site.go index a6760f26..ae0df3a8 100644 --- a/core/unifi/site.go +++ b/core/unifi/site.go @@ -7,10 +7,13 @@ func (u *Unifi) GetSites() (Sites, error) { var response struct { Data []*Site `json:"data"` } - if err := u.GetData(SiteList, &response); err != nil { + + if err := u.GetData(APISiteList, &response); err != nil { return nil, err } + sites := []string{} // used for debug log only + for i, d := range response.Data { // If the human name is missing (description), set it to the cryptic name. response.Data[i].Desc = pick(d.Desc, d.Name) @@ -18,7 +21,9 @@ func (u *Unifi) GetSites() (Sites, error) { response.Data[i].SiteName = d.Desc + " (" + d.Name + ")" sites = append(sites, d.Name) // used for debug log only } + u.DebugLog("Found %d site(s): %s", len(sites), strings.Join(sites, ",")) + return response.Data, nil } diff --git a/core/unifi/types.go b/core/unifi/types.go index 840b0930..394278a0 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -11,30 +11,30 @@ import ( // This is a list of unifi API paths. // The %s in each string must be replaced with a Site.Name. const ( - // StatusPath shows Controller version. - StatusPath string = "/status" - // SiteList is the path to the api site list. - SiteList string = "/api/stat/sites" - // ClientPath is Unifi Clients API Path - ClientPath string = "/api/s/%s/stat/sta" - // DevicePath is where we get data about Unifi devices. - DevicePath string = "/api/s/%s/stat/device" - // NetworkPath contains network-configuration data. Not really graphable. - NetworkPath string = "/api/s/%s/rest/networkconf" - // UserGroupPath contains usergroup configurations. - UserGroupPath string = "/api/s/%s/rest/usergroup" - // LoginPath is Unifi Controller Login API Path - LoginPath string = "/api/login" - // IPSEvents returns Intrusion Detection Systems Events - IPSEvents string = "/api/s/%s/stat/ips/event" + // APIStatusPath shows Controller version. + APIStatusPath string = "/status" + // APISiteList is the path to the api site list. + APISiteList string = "/api/stat/sites" + // APIClientPath is Unifi Clients API Path + APIClientPath string = "/api/s/%s/stat/sta" + // APIDevicePath is where we get data about Unifi devices. + APIDevicePath string = "/api/s/%s/stat/device" + // APINetworkPath contains network-configuration data. Not really graphable. + APINetworkPath string = "/api/s/%s/rest/networkconf" + // APIUserGroupPath contains usergroup configurations. + APIUserGroupPath string = "/api/s/%s/rest/usergroup" + // APILoginPath is Unifi Controller Login API Path + APILoginPath string = "/api/login" + // APIIPSEvents returns Intrusion Detection Systems Events + APIIPSEvents string = "/api/s/%s/stat/ips/event" ) // Logger is a base type to deal with changing log outputs. Create a logger // that matches this interface to capture debug and error logs. type Logger func(msg string, fmt ...interface{}) -// DiscardLogs is the default debug logger. -func DiscardLogs(msg string, v ...interface{}) { +// discardLogs is the default debug logger. +func discardLogs(msg string, v ...interface{}) { // do nothing. } @@ -86,9 +86,11 @@ type FlexInt struct { // Generally, do call this directly, it's used in the json interface. func (f *FlexInt) UnmarshalJSON(b []byte) error { var unk interface{} + if err := json.Unmarshal(b, &unk); err != nil { return err } + switch i := unk.(type) { case float64: f.Val = i @@ -102,6 +104,7 @@ func (f *FlexInt) UnmarshalJSON(b []byte) error { default: return fmt.Errorf("cannot unmarshal to FlexInt: %s", b) } + return nil } @@ -120,5 +123,6 @@ func (f *FlexBool) UnmarshalJSON(b []byte) error { strings.EqualFold(f.Txt, "t") || strings.EqualFold(f.Txt, "armed") || strings.EqualFold(f.Txt, "active") || strings.EqualFold(f.Txt, "enabled") || strings.EqualFold(f.Txt, "ready") || strings.EqualFold(f.Txt, "up") || strings.EqualFold(f.Txt, "ok") + return nil } diff --git a/core/unifi/types_test.go b/core/unifi/types_test.go index cd691158..a7eeef06 100644 --- a/core/unifi/types_test.go +++ b/core/unifi/types_test.go @@ -10,22 +10,23 @@ import ( func TestFlexInt(t *testing.T) { t.Parallel() a := assert.New(t) - type testReply struct { + five, seven := 5, 7 + + var r struct { Five FlexInt `json:"five"` Seven FlexInt `json:"seven"` Auto FlexInt `json:"auto"` Channel FlexInt `json:"channel"` Nil FlexInt `json:"nil"` } - var r testReply + // test unmarshalling the custom type three times with different values. a.Nil(json.Unmarshal([]byte(`{"five": "5", "seven": 7, "auto": "auto", "nil": null}`), &r)) - // test number in string. - a.EqualValues(5, r.Five.Val) + a.EqualValues(five, r.Five.Val) a.EqualValues("5", r.Five.Txt) // test number. - a.EqualValues(7, r.Seven.Val) + a.EqualValues(seven, r.Seven.Val) a.EqualValues("7", r.Seven.Txt) // test string. a.EqualValues(0, r.Auto.Val) diff --git a/core/unifi/uap.go b/core/unifi/uap.go index f873590b..6e1238a6 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -555,10 +555,13 @@ func (v *UAPStat) UnmarshalJSON(data []byte) error { var n struct { Ap `json:"ap"` } + v.Ap = &n.Ap + err := json.Unmarshal(data, v.Ap) // controller version 5.10. if err != nil { return json.Unmarshal(data, &n) // controller version 5.11. } + return nil } diff --git a/core/unifi/uap_test.go b/core/unifi/uap_test.go index 2ad1f982..155b3539 100644 --- a/core/unifi/uap_test.go +++ b/core/unifi/uap_test.go @@ -40,14 +40,14 @@ func TestUAPUnmarshalJSON(t *testing.T) { t.Parallel() a := assert.New(t) - + rxPakcets := 49299197 u := &UAPStat{} err := u.UnmarshalJSON([]byte(testcontroller510)) a.Nil(err, "must be no error unmarshaling test strings") - a.Equal(float64(49299197), u.RxPackets.Val, "data was not properly unmarshaled") + a.Equal(float64(rxPakcets), u.RxPackets.Val, "data was not properly unmarshaled") u = &UAPStat{} // reset err = u.UnmarshalJSON([]byte(testcontroller511)) a.Nil(err, "must be no error unmarshaling test strings") - a.Equal(float64(49299197), u.RxPackets.Val, "data was not properly unmarshaled") + a.Equal(float64(rxPakcets), u.RxPackets.Val, "data was not properly unmarshaled") } diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 01bc92d8..84e4a167 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -26,47 +26,61 @@ func NewUnifi(config *Config) (*Unifi, error) { if err != nil { return nil, err } - if config.ErrorLog == nil { - config.ErrorLog = DiscardLogs - } - if config.DebugLog == nil { - config.DebugLog = DiscardLogs - } + config.URL = strings.TrimRight(config.URL, "/") + + if config.ErrorLog == nil { + config.ErrorLog = discardLogs + } + + if config.DebugLog == nil { + config.DebugLog = discardLogs + } + u := &Unifi{Config: config, Client: &http.Client{ - Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !config.VerifySSL}}, - Jar: jar, + Jar: jar, + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: !config.VerifySSL}, + }, }, } if err := u.Login(); err != nil { return u, err } + if err := u.GetServerData(); err != nil { return u, fmt.Errorf("unable to get server version: %v", err) } + return u, nil } // Login is a helper method. It can be called to grab a new authentication cookie. func (u *Unifi) Login() error { + start := time.Now() + // magic login. - req, err := u.UniReq(LoginPath, fmt.Sprintf(`{"username":"%s","password":"%s"}`, u.User, u.Pass)) + req, err := u.UniReq(APILoginPath, fmt.Sprintf(`{"username":"%s","password":"%s"}`, u.User, u.Pass)) if err != nil { return err } + resp, err := u.Do(req) if err != nil { return err } - defer func() { - _, _ = io.Copy(ioutil.Discard, resp.Body) // avoid leaking. - _ = resp.Body.Close() - }() + defer resp.Body.Close() // we need no data here. + + _, _ = io.Copy(ioutil.Discard, resp.Body) // avoid leaking. + u.DebugLog("Requested %s: elapsed %v, returned %d bytes", + APILoginPath, time.Since(start).Round(time.Millisecond), resp.ContentLength) + if resp.StatusCode != http.StatusOK { return fmt.Errorf("authentication failed (user: %s): %s (status: %s)", - u.User, u.URL+LoginPath, resp.Status) + u.User, u.URL+APILoginPath, resp.Status) } + return nil } @@ -76,19 +90,24 @@ func (u *Unifi) GetServerData() error { var response struct { Data server `json:"meta"` } + u.server = &response.Data - return u.GetData(StatusPath, &response) + + return u.GetData(APIStatusPath, &response) } // GetData makes a unifi request and unmarshals the response into a provided pointer. func (u *Unifi) GetData(apiPath string, v interface{}) error { start := time.Now() + body, err := u.GetJSON(apiPath) - dur := time.Since(start) if err != nil { return err } - u.DebugLog("Requested %s: elapsed %v, returned %d bytes", apiPath, dur.Round(time.Millisecond), len(body)) + + u.DebugLog("Requested %s: elapsed %v, returned %d bytes", + apiPath, time.Since(start).Round(time.Millisecond), len(body)) + return json.Unmarshal(body, v) } @@ -103,11 +122,14 @@ func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err er default: req, err = http.NewRequest("POST", u.URL+apiPath, bytes.NewBufferString(params)) } + if err != nil { return } + req.Header.Add("Accept", "application/json") u.DebugLog("Requesting %s, with params: %v", apiPath, params != "") + return } @@ -117,19 +139,21 @@ func (u *Unifi) GetJSON(apiPath string) ([]byte, error) { if err != nil { return []byte{}, err } + resp, err := u.Do(req) if err != nil { return []byte{}, err } - defer func() { - _ = resp.Body.Close() - }() + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) if err != nil { return body, err } + if resp.StatusCode != http.StatusOK { err = fmt.Errorf("invalid status code from server %s", resp.Status) } + return body, err } diff --git a/core/unifi/unifi_test.go b/core/unifi/unifi_test.go index 9dc4a852..4494619d 100644 --- a/core/unifi/unifi_test.go +++ b/core/unifi/unifi_test.go @@ -9,6 +9,10 @@ import ( ) func TestNewUnifi(t *testing.T) { + /* NOT DONE: OPEN web server, check parameters posted, more. This test is incomplete. + a.EqualValues(`{"username": "user1","password": "pass2"}`, string(post_params), + "user/pass json parameters improperly encoded") + */ t.Parallel() a := assert.New(t) u := "http://127.0.0.1:64431" @@ -17,16 +21,12 @@ func TestNewUnifi(t *testing.T) { Pass: "pass2", URL: u, VerifySSL: false, - DebugLog: DiscardLogs, + DebugLog: discardLogs, } authReq, err := NewUnifi(c) a.NotNil(err) a.EqualValues(u, authReq.URL) a.Contains(err.Error(), "connection refused", "an invalid destination should produce a connection error.") - /* TODO: OPEN web server, check parameters posted, more. This test is incomplete. - a.EqualValues(`{"username": "user1","password": "pass2"}`, string(post_params), - "user/pass json parameters improperly encoded") - */ } func TestUniReq(t *testing.T) { @@ -35,7 +35,7 @@ func TestUniReq(t *testing.T) { p := "/test/path" u := "http://some.url:8443" // Test empty parameters. - authReq := &Unifi{Client: &http.Client{}, Config: &Config{URL: u, DebugLog: DiscardLogs}} + authReq := &Unifi{Client: &http.Client{}, Config: &Config{URL: u, DebugLog: discardLogs}} r, err := authReq.UniReq(p, "") a.Nil(err, "newrequest must not produce an error") a.EqualValues(p, r.URL.Path, @@ -46,7 +46,7 @@ func TestUniReq(t *testing.T) { // Test with parameters k := "key1=value9&key2=value7" - authReq = &Unifi{Client: &http.Client{}, Config: &Config{URL: "http://some.url:8443", DebugLog: DiscardLogs}} + authReq = &Unifi{Client: &http.Client{}, Config: &Config{URL: "http://some.url:8443", DebugLog: discardLogs}} r, err = authReq.UniReq(p, k) a.Nil(err, "newrequest must not produce an error") a.EqualValues(p, r.URL.Path, diff --git a/core/unifi/usg.go b/core/unifi/usg.go index d5cc7a21..42321fbc 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg.go @@ -239,10 +239,13 @@ func (v *USGStat) UnmarshalJSON(data []byte) error { var n struct { Gw `json:"gw"` } + v.Gw = &n.Gw + err := json.Unmarshal(data, v.Gw) // controller version 5.10. if err != nil { return json.Unmarshal(data, &n) // controller version 5.11. } + return nil } diff --git a/core/unifi/usg_test.go b/core/unifi/usg_test.go index 962dd677..16bb6a18 100644 --- a/core/unifi/usg_test.go +++ b/core/unifi/usg_test.go @@ -48,12 +48,13 @@ func TestUSGUnmarshalJSON(t *testing.T) { a := assert.New(t) u := &USGStat{} + lanRx := 37599596992669 err := u.UnmarshalJSON([]byte(testcontroller510)) a.Nil(err, "must be no error unmarshaling test strings") - a.Equal(float64(37599596992669), u.LanRxBytes.Val, "data was not properly unmarshaled") + a.Equal(float64(lanRx), u.LanRxBytes.Val, "data was not properly unmarshaled") u = &USGStat{} // reset err = u.UnmarshalJSON([]byte(testcontroller511)) a.Nil(err, "must be no error unmarshaling test strings") - a.Equal(float64(37599596992669), u.LanRxBytes.Val, "data was not properly unmarshaled") + a.Equal(float64(lanRx), u.LanRxBytes.Val, "data was not properly unmarshaled") } diff --git a/core/unifi/usw.go b/core/unifi/usw.go index f0dc88bc..d6eca554 100644 --- a/core/unifi/usw.go +++ b/core/unifi/usw.go @@ -364,10 +364,13 @@ func (v *USWStat) UnmarshalJSON(data []byte) error { var n struct { Sw `json:"sw"` } + v.Sw = &n.Sw + err := json.Unmarshal(data, v.Sw) // controller version 5.10. if err != nil { return json.Unmarshal(data, &n) // controller version 5.11. } + return nil } diff --git a/core/unifi/usw_test.go b/core/unifi/usw_test.go index a8220271..66bfac63 100644 --- a/core/unifi/usw_test.go +++ b/core/unifi/usw_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/assert" ) -func TestUSWUnmarshalJSON(t *testing.T) { - testcontroller511 := `{ +func testGetControllerJSON() (string, string) { + return `{ "sw": { "site_id": "mySite", "o": "sw", @@ -31,19 +31,8 @@ func TestUSWUnmarshalJSON(t *testing.T) { "tx_multicast": 123, "tx_broadcast": 123, "bytes": 123, - "duration": 123, - "port_1-tx_packets": 123, - "port_1-tx_bytes": 123, - "port_1-tx_multicast": 123, - "port_1-tx_broadcast": 123, - "port_1-rx_packets": 123, - "port_1-rx_bytes": 123, - "port_1-rx_dropped": 123, - "port_1-rx_multicast": 123, - "port_1-rx_broadcast": 123, - "port_1-rx_errors": 123}}` - - testcontroller510 := `{ + "duration": 123}}`, + `{ "site_id": "mySite", "o": "sw", "oid": "00:00:00:00:00:00", @@ -66,28 +55,21 @@ func TestUSWUnmarshalJSON(t *testing.T) { "tx_multicast": 123, "tx_broadcast": 123, "bytes": 123, - "duration": 123, - "port_1-tx_packets": 123, - "port_1-tx_bytes": 123, - "port_1-tx_multicast": 123, - "port_1-tx_broadcast": 123, - "port_1-rx_packets": 123, - "port_1-rx_bytes": 123, - "port_1-rx_dropped": 123, - "port_1-rx_multicast": 123, - "port_1-rx_broadcast": 123, - "port_1-rx_errors": 123}` + "duration": 123}` +} +func TestUSWUnmarshalJSON(t *testing.T) { t.Parallel() a := assert.New(t) - + testcontroller511, testcontroller510 := testGetControllerJSON() + rxMulticast := 123 u := &USWStat{} err := u.UnmarshalJSON([]byte(testcontroller510)) a.Nil(err, "must be no error unmarshaling test strings") - a.Equal(float64(123), u.RxMulticast.Val, "data was not properly unmarshaled") + a.Equal(float64(rxMulticast), u.RxMulticast.Val, "data was not properly unmarshaled") u = &USWStat{} // reset err = u.UnmarshalJSON([]byte(testcontroller511)) a.Nil(err, "must be no error unmarshaling test strings") - a.Equal(float64(123), u.RxMulticast.Val, "data was not properly unmarshaled") + a.Equal(float64(rxMulticast), u.RxMulticast.Val, "data was not properly unmarshaled") } From 7026de13982b398188efe918bad36588e9550b70 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Wed, 11 Dec 2019 01:10:33 -0800 Subject: [PATCH 113/194] fix cuddling --- core/unifi/ids.go | 1 + core/unifi/unifi.go | 3 ++- core/unifi/unifi_test.go | 9 +++++---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/core/unifi/ids.go b/core/unifi/ids.go index d28b7246..c0ece97c 100644 --- a/core/unifi/ids.go +++ b/core/unifi/ids.go @@ -121,6 +121,7 @@ func (u *Unifi) GetSiteIDS(site *Site, from, to time.Time) ([]*IDS, error) { if err != nil { return nil, err } + defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 84e4a167..a08552c7 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -70,8 +70,8 @@ func (u *Unifi) Login() error { if err != nil { return err } - defer resp.Body.Close() // we need no data here. + defer resp.Body.Close() // we need no data here. _, _ = io.Copy(ioutil.Discard, resp.Body) // avoid leaking. u.DebugLog("Requested %s: elapsed %v, returned %d bytes", APILoginPath, time.Since(start).Round(time.Millisecond), resp.ContentLength) @@ -144,6 +144,7 @@ func (u *Unifi) GetJSON(apiPath string) ([]byte, error) { if err != nil { return []byte{}, err } + defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) diff --git a/core/unifi/unifi_test.go b/core/unifi/unifi_test.go index 4494619d..9c9015fb 100644 --- a/core/unifi/unifi_test.go +++ b/core/unifi/unifi_test.go @@ -9,10 +9,6 @@ import ( ) func TestNewUnifi(t *testing.T) { - /* NOT DONE: OPEN web server, check parameters posted, more. This test is incomplete. - a.EqualValues(`{"username": "user1","password": "pass2"}`, string(post_params), - "user/pass json parameters improperly encoded") - */ t.Parallel() a := assert.New(t) u := "http://127.0.0.1:64431" @@ -59,3 +55,8 @@ func TestUniReq(t *testing.T) { a.Nil(err, "problem reading request body, POST parameters may be malformed") a.EqualValues(k, string(d), "POST parameters improperly encoded") } + +/* NOT DONE: OPEN web server, check parameters posted, more. This test is incomplete. +a.EqualValues(`{"username": "user1","password": "pass2"}`, string(post_params), + "user/pass json parameters improperly encoded") +*/ From f287cf6d0cdb0e522b7f408c9996a1d5da500852 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 15 Dec 2019 13:41:09 -0800 Subject: [PATCH 114/194] Add source parameter --- core/unifi/clients.go | 3 +++ core/unifi/devices.go | 8 ++++---- core/unifi/ids.go | 5 ++++- core/unifi/site.go | 3 +++ core/unifi/uap.go | 5 ++--- core/unifi/udm.go | 1 + core/unifi/usg.go | 1 + core/unifi/usw.go | 1 + 8 files changed, 19 insertions(+), 8 deletions(-) diff --git a/core/unifi/clients.go b/core/unifi/clients.go index a6be75c4..b9bcad71 100644 --- a/core/unifi/clients.go +++ b/core/unifi/clients.go @@ -19,6 +19,8 @@ func (u *Unifi) GetClients(sites Sites) (Clients, error) { } for i, d := range response.Data { + // Add special SourceName value. + response.Data[i].SourceName = u.URL // Add the special "Site Name" to each client. This becomes a Grafana filter somewhere. response.Data[i].SiteName = site.Desc + " (" + site.Name + ")" // Fix name and hostname fields. Sometimes one or the other is blank. @@ -37,6 +39,7 @@ type Clients []*Client // Client defines all the data a connected-network client contains. type Client struct { + SourceName string `json:"-"` Anomalies int64 `json:"anomalies,omitempty"` ApMac string `json:"ap_mac"` ApName string `json:"-"` diff --git a/core/unifi/devices.go b/core/unifi/devices.go index f6e77a65..d877d9c4 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -48,25 +48,25 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { switch assetType { // Unmarshal again into the correct type.. case "uap": - dev := &UAP{SiteName: siteName} + dev := &UAP{SiteName: siteName, SourceName: u.URL} 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} + dev := &USG{SiteName: siteName, SourceName: u.URL} 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} + dev := &USW{SiteName: siteName, SourceName: u.URL} if u.unmarshalDevice(assetType, r, dev) == nil { dev.Name = pick(dev.Name, dev.Mac) devices.USWs = append(devices.USWs, dev) } case "udm": - dev := &UDM{SiteName: siteName} + dev := &UDM{SiteName: siteName, SourceName: u.URL} if u.unmarshalDevice(assetType, r, dev) == nil { dev.Name = pick(dev.Name, dev.Mac) devices.UDMs = append(devices.UDMs, dev) diff --git a/core/unifi/ids.go b/core/unifi/ids.go index c0ece97c..7bb4232c 100644 --- a/core/unifi/ids.go +++ b/core/unifi/ids.go @@ -13,6 +13,7 @@ type IDSList []*IDS // IDS holds an Intrusion Prevention System Event. type IDS struct { + SourceName string `json:"-"` ID string `json:"_id"` Archived FlexBool `json:"archived"` Timestamp int64 `json:"timestamp"` @@ -94,7 +95,9 @@ func (u *Unifi) GetIDS(sites Sites, from, to time.Time) ([]*IDS, error) { if err != nil { return data, err } - + for i := range ids { + ids[i].SourceName = u.URL + } data = append(data, ids...) } diff --git a/core/unifi/site.go b/core/unifi/site.go index ae0df3a8..2789a8b6 100644 --- a/core/unifi/site.go +++ b/core/unifi/site.go @@ -15,6 +15,8 @@ func (u *Unifi) GetSites() (Sites, error) { sites := []string{} // used for debug log only for i, d := range response.Data { + // Add special SourceName value. + response.Data[i].SourceName = u.URL // If the human name is missing (description), set it to the cryptic name. response.Data[i].Desc = pick(d.Desc, d.Name) // Add the custom site name to each site. used as a Grafana filter somewhere. @@ -32,6 +34,7 @@ type Sites []*Site // Site represents a site's data. type Site struct { + SourceName string `json:"-"` ID string `json:"_id"` Name string `json:"name"` Desc string `json:"desc"` diff --git a/core/unifi/uap.go b/core/unifi/uap.go index 6e1238a6..172504b8 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -6,10 +6,9 @@ import ( ) // UAP represents all the data from the Ubiquiti Controller for a Unifi Access Point. +// This was auto generated then edited by hand to get all the data types right. type UAP struct { - /* This was auto generated and then slowly edited by hand - to get all the data types right and graphable. - */ + SourceName string `json:"-"` ID string `json:"_id"` Adopted FlexBool `json:"adopted"` AntennaTable []struct { diff --git a/core/unifi/udm.go b/core/unifi/udm.go index 51382435..172d0908 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -3,6 +3,7 @@ package unifi // UDM represents all the data from the Ubiquiti Controller for a Unifi Dream Machine. // The UDM shares several structs/type-data with USW and USG. type UDM struct { + SourceName string `json:"-"` SiteID string `json:"site_id"` SiteName string `json:"-"` Mac string `json:"mac"` diff --git a/core/unifi/usg.go b/core/unifi/usg.go index 42321fbc..d7aff5a1 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg.go @@ -7,6 +7,7 @@ import ( // USG represents all the data from the Ubiquiti Controller for a Unifi Security Gateway. type USG struct { + SourceName string `json:"-"` ID string `json:"_id"` Adopted FlexBool `json:"adopted"` Cfgversion string `json:"cfgversion"` diff --git a/core/unifi/usw.go b/core/unifi/usw.go index d6eca554..242b2053 100644 --- a/core/unifi/usw.go +++ b/core/unifi/usw.go @@ -7,6 +7,7 @@ import ( // USW represents all the data from the Ubiquiti Controller for a Unifi Switch. type USW struct { + SourceName string `json:"-"` SiteName string `json:"-"` ID string `json:"_id"` Adopted FlexBool `json:"adopted"` From 51666885889cd6f21e704a17f36073586aa17caf Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 15 Dec 2019 13:44:13 -0800 Subject: [PATCH 115/194] missed a commit --- core/unifi/ids.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/unifi/ids.go b/core/unifi/ids.go index 7bb4232c..6af0c8ab 100644 --- a/core/unifi/ids.go +++ b/core/unifi/ids.go @@ -95,9 +95,11 @@ func (u *Unifi) GetIDS(sites Sites, from, to time.Time) ([]*IDS, error) { if err != nil { return data, err } + for i := range ids { ids[i].SourceName = u.URL } + data = append(data, ids...) } From ccef9380475008631c0caa648173421a8659266d Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Thu, 26 Dec 2019 22:07:00 -0800 Subject: [PATCH 116/194] dpi data is no longer here --- core/unifi/Gopkg.lock | 41 ---------- core/unifi/Gopkg.toml | 3 - core/unifi/clients.go | 181 ++++++++++++++++++++---------------------- core/unifi/go.mod | 9 +++ core/unifi/go.sum | 5 ++ 5 files changed, 100 insertions(+), 139 deletions(-) delete mode 100644 core/unifi/Gopkg.lock delete mode 100644 core/unifi/Gopkg.toml create mode 100644 core/unifi/go.mod create mode 100644 core/unifi/go.sum diff --git a/core/unifi/Gopkg.lock b/core/unifi/Gopkg.lock deleted file mode 100644 index 82983fff..00000000 --- a/core/unifi/Gopkg.lock +++ /dev/null @@ -1,41 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" - name = "github.com/davecgh/go-spew" - packages = ["spew"] - pruneopts = "UT" - revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" - version = "v1.1.1" - -[[projects]] - digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" - name = "github.com/pmezard/go-difflib" - packages = ["difflib"] - pruneopts = "UT" - revision = "792786c7400a136282c1664665ae0a8db921c6c2" - version = "v1.0.0" - -[[projects]] - digest = "1:8548c309c65a85933a625be5e7d52b6ac927ca30c56869fae58123b8a77a75e1" - name = "github.com/stretchr/testify" - packages = ["assert"] - pruneopts = "UT" - revision = "221dbe5ed46703ee255b1da0dec05086f5035f62" - version = "v1.4.0" - -[[projects]] - digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96" - name = "gopkg.in/yaml.v2" - packages = ["."] - pruneopts = "UT" - revision = "51d6538a90f86fe93ac480b35f37b2be17fef232" - version = "v2.2.2" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - input-imports = ["github.com/stretchr/testify/assert"] - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/core/unifi/Gopkg.toml b/core/unifi/Gopkg.toml deleted file mode 100644 index 5c879c7d..00000000 --- a/core/unifi/Gopkg.toml +++ /dev/null @@ -1,3 +0,0 @@ -[prune] - go-tests = true - unused-packages = true diff --git a/core/unifi/clients.go b/core/unifi/clients.go index b9bcad71..2639d02e 100644 --- a/core/unifi/clients.go +++ b/core/unifi/clients.go @@ -39,99 +39,90 @@ type Clients []*Client // Client defines all the data a connected-network client contains. type Client struct { - SourceName string `json:"-"` - Anomalies int64 `json:"anomalies,omitempty"` - ApMac string `json:"ap_mac"` - ApName string `json:"-"` - AssocTime int64 `json:"assoc_time"` - Blocked bool `json:"blocked,omitempty"` - Bssid string `json:"bssid"` - BytesR int64 `json:"bytes-r"` - Ccq int64 `json:"ccq"` - Channel FlexInt `json:"channel"` - DevCat FlexInt `json:"dev_cat"` - DevFamily FlexInt `json:"dev_family"` - DevID FlexInt `json:"dev_id"` - DevVendor FlexInt `json:"dev_vendor,omitempty"` - DhcpendTime int `json:"dhcpend_time,omitempty"` - Satisfaction FlexInt `json:"satisfaction,omitempty"` - DpiStats struct { - App FlexInt - Cat FlexInt - RxBytes FlexInt - RxPackets FlexInt - TxBytes FlexInt - TxPackets FlexInt - } `json:"dpi_stats"` - DpiStatsLastUpdated int64 `json:"dpi_stats_last_updated"` - Essid string `json:"essid"` - FirstSeen int64 `json:"first_seen"` - FixedIP string `json:"fixed_ip"` - GwMac string `json:"gw_mac"` - GwName string `json:"-"` - Hostname string `json:"hostname"` - ID string `json:"_id"` - IP string `json:"ip"` - IdleTime int64 `json:"idle_time"` - Is11R FlexBool `json:"is_11r"` - IsGuest FlexBool `json:"is_guest"` - IsGuestByUAP FlexBool `json:"_is_guest_by_uap"` - IsGuestByUGW FlexBool `json:"_is_guest_by_ugw"` - IsGuestByUSW FlexBool `json:"_is_guest_by_usw"` - IsWired FlexBool `json:"is_wired"` - LastSeen int64 `json:"last_seen"` - LastSeenByUAP int64 `json:"_last_seen_by_uap"` - LastSeenByUGW int64 `json:"_last_seen_by_ugw"` - LastSeenByUSW int64 `json:"_last_seen_by_usw"` - LatestAssocTime int64 `json:"latest_assoc_time"` - Mac string `json:"mac"` - Name string `json:"name"` - Network string `json:"network"` - NetworkID string `json:"network_id"` - Noise int64 `json:"noise"` - Note string `json:"note"` - Noted FlexBool `json:"noted"` - OsClass FlexInt `json:"os_class"` - OsName FlexInt `json:"os_name"` - Oui string `json:"oui"` - PowersaveEnabled FlexBool `json:"powersave_enabled"` - QosPolicyApplied FlexBool `json:"qos_policy_applied"` - Radio string `json:"radio"` - RadioName string `json:"radio_name"` - RadioProto string `json:"radio_proto"` - RadioDescription string `json:"-"` - RoamCount int64 `json:"roam_count"` - Rssi int64 `json:"rssi"` - RxBytes int64 `json:"rx_bytes"` - RxBytesR int64 `json:"rx_bytes-r"` - RxPackets int64 `json:"rx_packets"` - RxRate int64 `json:"rx_rate"` - Signal int64 `json:"signal"` - SiteID string `json:"site_id"` - SiteName string `json:"-"` - SwDepth int `json:"sw_depth"` - SwMac string `json:"sw_mac"` - SwName string `json:"-"` - SwPort FlexInt `json:"sw_port"` - TxBytes int64 `json:"tx_bytes"` - TxBytesR int64 `json:"tx_bytes-r"` - TxPackets int64 `json:"tx_packets"` - TxRetries int64 `json:"tx_retries"` - TxPower int64 `json:"tx_power"` - TxRate int64 `json:"tx_rate"` - Uptime int64 `json:"uptime"` - UptimeByUAP int64 `json:"_uptime_by_uap"` - UptimeByUGW int64 `json:"_uptime_by_ugw"` - UptimeByUSW int64 `json:"_uptime_by_usw"` - UseFixedIP FlexBool `json:"use_fixedip"` - UserGroupID string `json:"usergroup_id"` - UserID string `json:"user_id"` - Vlan FlexInt `json:"vlan"` - WifiTxAttempts int64 `json:"wifi_tx_attempts"` - WiredRxBytes int64 `json:"wired-rx_bytes"` - WiredRxBytesR int64 `json:"wired-rx_bytes-r"` - WiredRxPackets int64 `json:"wired-rx_packets"` - WiredTxBytes int64 `json:"wired-tx_bytes"` - WiredTxBytesR int64 `json:"wired-tx_bytes-r"` - WiredTxPackets int64 `json:"wired-tx_packets"` + SourceName string `json:"-"` + Anomalies int64 `json:"anomalies,omitempty"` + ApMac string `json:"ap_mac"` + ApName string `json:"-"` + AssocTime int64 `json:"assoc_time"` + Blocked bool `json:"blocked,omitempty"` + Bssid string `json:"bssid"` + BytesR int64 `json:"bytes-r"` + Ccq int64 `json:"ccq"` + Channel FlexInt `json:"channel"` + DevCat FlexInt `json:"dev_cat"` + DevFamily FlexInt `json:"dev_family"` + DevID FlexInt `json:"dev_id"` + DevVendor FlexInt `json:"dev_vendor,omitempty"` + DhcpendTime int `json:"dhcpend_time,omitempty"` + Satisfaction FlexInt `json:"satisfaction,omitempty"` + Essid string `json:"essid"` + FirstSeen int64 `json:"first_seen"` + FixedIP string `json:"fixed_ip"` + GwMac string `json:"gw_mac"` + GwName string `json:"-"` + Hostname string `json:"hostname"` + ID string `json:"_id"` + IP string `json:"ip"` + IdleTime int64 `json:"idle_time"` + Is11R FlexBool `json:"is_11r"` + IsGuest FlexBool `json:"is_guest"` + IsGuestByUAP FlexBool `json:"_is_guest_by_uap"` + IsGuestByUGW FlexBool `json:"_is_guest_by_ugw"` + IsGuestByUSW FlexBool `json:"_is_guest_by_usw"` + IsWired FlexBool `json:"is_wired"` + LastSeen int64 `json:"last_seen"` + LastSeenByUAP int64 `json:"_last_seen_by_uap"` + LastSeenByUGW int64 `json:"_last_seen_by_ugw"` + LastSeenByUSW int64 `json:"_last_seen_by_usw"` + LatestAssocTime int64 `json:"latest_assoc_time"` + Mac string `json:"mac"` + Name string `json:"name"` + Network string `json:"network"` + NetworkID string `json:"network_id"` + Noise int64 `json:"noise"` + Note string `json:"note"` + Noted FlexBool `json:"noted"` + OsClass FlexInt `json:"os_class"` + OsName FlexInt `json:"os_name"` + Oui string `json:"oui"` + PowersaveEnabled FlexBool `json:"powersave_enabled"` + QosPolicyApplied FlexBool `json:"qos_policy_applied"` + Radio string `json:"radio"` + RadioName string `json:"radio_name"` + RadioProto string `json:"radio_proto"` + RadioDescription string `json:"-"` + RoamCount int64 `json:"roam_count"` + Rssi int64 `json:"rssi"` + RxBytes int64 `json:"rx_bytes"` + RxBytesR int64 `json:"rx_bytes-r"` + RxPackets int64 `json:"rx_packets"` + RxRate int64 `json:"rx_rate"` + Signal int64 `json:"signal"` + SiteID string `json:"site_id"` + SiteName string `json:"-"` + SwDepth int `json:"sw_depth"` + SwMac string `json:"sw_mac"` + SwName string `json:"-"` + SwPort FlexInt `json:"sw_port"` + TxBytes int64 `json:"tx_bytes"` + TxBytesR int64 `json:"tx_bytes-r"` + TxPackets int64 `json:"tx_packets"` + TxRetries int64 `json:"tx_retries"` + TxPower int64 `json:"tx_power"` + TxRate int64 `json:"tx_rate"` + Uptime int64 `json:"uptime"` + UptimeByUAP int64 `json:"_uptime_by_uap"` + UptimeByUGW int64 `json:"_uptime_by_ugw"` + UptimeByUSW int64 `json:"_uptime_by_usw"` + UseFixedIP FlexBool `json:"use_fixedip"` + UserGroupID string `json:"usergroup_id"` + UserID string `json:"user_id"` + Vlan FlexInt `json:"vlan"` + WifiTxAttempts int64 `json:"wifi_tx_attempts"` + WiredRxBytes int64 `json:"wired-rx_bytes"` + WiredRxBytesR int64 `json:"wired-rx_bytes-r"` + WiredRxPackets int64 `json:"wired-rx_packets"` + WiredTxBytes int64 `json:"wired-tx_bytes"` + WiredTxBytesR int64 `json:"wired-tx_bytes-r"` + WiredTxPackets int64 `json:"wired-tx_packets"` } diff --git a/core/unifi/go.mod b/core/unifi/go.mod new file mode 100644 index 00000000..80ac2e5c --- /dev/null +++ b/core/unifi/go.mod @@ -0,0 +1,9 @@ +module golift.io/unifi + +go 1.13 + +require ( + github.com/davecgh/go-spew v1.1.1 + github.com/pmezard/go-difflib v1.0.0 + github.com/stretchr/testify v1.4.0 +) diff --git a/core/unifi/go.sum b/core/unifi/go.sum new file mode 100644 index 00000000..0b286a58 --- /dev/null +++ b/core/unifi/go.sum @@ -0,0 +1,5 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= From 1ebc0e480485ac9a680d0e9ec37587b4af90cd7b Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Fri, 27 Dec 2019 20:32:32 -0800 Subject: [PATCH 117/194] Add DPI gathering methods --- core/unifi/.travis.yml | 2 +- core/unifi/clients.go | 30 +- core/unifi/dpi.go | 2366 ++++++++++++++++++++++++++++++++++++++++ core/unifi/go.sum | 6 + core/unifi/site.go | 35 +- core/unifi/types.go | 4 + core/unifi/udm.go | 108 +- core/unifi/unifi.go | 8 +- 8 files changed, 2483 insertions(+), 76 deletions(-) create mode 100644 core/unifi/dpi.go diff --git a/core/unifi/.travis.yml b/core/unifi/.travis.yml index cdcc5e6b..c7d4eacc 100644 --- a/core/unifi/.travis.yml +++ b/core/unifi/.travis.yml @@ -11,5 +11,5 @@ before_install: install: - dep ensure script: -- golangci-lint run --enable-all -e G402 +- golangci-lint run --enable-all -e G402 -D gochecknoglobals - go test ./... diff --git a/core/unifi/clients.go b/core/unifi/clients.go index 2639d02e..ca4ea34d 100644 --- a/core/unifi/clients.go +++ b/core/unifi/clients.go @@ -1,6 +1,8 @@ package unifi -import "fmt" +import ( + "fmt" +) // GetClients returns a response full of clients' data from the UniFi Controller. func (u *Unifi) GetClients(sites Sites) (Clients, error) { @@ -34,6 +36,32 @@ func (u *Unifi) GetClients(sites Sites) (Clients, error) { return data, nil } +// GetClientsDPI garners dpi data for clients. +func (u *Unifi) GetClientsDPI(sites Sites) ([]*DPITable, error) { + var data []*DPITable + + for _, site := range sites { + u.DebugLog("Polling Controller, retreiving Client DPI data, site %s (%s) ", site.Name, site.Desc) + + var response struct { + Data []*DPITable `json:"data"` + } + + clientDPIpath := fmt.Sprintf(APIClientDPI, site.Name) + if err := u.GetData(clientDPIpath, &response, `{"type":"by_app"}`); err != nil { + return nil, err + } + + for _, d := range response.Data { + d.SourceName = site.SourceName + d.SiteName = site.SiteName + data = append(data, d) + } + } + + return data, nil +} + // Clients contains a list that contains all of the unifi clients from a controller. type Clients []*Client diff --git a/core/unifi/dpi.go b/core/unifi/dpi.go new file mode 100644 index 00000000..86170d03 --- /dev/null +++ b/core/unifi/dpi.go @@ -0,0 +1,2366 @@ +package unifi + +import "strconv" + +// DPITable contains DPI data for clients or sites, or .. things. +type DPITable struct { + SourceName string `json:"-"` + SiteName string `json:"-"` + Name string `json:"-"` + MAC string `json:"mac"` + ByCat []DPIData `json:"by_cat"` + ByApp []DPIData `json:"by_app"` + LastUpdated int64 `json:"last_updated"` +} + +// DPIData is the DPI data in the DPI table. +type DPIData struct { + Cat int `json:"cat"` + App int `json:"app"` + RxBytes int64 `json:"rx_bytes"` + TxBytes int64 `json:"tx_bytes"` + RxPackets int64 `json:"rx_packets"` + TxPackets int64 `json:"tx_packets"` +} + +// DPIMap allows binding methods to the DPICat and DPIApps variables. +type DPIMap map[int]string + +// Get returns a value, or an unknown placeholder. +func (d DPIMap) Get(cat int) string { + if v, ok := d[cat]; ok { + return v + } + + return "Unknown_" + strconv.Itoa(cat) +} + +// GetApp returns an app value, or an unknown placeholder. +func (d DPIMap) GetApp(cat, app int) string { + if v, ok := d[cat<<16+app]; ok { + return v + } + + return "Unknown_" + strconv.Itoa(cat<<16+app) +} + +// Keys returns the map keys in a slice. +func (d DPIMap) Keys() []string { + out := []string{} + for k := range d { + out = append(out, strconv.Itoa(k)) + } + + return out +} + +// DPICats maps the categories to descriptions. +// From: https://fw-download.ubnt.com/data/usg-dpi/1628-debian-v1.442.0-05f5a57eaef344358bd5a8e84a184c18.tar +var DPICats = DPIMap{ + 0: "Instant Messengers", + 1: "Peer-to-Peer Networks", + 3: "File Sharing", + 4: "Media Streaming", + 5: "Email Messaging", + 6: "VoIP Services", + 7: "Database Tools", + 8: "Online Games", + 9: "Management Protocols", + 10: "Remote Access", + 11: "Tunneling and Proxy", + 12: "Investment Platforms", + 13: "Web Services", + 14: "Security Updates", + 15: "Web IM", + 17: "Business Tools", + 18: "Network Protocols_18", + 19: "Network Protocols_19", + 20: "Network Protocols_20", + 23: "Private Protocols", + 24: "Social Networks", + 255: "Unknown_255", +} + +// DPIApps maps the applications to names. +// From: https://fw-download.ubnt.com/data/usg-dpi/1628-debian-v1.442.0-05f5a57eaef344358bd5a8e84a184c18.tar +var DPIApps = DPIMap{ + 1: "MSN", + 2: "Yahoo Messenger", + 3: "AIM/ICQ/iIM", + 4: "QQ/TM", + 5: "DingTalk/Laiwang", + 6: "IRC", + 7: "Yoics", + 8: "Rediff BOL", + 9: "Google Talk", + 10: "Gadu-Gadu", + 11: "Yixin", + 12: "POPO", + 13: "Tlen", + 14: "Wlt", + 15: "RenRen", + 16: "Omegle", + 17: "IPMSG", + 18: "Aliww", + 19: "Mail.ru IM", + 20: "Kubao", + 21: "Lava-Lava", + 22: "PaltalkScene", + 23: "UcTalk", + 24: "WinpopupX", + 25: "BeeTalk", + 26: "Squiggle", + 27: "Apple iMessage", + 28: "Pidgin", + 29: "ISPQ", + 30: "Momo", + 31: "ChatON", + 32: "Caihong", + 33: "KC", + 34: "IMVU", + 35: "Instan-t", + 36: "PiIM", + 37: "Xfire", + 38: "Raidcall", + 39: "Slack", + 41: "WhatsApp", + 42: "Userplane", + 43: "24im", + 44: "Camfrog", + 45: "Snow", + 46: "Digsby", + 49: "Message Send Protocol", + 52: "SOMA", + 53: "Hike", + 54: "Fetion", + 55: "Heyyo", + 56: "Alicall", + 57: "Qeshow", + 58: "MissLee", + 59: "Jctrans", + 61: "BaiduHi", + 62: "TELTEL", + 64: "9158", + 65: "Kltx", + 66: "IM+", + 67: "Imi", + 68: "Netcall", + 69: "ECP", + 72: "Etnano", + 77: "ProvideSupport", + 78: "Dudu IM", + 80: "Weibo IM", + 81: "WO", + 82: "Guagua", + 83: "Hangouts", + 84: "ClubCooee", + 85: "Palringo", + 86: "KikMessenger", + 87: "Doshow", + 88: "Mibbit", + 89: "YY", + 90: "Ispeak", + 91: "VzoChat", + 92: "Trillian", + 93: "HipChat", + 94: "IntraMessenger", + 95: "BitWise", + 96: "Barablu", + 97: "Whoshere", + 98: "LiiHo", + 99: "Appme", + 100: "Verychat", + 101: "Voxer", + 102: "TextMe", + 103: "Bump", + 104: "CoolMessenger", + 105: "NateOn", + 106: "WeChat", + 107: "Snapchat", + 108: "Wangxin", + 65538: "BitTorrent Series", + 65540: "DirectConnect", + 65542: "eDonkey Series", + 65543: "FastTrack", + 65544: "Gnutella", + 65545: "WinMX", + 65546: "Foxy", + 65547: "Winny", + 65548: "POCO", + 65549: "iMesh/Lphant", + 65550: "ClubBox", + 65551: "Vagaa", + 65553: "Thunder", + 65554: "myMusic", + 65555: "QQDownload", + 65556: "WebTorrent", + 65557: "easyMule", + 65559: "Fileguri", + 65563: "Soulseek", + 65565: "GNUnet", + 65566: "XNap", + 65567: "Avicora", + 65568: "Kceasy", + 65569: "Aria2", + 65570: "Arctic", + 65572: "Bitflu", + 65573: "BTG", + 65574: "Pando", + 65577: "Deepnet Explorer", + 65578: "aMule", + 65580: "Ares", + 65581: "Azureus", + 65582: "BCDC++", + 65583: "BitBuddy", + 65584: "BitComet", + 65585: "BitTornado", + 65587: "ApexDC++", + 65588: "Bearshare", + 65590: "BitLord", + 65591: "BitSpirit", + 65594: "Shareaza", + 65598: "eMule", + 65600: "eMule Plus", + 65604: "FileScope", + 65609: "GoGoBox", + 65612: "Hydranode", + 65617: "Kazaa Lite Tools K++", + 65620: "BitRocket", + 65621: "MlDonkey", + 65622: "MooPolice", + 65630: "Phex", + 65633: "RevConnect", + 65634: "Rufus", + 65635: "SababaDC", + 65636: "Shareaza Plus", + 65640: "BTSlave", + 65642: "TorrentStorm", + 65648: "uTorrent", + 65652: "ZipTorrent", + 65655: "BitPump", + 65665: "Tuotu", + 65685: "Vuze", + 65686: "Enhanced CTorrent", + 65688: "Bittorrent X", + 65689: "DelugeTorrent", + 65690: "CTorrent", + 65691: "Propagate Data Client", + 65692: "EBit", + 65693: "Electric Sheep", + 65695: "FoxTorrent", + 65696: "GSTorrent", + 65698: "Halite", + 65700: "KGet", + 65701: "KTorrent", + 65703: "LH-ABC", + 65704: "libTorrent", + 65705: "LimeWire", + 65707: "MonoTorrent", + 65708: "MoonlightTorrent", + 65709: "Net Transport", + 65714: "qBittorrent", + 65715: "Qt 4 Torrent example", + 65716: "Retriever", + 65718: "Swiftbit", + 65720: "SwarmScope", + 65721: "SymTorrent", + 65722: "Sharktorrent", + 65724: "TorrentDotNET", + 65725: "Transmission", + 65726: "uLeecher", + 65727: "BitLet", + 65728: "FireTorrent", + 65730: "XanTorrent", + 65731: "Xtorrent", + 65732: "Pruna", + 65733: "Soribada", + 65734: "Gample", + 65735: "DIYHARD", + 65736: "LottoFile", + 65737: "ShareBox", + 65738: "Bondisk", + 65739: "Filei", + 65740: "KDISK", + 65741: "Ondisk", + 65742: "FILEJO", + 65743: "FILEDOK", + 65744: "Tomatopang/Santa25", + 65745: "Webhard", + 65746: "TPLE", + 65747: "DiskPump", + 65748: "NETFOLDER", + 65749: "QFILE", + 65750: "DISKMAN", + 65751: "DBGO", + 65752: "Congaltan", + 65753: "Diskpot", + 65754: "Ipopclub", + 65755: "Yesfile", + 65756: "Nedisk", + 65757: "Me2disk", + 65758: "Odisk", + 65759: "Tomfile", + 65760: "Adrive.co.kr", + 65761: "ZIOfile", + 65762: "APPLEFILE", + 65763: "SUPERDOWN", + 65764: "Hidisk", + 65765: "Downs", + 65766: "DownDay", + 65767: "BOMULBOX", + 65768: "FILEHAM", + 65769: "Tdisk", + 65770: "Filehon", + 65771: "Jjangfile", + 65772: "Onehard.com", + 65773: "Pdpop", + 65774: "AirFile", + 65775: "FILEZZIM", + 65776: "Atomfile.co.kr", + 65777: "QDOWN.com", + 65778: "Alfile.net", + 65779: "Bigfile.co.kr", + 65780: "Hardmoa.com", + 65781: "Redfile.co.kr", + 65782: "FILETV.co.kr", + 65783: "Now.co.kr", + 65784: "JustBeamIt", + 65785: "reep.io", + 65786: "GnucDNA/Gimme", + 65787: "MyNapster", + 196609: "FTP Applications", + 196610: "GetRight", + 196611: "FlashGet", + 196612: "AsianDVDClub", + 196613: "Web File Transfer", + 196614: "FileZilla", + 196615: "Kuaipan", + 196616: "DBank", + 196617: "115.com", + 196618: "Weiyun", + 196619: "Rayfile", + 196620: "0zz0", + 196621: "Herosh", + 196622: "2Shared", + 196624: "BIZHARD", + 196626: "UPlusBox", + 196627: "Filebox.ro", + 196628: "Qnext", + 196629: "OneDrive", + 196630: "YunFile", + 196631: "Filehosting", + 196632: "Dev-Host", + 196633: "Solidfiles", + 196634: "IBackup", + 196635: "FileSwap", + 196637: "Temp-Share", + 196638: "WikiUpload", + 196640: "MEGA", + 196641: "Copy.com", + 196642: "4Shared", + 196643: "HiCloud", + 196644: "Depositfiles", + 196645: "Docstoc", + 196646: "360 Cloud", + 196647: "Symantec Nomdb", + 196648: "Baidu Cloud", + 196649: "GitHub", + 196650: "FileDropper", + 196651: "CrashPlan", + 196652: "Net2FTP", + 196653: "Mediafire", + 196655: "Carbonite", + 196656: "Mozy", + 196657: "SOS Online Backup", + 196670: "NFS", + 196672: "WD My Cloud", + 196676: "Box", + 196678: "Scribd", + 196680: "Rapidshare", + 196681: "Sendspace", + 196683: "Hightail", + 196684: "Diino", + 196686: "Fluxiom", + 196689: "Nomadesk", + 196692: "Dropbox", + 196693: "Filesend.to", + 196694: "Firestorage", + 196695: "Naver Cloud", + 196696: "Filesend.net", + 196697: "Crocko", + 196700: "Fileserve", + 196701: "Netload", + 196702: "Megashares", + 196703: "TransferBigFiles", + 196705: "Filemail", + 196706: "Zamzar", + 196708: "Divshare", + 196709: "DL Free", + 196711: "Nakido", + 196713: "Gigaup", + 196714: "Filestube", + 196716: "Filer.cx", + 196717: "Cx.com", + 196718: "Elephantdrive", + 196722: "Zshare", + 196723: "Freakshare", + 196724: "Uploading", + 196725: "Bitshare", + 196726: "Letitbit.net", + 196727: "Extabit", + 196728: "Filefactory", + 196729: "Furk", + 196731: "GoldFile", + 196732: "GigaSize", + 196733: "Turbobit", + 196735: "Hitfile", + 196737: "Zippyshare", + 196738: "SoundCloud", + 196739: "SpeedyShare", + 196741: "WinSCP", + 196742: "FilePost.net", + 196743: "GlumboUploads", + 196744: "RapidGator.net", + 196745: "GoZilla", + 196746: "Clip2net", + 196747: "Datei.to", + 196748: "Totodisk", + 196749: "LeapFile", + 196750: "BigUpload", + 196751: "OnlineFileFolder", + 196752: "ASUSWebStorage", + 196753: "File-Upload.net", + 196754: "File-Works", + 196755: "Zumodrive", + 196756: "PutLocker", + 196757: "Wetransfer", + 196758: "iCloud", + 196759: "CloudMe", + 196760: "Beanywhere", + 196761: "Sugarsync", + 196762: "DriveHQ", + 196763: "Yandex.Disk", + 196764: "Backblaze", + 196765: "AirSet", + 196766: "SpiderOak", + 196767: "1337X", + 196768: "MailBigFile", + 196769: "GoldCoupon.co.kr", + 196770: "Egnyte", + 196771: "SmugMug", + 196772: "SlideShare.net", + 196773: "4Sync", + 196774: "IDrive", + 196775: "Mendeley", + 196777: "Daum-cloud", + 196778: "TeamBeam", + 262145: "Windows Media Player", + 262146: "RealPlayer", + 262147: "Winamp", + 262148: "QuickTime", + 262149: "Weather Channel", + 262150: "PPTV (PPLive)", + 262151: "QQLive", + 262152: "LOVEFiLM", + 262153: "ITV", + 262154: "iTunes", + 262155: "Adobe Flash", + 262156: "Channel 5", + 262157: "iQIYI/PPS", + 262158: "Headweb", + 262159: "Viaplay", + 262160: "KKBox", + 262161: "WATCHEVER", + 262162: "Maxdome", + 262163: "Twitch.tv", + 262164: "TED", + 262165: "RTP", + 262166: "SBS", + 262167: "UUSee", + 262168: "SopCast", + 262169: "KeyHoleTV", + 262170: "Sina Video", + 262171: "Metacafe", + 262172: "Wuaki.tv", + 262173: "SHOUTcast", + 262174: "BBC-iplayer", + 262175: "Live365", + 262176: "Dailymotion", + 262177: "Filmin", + 262178: "Flixster", + 262179: "Hulu", + 262180: "GuaGua", + 262181: "NUBEOX", + 262182: "Kugou", + 262183: "MoveNetworks", + 262184: "Babelgum", + 262185: "Livestation", + 262186: "Apple Music", + 262187: "Miro", + 262188: "Smithsonian Channel", + 262189: "NHL", + 262190: "NicoNico", + 262191: "Ooyala", + 262192: "Photobucket", + 262193: "MLSsoccer", + 262194: "Channel 4", + 262195: "VideoDetective", + 262196: "Ustream.tv", + 262197: "Veetle", + 262198: "VeohTV", + 262199: "iTunes Festival", + 262200: "SiriusXM", + 262201: "Break.com", + 262202: "CinemaNow/FilmOn", + 262203: "Letv", + 262204: "RTSP", + 262205: "Funshion", + 262206: "17", + 262207: "MTV.com", + 262208: "Sohu TV", + 262209: "MP4", + 262210: "MMS/WMSP", + 262211: "FLV", + 262212: "PIPI", + 262213: "Hulkshare", + 262214: "Tudou", + 262215: "Ifeng Video ", + 262216: "WSJ Live", + 262217: "Cradio", + 262218: "Roku", + 262219: "Amazon Prime Music", + 262220: "Crackle", + 262221: "Blip.tv", + 262223: "Audible", + 262224: "Web Streaming", + 262225: "DIRECTV", + 262226: "Vyclone", + 262227: "China Streaming Video", + 262228: "Crunchyroll", + 262229: "EmpFlix", + 262230: "Porn.com", + 262231: "EskimoTube", + 262232: "NewBigTube", + 262233: "Madbitties", + 262234: "RTMP", + 262235: "Hustlertube", + 262236: "TnaFlix", + 262237: "Xtube", + 262238: "Yobt.tv", + 262239: "Youjizz", + 262240: "v.163.com", + 262241: "Yahoo Video", + 262245: "Pandora", + 262246: "Deezer", + 262247: "VLC", + 262250: "Livesearch.tv/CoolStreaming", + 262251: "Qello", + 262252: "CNTV", + 262254: "Thunderkankan", + 262256: "Youtube", + 262258: "56.com", + 262259: "RMVB", + 262260: "Youku.com", + 262261: "SWF", + 262262: "AVI", + 262263: "MP3", + 262264: "WMA", + 262265: "MOV", + 262266: "WMV", + 262267: "ASF", + 262268: "Vudu", + 262270: "PBS Video", + 262271: "Freecast", + 262272: "Ku6", + 262274: "Spotify", + 262275: "LastFM", + 262276: "Netflix", + 262277: "Uitzendinggemist", + 262278: "RTL.nl", + 262279: "TudouVa", + 262280: "GYAO", + 262281: "BARKS", + 262283: "Baofeng", + 262284: "Qvod/Bobohu", + 262285: "Grooveshark", + 262286: "Microsoft Silverlight", + 262287: "6.cn", + 262288: "Rhapsody", + 262289: "Kideos", + 262290: "Imgo TV", + 262291: "Joy.cn", + 262292: "Yinyuetai", + 262293: "Hichannel", + 262294: "ADNstream", + 262295: "Livestream", + 262296: "YoukuVa ", + 262297: "Kodi", + 262298: "Voddler", + 262299: "National Geographic Kids", + 262301: "Flixwagon", + 262302: "M4V", + 262303: "Podcast", + 262305: "Shazam", + 262306: "TuneIn", + 262307: "PBS Kids", + 262308: "BaiduMusic", + 262310: "DoubanFM", + 262311: "IMDb.com", + 262312: "XVideos.com", + 262313: "xHamster.com", + 262314: "PornHub.com", + 262315: "LiveJasmin.com", + 262316: "XNXX.com", + 262317: "YouPorn.com", + 262318: "MajorLeagueGaming", + 262319: "Wowtv.co.kr", + 262320: "iMBC", + 262321: "AfreecaTV", + 262322: "Arirang", + 262323: "KCTVjeju", + 262324: "CJB.co.kr", + 262325: "MBN", + 262326: "MYSolive", + 262327: "KBS", + 262328: "Mwave", + 262329: "YTN", + 262330: "Musicsoda", + 262331: "FreeOnes.com", + 262332: "Streamate.com", + 262333: "Airplay", + 262334: "DAAP", + 262335: "M1905", + 262336: "VEVO", + 262337: "Amazon Instant Video", + 262338: "MixBit", + 262339: "Baomihua", + 262340: "FORA.tv", + 262341: "Vimeo", + 262342: "Vube", + 262343: "RedTube.com", + 262344: "Tube8", + 262345: "Mgoon", + 262346: "Trailers", + 262347: "HBOGO", + 262348: "MLB.com", + 262349: "Kaltura.com", + 262350: "Plex.tv", + 262351: "DouyuTV", + 262358: "Kids.gov", + 262367: "Periscope", + 262373: "HBO NOW", + 262374: "MiaoPai", + 262389: "UniFi Video Camera", + 327681: "SMTP", + 327682: "POP3", + 327683: "IMAP4", + 327684: "NNTP", + 327685: "Twig", + 327686: "GroupWise", + 327687: "au one net", + 327688: "Virtru", + 327689: "PChome", + 327690: "DTI MyMail", + 327691: "Ymail", + 327692: "IIJ MailViewer", + 327693: "Telenet Mail", + 327694: "Open Mail", + 327695: "InfoSphere Webmail", + 327696: "Goo Mail", + 327697: "Nifty", + 327698: "QQ Mail", + 327699: "Roundcubemail", + 327700: "Zenno", + 327701: "Itm-asp", + 327702: "Biglobe", + 327703: "SquirrelMail", + 327704: "Zoho Mail", + 327705: "Inter7", + 327706: "TOK2", + 327707: "Smoug", + 327708: "1und1", + 327709: "Plala", + 327710: "WAKWAK", + 327711: "Eyejot", + 327712: "AsahiNet", + 327713: "Aikq", + 327714: "Yandex.Mail", + 327715: "Arcor", + 327716: "Bluewin", + 327717: "Directbox", + 327718: "Freenet", + 327720: "Smart Mail", + 327722: "WEB.DE", + 327723: "MS Exchange Server", + 327732: "Webmail.de", + 327742: "NETEASE Mail", + 327743: "Gmx Mail", + 327744: "Excite", + 327745: "InfoSeek Mail", + 327746: "Livedoor", + 327747: "Nate Mail", + 327749: "Optimum", + 327751: "Secureserver", + 327753: "Sina Mail", + 327755: "Rambler", + 327760: "Daum Mail", + 327761: "Mail.com", + 327762: "OCN", + 327763: "MailChimp", + 327764: "Rediff Mail", + 327770: "Korea Mail", + 327772: "MyEmail", + 327773: "JumboMail", + 327775: "Gmail", + 327776: "AOL Mail", + 327777: "hiBox", + 327778: "COX", + 327779: "Hushmail", + 327780: "Mail.ru", + 327781: "HiNet Mail", + 327782: "Horde", + 327783: "Fastmail", + 327784: "Comcast", + 327785: "Laposte", + 327786: "Yahoo Mail", + 327787: "Usermin Mail", + 327788: "Tistory", + 327789: "Orange", + 327790: "012mail", + 327791: "T-Online", + 327792: "Jubii Mail", + 327793: "Whalemail", + 327794: "Lavabit", + 327795: "Tiscali", + 393217: "Skype", + 393218: "H.323", + 393220: "Facetime", + 393221: "Juiker", + 393222: "Sqwiggle", + 393223: "ooVoo", + 393225: "TeamSpeak", + 393226: "Ventrilo", + 393228: "SIP", + 393229: "NetMeeting", + 393230: "Inter-Asterisk", + 393231: "Net2Phone", + 393232: "MSRP", + 393234: "LINE", + 393235: "Fring", + 393236: "Goober", + 393238: "Viber", + 393239: "Kakao", + 393240: "iCall", + 393242: "Nimbuzz", + 393243: "Bobsled", + 393244: "indoona", + 393245: "Wi-Fi Calling", + 393246: "Tango", + 393247: "Ooma", + 458753: "MSSQL", + 458754: "MySQL", + 458755: "Oracle", + 458756: "PostgreSQL", + 458757: "SAP", + 458760: "Etelos", + 458761: "Centriccrm", + 458766: "MongoDB", + 458767: "Salesforce", + 458768: "MariaDB", + 524289: "QQ Game", + 524290: "Our Game", + 524291: "Cga.com", + 524292: "FIFA", + 524293: "PopKart", + 524294: "Archlord", + 524295: "AddictingGames.com", + 524296: "Realgame", + 524297: "Audition", + 524298: "Koramgame", + 524299: "BnB Game", + 524300: "Chinagame", + 524301: "CS Game", + 524302: "Diablo", + 524303: "Legend", + 524304: "Lineage", + 524306: "Quake Game", + 524307: "Diablo3", + 524308: "Sina Web Game", + 524310: "WOW Game", + 524311: "Ispeakgame", + 524312: "Torchlight2", + 524313: "MapleStory", + 524314: "TowerOfSaviors", + 524315: "Wolfenstein", + 524316: "Second Life", + 524317: "Kimi", + 524318: "Pokemon Go", + 524319: "PartyPoker", + 524320: "Pogo", + 524321: "PokerStars", + 524322: "Zango", + 524323: "Little Fighter 2", + 524324: "BomberClone", + 524325: "Doom", + 524326: "FSJOY", + 524327: "175pt", + 524328: "Zhuxian", + 524329: "GameTea/GameABC", + 524330: "Talesrunner", + 524331: "PK Game", + 524332: "Concerto Gate", + 524333: "TLBB", + 524334: "YBOnline", + 524335: "Xunyou", + 524336: "Mwo", + 524337: "Mobile Strike", + 524338: "WuLin", + 524339: "DNF Game", + 524340: "Bo Game", + 524341: "Gran Turismo", + 524343: "Electronic Arts", + 524344: "ZhengTu", + 524345: "SGOL", + 524346: "XY2Online", + 524347: "Asherons Call", + 524348: "Kali", + 524349: "EverQuest", + 524350: "XBOX", + 524351: "BrettspielWelt", + 524352: "Bet-at-Home", + 524353: "City of Heroes", + 524354: "ClubPenguin", + 524355: "StepMania", + 524356: "Battle.net", + 524358: "Apprentice", + 524359: "Monster Hunter Frontier Z", + 524360: "FreeLotto Game", + 524361: "Halo", + 524362: "iSketch", + 524363: "RuneScape", + 524364: "FUNMILY", + 524365: "Yeapgame", + 524366: "Grand Theft Auto", + 524367: "Lineage2", + 524368: "GM99 Game", + 524369: "RayCity", + 524370: "Rockstar Games", + 524371: "Aleph One", + 524372: "Wayi", + 524373: "CMWEBGAME", + 524374: "Call of Duty", + 524375: "CAPTAN", + 524376: "Supercell", + 524377: "Need for Speed", + 524379: "Madden NFL", + 524380: "Half-Life", + 524381: "Team Fortress", + 524383: "Final Fantasy", + 524384: "Mythic", + 524385: "NetPanzer", + 524386: "Sdo.com", + 524388: "Pokemon Netbattle", + 524389: "RunUO-Ultima", + 524390: "Soldat Dedicated", + 524391: "Blizzard Entertainment", + 524392: "RIFT", + 524393: "TetriNET", + 524394: "Tibia", + 524395: "PlanetSide", + 524396: "TripleA", + 524398: "Unreal", + 524399: "Valve Steam", + 524400: "WesNOth", + 524401: "Xpilot", + 524402: "Swtor", + 524403: "EVEOnline", + 524404: "Hearthstone", + 524405: "Guild Wars", + 524406: "Zhong Hua Hero", + 524407: "Wizard101", + 524408: "SD Gundam", + 524409: "Prius", + 524410: "Age of Conan", + 524411: "RF Returns", + 524412: "AION", + 524413: "POPO Game", + 524414: "War-Rock", + 524415: "TEN Game", + 524416: "LUNA2", + 524417: "Karos", + 524418: "SPOnline", + 524419: "RO Game", + 524420: "StarCraft2", + 524421: "Itaiwanmj", + 524422: "CMWEBGAME Game", + 524423: "Beanfun Game", + 524424: "JXW", + 524425: "Nobol", + 524426: "DragonNest", + 524427: "BBonline", + 524428: "Hangame", + 524429: "Homygame", + 524430: "Sony PlayStation", + 524431: "Garena", + 524432: "91555", + 524433: "JJ Game", + 524434: "YHgame", + 524435: "Mdm365", + 524436: "7fgame", + 524437: "Dokee", + 524438: "VSA", + 524439: "Funtown", + 524440: "SF Game", + 524441: "173kh", + 524442: "Boyaapoker", + 524443: "GameCenter", + 524444: "Minecraft", + 524445: "Dark Souls", + 524446: "The Secret World", + 524447: "World2", + 524448: "CrossFire", + 524449: "XYQ", + 524450: "Nexon", + 524451: "Vindictus", + 524452: "DotA", + 524453: "PAYDAY", + 524454: "Wayi Game", + 524455: "War Thunder", + 524456: "Warframe", + 524457: "TT-Play Game", + 524458: "TT-Play", + 524459: "Robocraft", + 524460: "World of Tanks", + 524461: "Divinity", + 524462: "Left 4 Dead 2", + 524463: "DayZ", + 524464: "Heroes of the Storm", + 524466: "TXWY Game", + 524476: "Smite", + 524478: "FreeStyle 2 Street Basketball", + 524479: "Yeapgame Game", + 524483: "BlackShot", + 524486: "Combat Arms", + 524490: "Blade and Soul", + 524491: "FUNMILY Game", + 524500: "Elsword", + 524501: "Echo of Soul", + 524502: "Aura Kingdom", + 524503: "Aeria Games", + 524504: "9-yin", + 524505: "Tera", + 524506: "PSO2", + 524507: "Mabinogi", + 524510: "Ubisoft", + 524512: "Sony Entertainment Network", + 524513: "WSOP", + 524514: "TexasHoldemPoker", + 524515: "DarkSummoner", + 524516: "AjaxPlay", + 524517: "AirlineMogul", + 524518: "Evony", + 524519: "BasketBallZone", + 524520: "Y8 Game", + 524521: "Y8-Y8", + 524522: "KIZI-GAMES", + 524523: "Ibibo", + 524524: "Hattrick Game", + 524525: "Godgame", + 524526: "Aswordtw", + 524527: "Qme RO", + 524529: "THE WORLD", + 524530: "Qme JH", + 524531: "Qme COS", + 524532: "Qme SG", + 524533: "Origin", + 524534: "LoL", + 524535: "THISISGAME", + 524536: "Miniclip Game", + 524537: "888games", + 524538: "WilliamHill", + 524539: "Betfair Game", + 524540: "Kongregate Game", + 524541: "Roblox Game", + 524542: "King Game", + 524543: "Chess Game", + 524593: "Overwatch", + 524632: "Battlefield", + 524633: "Star Wars Battlefront", + 524639: "Rainbow Six Siege", + 524640: "ARK Survival Evolved", + 524641: "The Division", + 524648: "Super Mario Run", + 524649: "Nintendo", + 524651: "Clash of Clans", + 524652: "Clash Royale", + 524736: "Grand Theft Auto: San Andreas", + 524782: "Destiny 2", + 524790: "NBA 2K18", + 524794: "Uncharted: The Lost Legacy", + 524795: "NHL 18", + 524796: "NBA Live 18", + 524801: "Wargaming.net", + 589828: "IGMP", + 589829: "SNMP", + 589885: "DNS", + 589888: "Multicast DNS", + 589890: "Finger protocol", + 589916: "DCE-RPC", + 589933: "SSDP", + 589934: "SMB", + 589936: "SMB2", + 589942: "ICMP", + 589951: "UPnP", + 655361: "pcAnywhere", + 655362: "VNC", + 655363: "TeamViewer", + 655364: "MS Remote Desktop Protocol (RDP)", + 655365: "Chrome Remote Desktop", + 655366: "NTRglobal", + 655367: "RemoteCall", + 655368: "LiveCare", + 655369: "GoToMyPC", + 655370: "Pulseway", + 655371: "Radmin", + 655372: "Beinsync", + 655373: "Fastviewer", + 655374: "CrossTec Remote Control", + 655375: "GoToMeeting", + 655376: "ShowMyPC", + 655377: "Join.me", + 655378: "Telnet", + 655379: "Techinline", + 655380: "ISL Online", + 655381: "Secure Shell (SSH)", + 655385: "IBM Remote monitoring and Control", + 655395: "Netviewer", + 655396: "VT100", + 655397: "AnyDesk", + 655398: "X11", + 655399: "Alpemix", + 655402: "Instanthousecall", + 655403: "Ammyy", + 655404: "Anyplace Control", + 655405: "BeamYourScreen", + 655406: "Laplink Everywhere", + 655407: "GoToAssist", + 655408: "MSP Anywhere", + 720898: "VNN", + 720899: "Spotflux", + 720900: "SoftEther/PacketiX", + 720901: "TinyVPN", + 720902: "HTTP-Tunnel", + 720903: "Tor", + 720904: "Ping Tunnel", + 720905: "Wujie/UltraSurf", + 720906: "Freegate", + 720907: "Hidemyass", + 720909: "Vedivi", + 720910: "ZenMate", + 720911: "Hamachi", + 720912: "Disconnect.me", + 720914: "Asproxy", + 720915: "OpenDoor", + 720916: "NSTX DNS Tunnel", + 720917: "Coralcdn", + 720918: "Glype", + 720919: "GPass", + 720920: "Kproxy", + 720921: "Megaproxy", + 720922: "FreeSafeIP", + 720924: "GreenVPN", + 720925: "Surrogafier", + 720926: "Vtunnel", + 720927: "GomVPN", + 720928: "BypassThat", + 720929: "GetPrivate", + 720930: "JAP/JonDo", + 720933: "SofaWare", + 720934: "FlyProxy", + 720936: "Kerberos", + 720939: "EasyHideIP", + 720942: "CPROXY", + 720943: "AnonyMouse", + 720945: "Avoidr", + 720946: "Hidedoor", + 720948: "CGIProxy", + 720949: "ProxyTopSite", + 720950: "Phproxy", + 720951: "OpenVPN", + 720952: "CCProxy", + 720953: "Proxy Rental", + 720954: "PD-Proxy", + 720955: "Proxy4Free", + 720957: "Hideman", + 720959: "Rtmpt", + 720960: "LogMeIn", + 720961: "HotspotShield", + 720962: "ExpressVPN", + 720963: "GogoNET", + 720964: "HTTP Proxy Server", + 720965: "Hola", + 720966: "Texasproxy", + 720967: "Ourproxy", + 720968: "Proxify", + 720969: "Fast Proxy", + 720970: "Zalmos", + 720971: "Easy Proxy", + 720972: "Proxy Era", + 720973: "DotVPN", + 720974: "BrowSec", + 720976: "Unblock Proxy", + 720977: "Air-Proxy", + 720978: "Suresome", + 720979: "Defilter", + 720980: "SSLunblock", + 720983: "K12History", + 720984: "SurfEasy", + 720985: "Frozenway", + 720986: "CyberGhostVPN", + 720987: "SecurityKISS", + 720988: "WebWarper", + 720989: "Guardster", + 720990: "ProxFree", + 720991: "TunnelBear", + 720992: "AstrillVPN", + 720993: "Hide ALL IP", + 720994: "ZfreeZ", + 720995: "IPVanish", + 720996: "PrivateTunnel", + 720997: "SaferSurf", + 720998: "SecureLine VPN", + 720999: "Steganos VPN", + 721000: "StrongVPN", + 721001: "ZeroTier", + 721002: "Ngrok", + 721003: "Pagekite", + 721004: "Goproxing", + 721005: "VPN.HT", + 721006: "Betternet", + 721007: "Hide My IP", + 721008: "Stay Invisible", + 721009: "Zapyo", + 721010: "NordVPN", + 721011: "Avast SecureLine", + 721013: "Tunnello", + 721014: "Opera VPN", + 786434: "DZH", + 786435: "10JQKA", + 786437: "Qianlong", + 786438: "Compass.cn", + 786439: "Huaan", + 786440: "StockStar ", + 786441: "TDX", + 786443: "Hexun", + 786444: "Hypwise", + 786449: "Kiwoom", + 786450: "Windin", + 786451: "SamsungPoP", + 786453: "StockTrace", + 786454: "JRJ", + 786455: "TradeFields", + 786456: "Bloomberg", + 786457: "Netdania", + 786458: "TradeInterceptor", + 851969: "WhiteHat Aviator", + 851970: "HTC Widget", + 851971: "Doodle", + 851972: "Level3", + 851973: "FuzeMeeting", + 851974: "Mobile01", + 851975: "Speedtest.net", + 851976: "Google Chrome", + 851977: "Babelfish", + 851978: "Google Translate", + 851980: "Mozilla Firefox", + 851981: "Apple Safari", + 851982: "Opera browser", + 851984: "Google Books", + 851985: "eBay", + 851986: "hao123", + 851987: "WebSocket", + 851988: "Tmall", + 851989: "PayPal.com", + 851990: "Ask.com", + 851991: "BBC", + 851992: "Alibaba.com", + 851993: "CNN.com", + 851995: "Sogou.com", + 851996: "Evernote", + 851997: "About.com", + 851998: "Alipay.com", + 851999: "Imgur", + 852000: "Adcash", + 852001: "Huffington Post", + 852002: "360buy", + 852003: "ESPN", + 852004: "Books", + 852005: "Craigslist.org", + 852006: "Google Analytics", + 852007: "Bing Maps", + 852008: "ETtoday ", + 852009: "104 Job Bank", + 852010: "NOWnews", + 852011: "518 Job Bank", + 852012: "Chinatimes.com", + 852013: "GOHAPPY", + 852014: "591", + 852015: "8591", + 852016: "Chinatrust", + 852017: "Donga.com", + 852018: "Gmarket", + 852019: "Chosun.com", + 852020: "Cafe24.com", + 852021: "11st", + 852022: "MK.co.kr", + 852023: "Auction", + 852024: "Hankyung", + 852025: "Ppomppu", + 852026: "MT.co.kr", + 852027: "Zum.com", + 852028: "Hankooki", + 852029: "JOBKOREA", + 852031: "Khan.co.kr", + 852032: "Incruit", + 852033: "YES24", + 852034: "Amazon CloudFront", + 852035: "Pcstore", + 852036: "Myfreshnet.com", + 852037: "Microsoft.com", + 852038: "Life.com.tw", + 852039: "Libertytimes", + 852040: "Lativ", + 852041: "Inven", + 852042: "cnYES", + 852043: "Babyhome", + 852044: "8comic.com", + 852045: "Ck101.com", + 852046: "Taiwanlottery", + 852047: "Momoshop", + 852048: "Eyny.com", + 852049: "Yam.com", + 852050: "PChome.com", + 852051: "Gamme", + 852052: "Apple.com", + 852053: "Hinet.net", + 852054: "Google Earth", + 852055: "Saramin", + 852056: "KoreaHerald", + 852057: "Plus28.com", + 852058: "ChunghwaPost ", + 852059: "Gomaji ", + 852060: "NewSen", + 852061: "Etnews.com", + 852062: "Seoul.co.kr", + 852063: "YONHAPNEWS", + 852064: "Etoday.co.kr", + 852065: "Yesky.com", + 852066: "1111 Job Bank", + 852067: "Emart", + 852068: "KBstar", + 852069: "HERALDCORP", + 852070: "ActiveX", + 852071: "MSN.com", + 852072: "Edaily", + 852073: "Segye", + 852074: "Bobaedream", + 852075: "Nocutnews", + 852076: "MONETA.co.kr", + 852077: "Kukinews", + 852078: "Java Applet", + 852079: "Todayhumor", + 852080: "Inews24", + 852081: "KoreaTimes", + 852082: "OhmyNews", + 852083: "Aladin.co.kr", + 852084: "SK Encar", + 852085: "eTorrent", + 852086: "TVREPORT", + 852087: "Mydaily", + 852088: "Microsoft Live.com", + 852089: "News1.kr", + 852090: "Munhwa", + 852091: "Dreamwiz", + 852092: "Dailian.co.kr", + 852093: "Rediff.com", + 852094: "Akamai.net", + 852096: "Microsoft Edge", + 852097: "Yugma", + 852098: "TPB PirateBrowser", + 852099: "Android browser", + 852100: "Wikispaces", + 852101: "Wikidot", + 852102: "Google Play", + 852103: "Wetpaint", + 852104: "Windows Store", + 852105: "Webshots", + 852106: "Kindle Cloud Reader", + 852107: "Nice264", + 852108: "Symbian browser", + 852109: "Vyew", + 852110: "TikiWiki", + 852111: "Castfire", + 852112: "Mercari", + 852113: "SugarCRM", + 852115: "Stumbleupon", + 852116: "Yahoo Shopping", + 852117: "Clothes Aoyama", + 852118: "Rakuten Shopping", + 852119: "Spark", + 852120: "Socialtext", + 852121: "CacaoWeb", + 852122: "PBworks", + 852123: "Fool", + 852124: "Showbie", + 852125: "MorningStar", + 852126: "Screaming Frog SEO Spider", + 852127: "MoinMoin", + 852128: "AppStore", + 852129: "Ragingbull", + 852130: "Daum", + 852131: "Google Docs", + 852133: "Naver", + 852134: "Editgrid", + 852135: "Jaspersoft", + 852136: "Clarizen", + 852139: "Interpark", + 852140: "Hyundaihmall", + 852141: "Groupon", + 852142: "Gsshop", + 852143: "Wemakeprice", + 852144: "Lotte.com", + 852145: "Coupang", + 852147: "Google Alerts", + 852149: "Dnshop.com", + 852150: "ZoomSpider crawler", + 852151: "Win Web Crawler", + 852152: "HTTrack crawler", + 852153: "Abot crawler", + 852154: "Googlebot crawler", + 852155: "Microsoft bingbot crawler", + 852156: "Yahoo Slurp crawler", + 852157: "Beanfun", + 852158: "QUIC", + 852159: "ifeng.com", + 852160: "Conduit Mobile", + 852161: "Rakuten Point", + 852162: "Gamebase", + 852163: "Kingstone", + 852164: "Udn.com", + 852165: "Fril", + 852166: "Sportsseoul", + 852167: "Babylon ", + 852168: "Yahoo Finance", + 852170: "Creative Cloud", + 852171: "Jira", + 852172: "PHPwiki", + 852173: "Rakuten Edy", + 852174: "WebCT", + 852175: "Youseemore", + 852176: "Zwiki-editing", + 852177: "Adobe.com", + 852178: "Backpackit/Campfire", + 852180: "ERoom-net", + 852182: "DiDiTaxi", + 852184: "Glide", + 852186: "Mediawiki", + 852187: "fitbit", + 852188: "LastPass", + 852189: "National Geographic", + 852190: "HTTP", + 852191: "AOL Toolbar", + 852192: "Yandex.Browser", + 852193: "Uber", + 852194: "Web-crawler", + 852195: "RSS", + 852196: "WeatherBug", + 852197: "Yahoo Toolbar", + 852198: "Alexa Toolbar", + 852199: "Internet Archive", + 852200: "Wikipedia", + 852201: "Wiktionary", + 852202: "Amazon", + 852203: "Google Toolbar", + 852205: "Zoho", + 852206: "Microsoft Internet Explorer", + 852207: "Localmind", + 852208: "LinkedIn Pulse", + 852209: "BookU", + 852210: "Zappos", + 852211: "Expedia", + 852212: "AdF.ly", + 852213: "Baidu", + 852214: "Yahoo", + 852215: "Taobao", + 852216: "163.com", + 852217: "Sina.com", + 852218: "Bing.com", + 852219: "Ruten", + 852220: "Shop.com", + 852221: "Appledaily", + 852222: "CWB", + 852223: "CNA", + 852224: "Harvey Norman", + 852225: "Hackpad", + 852226: "JB Hi-Fi", + 852227: "MyDeal.com.au", + 852228: "AUSHOP", + 852229: "CrazySales", + 852230: "Giphy", + 852231: "Riffsy", + 852232: "Gumtree", + 852233: "Priceline", + 852234: "Carousell", + 852235: "Wish", + 852236: "Shein Shopping", + 852237: "Romwe", + 852238: "The Iconic", + 852239: "Boohoo", + 852240: "Aliexpress", + 852241: "ASOS", + 852242: "Catch of the Day", + 852273: "Amazon AppStream", + 917505: "TrendMicro Titanium-6-ICRC", + 917506: "TrendMicro Titanium-7-ICRC", + 917507: "TrendMicro Titanium-8-ICRC", + 917508: "BitDefender", + 917509: "360Safe", + 917510: "Rising", + 917511: "TortoiseSVN", + 917513: "Microsoft Windows Update", + 917514: "Norton", + 917515: "Sophos", + 917516: "Yum", + 917517: "MIUI", + 917518: "Adobe", + 917519: "InstallAnyWhere", + 917520: "Kaspersky", + 917521: "McAfee", + 917522: "TrendMicro", + 917523: "F-Secure", + 917524: "NOD32", + 917525: "Avast", + 917526: "Jiangmin", + 917527: "Avira", + 917528: "Emsisoft", + 917529: "Panda", + 917530: "AVG", + 917531: "PCTools", + 917532: "TrendMicro Titanium-10-ICRC", + 917533: "Outpost", + 917534: "Spybot", + 917535: "Duba", + 917536: "Apple", + 917538: "Google Update", + 917539: "TrendMicro Titanium-6-WTP", + 917540: "JAVA Update", + 917541: "SONY PC/Xperia Companion", + 917542: "SketchUp", + 917543: "Webroot", + 917544: "TrendMicro Titanium-7-WTP", + 917545: "TrendMicro Titanium-8-WTP", + 917546: "TrendMicro Titanium-10-WTP", + 917547: "TrendMicro Titanium-11-ICRC", + 917548: "TrendMicro Titanium-11-WTP", + 917549: "TrendMicro Titanium-12-ICRC", + 917550: "TrendMicro Titanium-12-WTP", + 983043: "eBuddy.com", + 983044: "iLoveIM.com", + 983047: "imo.im", + 983048: "Chikka", + 983050: "QQ Web Messenger", + 983051: "AOL Web Messenger", + 983054: "ICQ Web Messenger", + 983057: "AirAim", + 983058: "Instan-t Web Messenger", + 983065: "TaoBao AliWW", + 983069: "Gadu-Gadu Web Messenger", + 983070: "Karoo Lark", + 983072: "Web IM+", + 1114113: "WatchGuard WSM Management", + 1114114: "WatchGuard Web Management UI", + 1114115: "WatchGuard Authentication Access", + 1114117: "WatchGuard external Webblocker database fetch", + 1114118: "Livelink", + 1114119: "Altiris", + 1114120: "AMS", + 1114121: "Apache Synapse", + 1114122: "WatchGuard CLI ", + 1114124: "Webex", + 1114125: "Webex-WebOffice", + 1114128: "Avamar", + 1114129: "Avaya", + 1114130: "BackupExec", + 1114131: "Bitcoin Core", + 1114133: "Microsoft OS license", + 1114134: "Microsoft Office 2013 license", + 1114138: "BZFlag", + 1114140: "CAJO", + 1114141: "Cisco HSRP", + 1114142: "SkyDesk", + 1114144: "Microsoft Office", + 1114150: "openQRM", + 1114151: "Citrix", + 1114152: "CodeMeter", + 1114155: "Corba", + 1114158: "Cups", + 1114160: "Cvsup", + 1114161: "DameWare", + 1114167: "Db2", + 1114168: "Docker", + 1114169: "Dclink", + 1114170: "Urchin Web Analytics", + 1114172: "Applications Manager", + 1114174: "Zoom", + 1114176: "EForward-document transport system", + 1114177: "EMWIN", + 1114179: "Adobe Connect", + 1114182: "Big Brother", + 1114185: "Fuze Meeting", + 1114187: "FritzBox", + 1114188: "Skype for Business", + 1114191: "Websense", + 1114195: "Whisker", + 1114201: "HP-JetDirect", + 1114203: "VMWare", + 1114205: "IBM HTTP", + 1114206: "IBM SmartCloud", + 1114212: "IMS", + 1114213: "Informix", + 1114222: "Limelight", + 1114229: "Lawson-m3", + 1114238: "Meeting-maker", + 1114239: "Zendesk", + 1114246: "Microsoft DTC", + 1114248: "Microsoft Netlogon", + 1114250: "Microsoft Remote Web Workplace", + 1114251: "Office Sway", + 1114252: "Sharepoint-wiki", + 1114253: "Microsoft SSDP", + 1114255: "GatherPlace", + 1114269: "Xgrid", + 1114272: "Backweb", + 1114273: "Bugzilla", + 1114274: "NCube", + 1114275: "WinboxRouterOS", + 1114277: "WSO2", + 1114279: "NetFlow", + 1114289: "concur", + 1114290: "NetSupport", + 1114308: "DirectAdmin", + 1114309: "EasyBits", + 1114310: "Eiq-sec-analyzer", + 1114311: "Netbotz", + 1114312: "Aspera FASP", + 1114318: "Perforce", + 1114320: "TiVoConnect", + 1114321: "Polycom", + 1114322: "WebSphere", + 1114330: "Radacct RADIUS", + 1114334: "Securemeeting", + 1114337: "SANE", + 1114339: "WebHost", + 1114340: "CPanel", + 1114342: "Sibelius", + 1114343: "Siebel-crm", + 1114347: "SMS", + 1114350: "Spirent", + 1114351: "SPSS", + 1114352: "Subversion", + 1114355: "Tripwire", + 1114359: "WatchGuard Webblocker database transfer", + 1114361: "WatchGuard Security Event Processor logging", + 1114363: "Genesys Meeting Center", + 1114365: "Nagios", + 1114366: "Microsoft Office 365", + 1114396: "ChatWork", + 1179649: "TCP Port Service Multiplexer", + 1179650: "Management Utility", + 1179651: "Compression Process", + 1179652: "Zeroconf", + 1179653: "Echo", + 1179654: "Discard", + 1179655: "Active Users", + 1179656: "L2TP", + 1179657: "puparp", + 1179658: "vsinet", + 1179659: "maitrd", + 1179660: "Character Generator", + 1179663: "applix", + 1179664: "Net Assistant", + 1179665: "any private mail system", + 1179666: "BackOrifice", + 1179667: "AltaVista Firewall97", + 1179668: "NSW User System FE", + 1179669: "MSG ICP", + 1179670: "MSG Authentication", + 1179671: "Display Support Protocol", + 1179672: "any private printer server", + 1179673: "Time", + 1179674: "Route Access Protocol", + 1179675: "Resource Location Protocol", + 1179676: "graphics", + 1179677: "Host Name Server", + 1179678: "NIC Name", + 1179679: "MPM FLAGS Protocol", + 1179680: "Message Processing Module [recv]", + 1179681: "MPM [default send]", + 1179682: "NI FTP", + 1179683: "Digital Audit Daemon", + 1179684: "Login Host Protocol (TACACS)", + 1179685: "Remote Mail Checking Protocol", + 1179686: "IMP Logical Address Maintenance", + 1179687: "XNS Time Protocol", + 1179688: "Domain Name Server", + 1179689: "XNS Clearinghouse", + 1179690: "ISI Graphics Language", + 1179691: "XNS Authentication", + 1179692: "Mail Transfer Protocol (MTP)", + 1179693: "XNS Mail", + 1179694: "any private file service", + 1179695: "NI MAIL", + 1179696: "ACA Services", + 1179697: "VIA Systems - FTP whois++", + 1179698: "Communications Integrator (CI)", + 1179699: "TACACS-Database Service", + 1179700: "Oracle SQL-NET", + 1179701: "Bootstrap Protocol Server", + 1179702: "Bootstrap Protocol Client", + 1179703: "profile", + 1179704: "Gopher", + 1179705: "Remote Job Service", + 1179706: "any private dial out service", + 1179707: "Distributed External Object Store", + 1179708: "any private RJE service netrjs", + 1179709: "Vet TCP", + 1179710: "Finger", + 1179711: "World Wide Web HTTP", + 1179712: "Torpark", + 1179713: "XFER Utility", + 1179714: "MIT ML Device", + 1179715: "Common Trace Facility", + 1179716: "Micro Focus Cobol", + 1179717: "any private terminal link ttylink", + 1179718: "Kerberos", + 1179719: "SU MIT Telnet Gateway", + 1179720: "DNSIX Securit Attribute Token Map", + 1179721: "MIT Dover Spooler", + 1179722: "Network Printing Protocol", + 1179723: "Device Control Protocol", + 1179724: "Tivoli Object Dispatcher", + 1179725: "BSD supdupd(8)", + 1179726: "DIXIE Protocol Specification", + 1179727: "Swift Remote Virtural File Protocol", + 1179728: "linuxconf", + 1179729: "Metagram Relay", + 1179731: "NIC Host Name Server", + 1179732: "ISO-TSAP Class 0", + 1179733: "Genesis Point-to-Point Trans Net", + 1179734: "ACR-NEMA Digital Imag. & Comm. 300", + 1179735: "Mailbox Name Nameserver", + 1179736: "msantipiracy", + 1179737: "Eudora compatible PW changer", + 1179739: "SNA Gateway Access Server", + 1179740: "PostOffice V.2", + 1179742: "Portmapper RPC Bind", + 1179743: "McIDAS Data Transmission Protocol", + 1179744: "Ident Tap Authentication Service", + 1179745: "Audio News Multicast", + 1179746: "Simple File Transfer Protocol", + 1179747: "ANSA REX Notify", + 1179748: "UUCP Path Service", + 1179749: "SQL Services", + 1179751: "blackjack", + 1179752: "Encore Expedited Remote Pro.Call", + 1179753: "Smakynet", + 1179754: "Network Time Protocol", + 1179755: "ANSA REX Trader", + 1179756: "Locus PC-Interface Net Map Ser", + 1179757: "Unisys Unitary Login", + 1179758: "Locus PC-Interface Conn Server", + 1179759: "GSS X License Verification", + 1179760: "Password Generator Protocol", + 1179761: "Cisco FNATIVE", + 1179762: "Cisco TNATIVE", + 1179763: "Cisco SYSMAINT", + 1179764: "Statistics Service", + 1179765: "INGRES-NET Service", + 1179766: "NCS local location broker", + 1179767: "PROFILE Naming System", + 1179768: "NetBIOS Name Service", + 1179769: "NetBIOS Datagram Service", + 1179770: "NetBIOS Session Service", + 1179771: "EMFIS Data Service", + 1179772: "EMFIS Control Service", + 1179773: "Britton-Lee IDM", + 1179774: "Internet Message Access Protocol", + 1179775: "Universal Management Architecture", + 1179776: "UAAC Protocol", + 1179777: "iso-ip0", + 1179778: "iso-ip", + 1179779: "Jargon", + 1179780: "AED 512 Emulation Service", + 1179781: "SQL-net", + 1179782: "HEMS", + 1179783: "Background File Transfer Program (BFTP)", + 1179784: "SGMP", + 1179785: "NetSC-prod", + 1179786: "NetSC-dev", + 1179787: "SQL Service", + 1179788: "KNET VM Command Message Protocol", + 1179789: "PCMail Server", + 1179790: "NSS-Routing", + 1179791: "SGMP-traps", + 1179793: "SNMPTRAP", + 1179794: "CMIP TCP Manager", + 1179795: "CMIP TCP Agent", + 1179796: "Xerox", + 1179797: "Sirius Systems", + 1179798: "namp", + 1179799: "rsvd", + 1179800: "send", + 1179801: "Network PostScript", + 1179802: "Network Innovations Multiplex", + 1179803: "Network Innovations CL 1", + 1179804: "xyplex-mux", + 1179805: "mailq", + 1179806: "vmnet", + 1179807: "genrad-mux", + 1179808: "X Display Manager Control Protocol", + 1179809: "NextStep Window Server", + 1179810: "Border Gateway Protocol", + 1179811: "Intergraph", + 1179812: "unify", + 1179813: "Unisys Audit SITP", + 1179814: "ocbinder", + 1179815: "ocserver", + 1179816: "remote-kis", + 1179817: "KIS Protocol", + 1179818: "Application Communication Interface", + 1179819: "Plus Fives MUMPS", + 1179820: "Queued File Transport", + 1179821: "Gateway Access Control Protocol", + 1179822: "Prospero Directory Service", + 1179823: "OSU Network Monitoring System", + 1179824: "Spider Remote Monitoring Protocol", + 1179825: "Internet Relay Chat", + 1179826: "DNSIX Network Level Module Audit", + 1179827: "DNSIX Session Mgt Module Audit Redir", + 1179828: "Directory Location Service", + 1179829: "Directory Location Service Monitor", + 1179830: "SMUX", + 1179831: "IBM System Resource Controller", + 1179832: "AppleTalk Routing Maintenance", + 1179833: "AppleTalk Name Binding", + 1179834: "AppleTalk Unused", + 1179835: "AppleTalk Echo", + 1179836: "AppleTalk Zone Information", + 1179838: "Trivial Authenticated Mail Protocol", + 1179839: "ANSI Z39.50", + 1179840: "Texas Instruments", + 1179841: "ATEXSSTR", + 1179842: "IPX", + 1179843: "vmpwscs", + 1179844: "Insignia Solutions", + 1179845: "Computer Associates Intl License Server", + 1179846: "dBASE Unix", + 1179847: "Netix Message Posting Protocol", + 1179848: "Unisys ARPs", + 1179849: "Interactive Mail Access Protocol v3", + 1179850: "Berkeley rlogind with SPX auth", + 1179851: "Berkeley rshd with SPX auth", + 1179852: "Certificate Distribution Center", + 1179853: "masqdialer", + 1179854: "direct", + 1179855: "Survey Measurement", + 1179856: "inbusiness", + 1179857: "link", + 1179858: "Display Systems Protocol", + 1179859: "VAT", + 1179860: "bhfhs", + 1179862: "RAP (Route Access Protocol)", + 1179863: "Checkpoint Firewall-1", + 1179864: "Efficient Short Remote Operations", + 1179865: "openport", + 1179866: "Checkpoint Firewall-1 Management", + 1179867: "arcisdms", + 1179868: "hdap", + 1179869: "Border Gateway Multicast Protocol (BGMP)", + 1179870: "X-Bone CTL", + 1179871: "SCSI on ST", + 1179872: "Tobit David Service Layer", + 1179873: "Tobit David Replica", + 1179874: "http-mgmt", + 1179875: "personal-link", + 1179876: "Cable Port A X", + 1179877: "rescap", + 1179878: "corerjd", + 1179879: "FXP-1", + 1179880: "K-BLOCK", + 1179881: "Novastor Backup", + 1179882: "entrusttime", + 1179883: "bhmds", + 1179884: "AppleShare IP WebAdmin", + 1179885: "VSLMP", + 1179886: "magenta-logic", + 1179887: "opalis-robot", + 1179888: "DPSI", + 1179889: "decAuth", + 1179890: "zannet", + 1179891: "PKIX TimeStamp", + 1179892: "PTP Event", + 1179893: "PTP General", + 1179894: "Programmable Interconnect Point (PIP)", + 1179895: "RTSPS", + 1179896: "Texar Security Port", + 1179897: "Prospero Data Access Protocol", + 1179898: "Perf Analysis Workbench", + 1179899: "Zebra server", + 1179900: "Fatmen Server", + 1179901: "Cabletron Management Protocol", + 1179902: "mftp", + 1179903: "MATIP Type A", + 1245185: "PPTP", + 1245186: "BakBone NetVault", + 1245187: "DTAG or bhoedap4", + 1245188: "ndsauth", + 1245189: "bh611", + 1245190: "datex-asn", + 1245191: "Cloanto Net 1", + 1245192: "bhevent", + 1245193: "shrinkwrap", + 1245194: "Windows RPC", + 1245195: "Tenebris Network Trace Service", + 1245196: "scoi2odialog", + 1245197: "semantix", + 1245198: "SRS Send", + 1245200: "aurora-cmgr", + 1245201: "DTK", + 1245202: "odmr", + 1245203: "mortgageware", + 1245204: "qbikgdp", + 1245205: "rpc2portmap", + 1245206: "Coda authentication server (codaauth2)", + 1245207: "ClearCase", + 1245208: "ListProcessor", + 1245209: "Legent Corporation", + 1245210: "hassle", + 1245211: "Amiga Envoy Network Inquiry Proto", + 1245212: "NEC Corporation", + 1245213: "TIA EIA IS-99 modem client", + 1245214: "TIA EIA IS-99 modem server", + 1245215: "HP Performance data collector", + 1245216: "HP Performance data managed node", + 1245217: "HP Performance data alarm manager", + 1245218: "A Remote Network Server System", + 1245219: "IBM Application", + 1245220: "ASA Message Router Object Def.", + 1245221: "Appletalk Update-Based Routing Pro.", + 1245222: "Unidata LDM", + 1245223: "Lightweight Directory Access Protocol", + 1245224: "uis", + 1245225: "SynOptics SNMP Relay Port", + 1245226: "SynOptics Port Broker Port", + 1245228: "Meta5", + 1245229: "EMBL Nucleic Data Transfer", + 1245230: "NETscout Control Protocol", + 1245231: "Novell Netware over IP", + 1245232: "Multi Protocol Trans. Net.", + 1245233: "kryptolan", + 1245234: "ISO Transport Class 2 Non-Control over TCP", + 1245235: "Workstation Solutions", + 1245236: "Uninterruptible Power Supply", + 1245237: "Genie Protocol", + 1245238: "decap", + 1245239: "nced", + 1245240: "ncld", + 1245241: "Interactive Mail Support Protocol", + 1245242: "timbuktu", + 1245243: "Prospero Resource Manager Sys. Man.", + 1245244: "Prospero Resource Manager Node Man.", + 1245245: "DECLadebug Remote Debug Protocol", + 1245246: "Remote MT Protocol", + 1245247: "Trap Convention Port", + 1245248: "smsp", + 1245249: "infoseek", + 1245250: "bnet", + 1245251: "silverplatter", + 1245252: "onmux", + 1245253: "hyper-g", + 1245254: "ariel1", + 1245255: "smpte", + 1245256: "ariel2", + 1245257: "ariel3", + 1245258: "IBM Operations Planning and Control Start", + 1245259: "IBM Operations Planning and Control Track", + 1245260: "icad-el", + 1245261: "smartsdp", + 1245262: "Server Location", + 1245263: "ocs_cmu", + 1245264: "ocs_amu", + 1245265: "utmpsd", + 1245266: "utmpcd", + 1245267: "iasd", + 1245268: "Usenet Network News Transfer", + 1245269: "mobileip-agent", + 1245270: "mobilip-mn", + 1245271: "dna-cml", + 1245272: "comscm", + 1245273: "dsfgw", + 1245274: "dasp", + 1245275: "sgcp", + 1245276: "decvms-sysmgt", + 1245277: "cvc_hostd", + 1245278: "HTTP Protocol over TLS SSL", + 1245279: "Simple Network Paging Protocol", + 1245280: "Win2k+ Server Message Block", + 1245281: "ddm-rdb", + 1245282: "ddm-dfm", + 1245283: "DDM-SSL", + 1245284: "AS Server Mapper", + 1245285: "tserver", + 1245286: "Cray Network Semaphore server", + 1245287: "Cray SFS config server", + 1245288: "creativeserver", + 1245289: "contentserver", + 1245290: "creativepartnr", + 1245291: "macon-tcp", + 1245292: "scohelp", + 1245294: "ampr-rcmd", + 1245295: "skronk", + 1245296: "datasurfsrv", + 1245297: "datasurfsrvsec", + 1245298: "Alpes", + 1245299: "kpasswd", + 1245300: "SMTP Protocol over TLS SSL (was SSMTP)", + 1245301: "digital-vrc", + 1245302: "mylex-mapd", + 1245303: "Photuris Key Management", + 1245304: "Radio Control Protocol", + 1245305: "scx-proxy", + 1245306: "mondex", + 1245307: "ljk-login", + 1245308: "hybrid-pop", + 1245309: "tn-tl-w1", + 1245310: "Tcpnethaspsrv Protocol", + 1245311: "tn-tl-fd1", + 1245312: "ss7ns", + 1245313: "spsc", + 1245314: "iafserver", + 1245315: "WCCP", + 1245316: "loadsrv", + 1245317: "serialnumberd", + 1245318: "dvs", + 1245319: "bgs-nsi", + 1245320: "ulpnet", + 1245321: "Integra Software Management Environment", + 1245322: "Air Soft Power Burst", + 1245324: "sstats", + 1245325: "saft Simple Asynchronous File Transfer", + 1245326: "gss-http", + 1245327: "nest-protocol", + 1245328: "micom-pfs", + 1245329: "go-login", + 1245330: "Transport Independent Convergence for FNA", + 1245331: "pov-ray", + 1245332: "intecourier", + 1245333: "pim-rp-disc", + 1245334: "dantz", + 1245335: "siam", + 1245336: "ISO ILL Protocol", + 1245337: "VPN Key Exchange", + 1245338: "Simple Transportation Management Framework (STMF)", + 1245339: "asa-appl-proto", + 1245340: "intrinsa", + 1245341: "Citadel", + 1245342: "mailbox-lm", + 1245343: "ohimsrv", + 1245344: "crs", + 1245345: "xvttp", + 1245346: "snare", + 1245347: "FirstClass Protocol", + 1245348: "passgo", + 1245349: "BSD rexecd(8)", + 1245350: "BSD rlogind(8)", + 1245351: "BSD rshd(8)", + 1245352: "spooler", + 1245353: "videotex", + 1245354: "like tenex link but across", + 1245355: "ntalk", + 1245356: "unixtime", + 1245357: "Routing Information Protocol (RIP)", + 1245358: "ripng", + 1245359: "ulp", + 1245360: "ibm-db2", + 1245361: "NetWare Core Protocol (NCP)", + 1245362: "Timeserver", + 1245363: "newdate", + 1245364: "Stock IXChange", + 1245365: "Customer IXChange", + 1245366: "irc-serv", + 1245370: "readnews", + 1245371: "netwall for emergency broadcasts", + 1245372: "MegaMedia Admin", + 1245373: "iiop", + 1245374: "opalis-rdv", + 1245375: "Networked Media Streaming Protocol", + 1245376: "gdomap", + 1245377: "Apertus Technologies Load Determination", + 1245378: "uucpd", + 1245379: "uucp-rlogin", + 1245380: "Commerce", + 1245381: "klogin", + 1245382: "krcmd", + 1245383: "Kerberos encrypted remote shell", + 1245384: "DHCPv6 Client", + 1245385: "DHCPv6 Server", + 1245386: "AFP over TCP", + 1245387: "idfp", + 1245388: "new-who", + 1245389: "cybercash", + 1245390: "deviceshare", + 1245391: "pirp", + 1245392: "Real Time Stream Control Protocol", + 1245393: "dsf", + 1245394: "Remote File System (RFS)", + 1245395: "openvms-sysipc", + 1245396: "sdnskmp", + 1245397: "teedtap", + 1245398: "rmonitord", + 1245399: "monitor", + 1245400: "chcmd", + 1245402: "snews", + 1245403: "plan 9 file service", + 1245404: "whoami", + 1245405: "streettalk", + 1245406: "banyan-rpc", + 1245407: "Microsoft shuttle", + 1245408: "Microsoft rome", + 1245409: "demon", + 1245410: "udemon", + 1245411: "sonar", + 1245412: "banyan-vip", + 1245413: "FTP Software Agent System", + 1245414: "vemmi", + 1245415: "ipcd", + 1245416: "vnas", + 1245417: "ipdd", + 1245418: "decbsrv", + 1245419: "sntp-heartbeat", + 1245420: "Bundle Discovery Protocol", + 1245421: "scc-security", + 1245422: "Philips Video-Conferencing", + 1245423: "keyserver", + 1245424: "IMAP4+SSL", + 1245425: "password-chg", + 1245426: "submission", + 1245427: "cal", + 1245428: "eyelink", + 1245429: "tns-cml", + 1245430: "FileMaker Pro", + 1245431: "eudora-set", + 1245432: "HTTP RPC Ep Map", + 1245433: "tpip", + 1245434: "cab-protocol", + 1245435: "smsd", + 1245436: "PTC Name Service", + 1245437: "SCO Web Server Manager 3", + 1245438: "Aeolon Core Protocol", + 1245439: "Sun IPC server", + 1310721: "nqs", + 1310722: "Sender-Initiated Unsolicited File Transfer", + 1310723: "npmp-trap", + 1310724: "npmp-local", + 1310725: "npmp-gui", + 1310726: "HMMP Indication", + 1310727: "HMMP Operation", + 1310728: "SSLshell", + 1310729: "Internet Configuration Manager", + 1310730: "SCO System Administration Server", + 1310731: "SCO Desktop Administration Server", + 1310732: "DEI-ICDA", + 1310733: "Digital EVM", + 1310734: "SCO WebServer Manager", + 1310735: "ESCP", + 1310736: "Collaborator", + 1310737: "Aux Bus Shunt", + 1310738: "Crypto Admin", + 1310739: "DEC DLM", + 1310740: "ASIA", + 1310741: "PassGo Tivoli", + 1310742: "QMQP (qmail)", + 1310743: "3Com AMP3", + 1310744: "RDA", + 1310745: "IPP (Internet Printing Protocol)", + 1310746: "bmpp", + 1310747: "Service Status update (Sterling Software)", + 1310748: "ginad", + 1310749: "RLZ DBase", + 1310750: "LDAP Protocol over TLS SSL (was SLDAP)", + 1310751: "lanserver", + 1310752: "mcns-sec", + 1310753: "Multicast Source Discovery Protocol (MSDP)", + 1310754: "entrust-sps", + 1310755: "repcmd", + 1310756: "ESRO-EMSDP V1.3", + 1310757: "SANity", + 1310758: "dwr", + 1310759: "PSSC", + 1310760: "Label Distribution Protocol (LDP)", + 1310761: "DHCP Failover", + 1310762: "Registry Registrar Protocol (RRP)", + 1310763: "Aminet", + 1310764: "OBEX", + 1310765: "IEEE MMS", + 1310766: "HELLO_PORT", + 1310767: "AODV", + 1310768: "TINC", + 1310769: "SPMP", + 1310770: "RMC", + 1310771: "TenFold", + 1310772: "URL Rendezvous", + 1310773: "MacOS Server Admin", + 1310774: "HAP", + 1310775: "PFTP", + 1310776: "PureNoise", + 1310777: "Secure Aux Bus", + 1310778: "Sun DR", + 1310779: "doom Id Software", + 1310780: "campaign contribution disclosures - SDR Technologies", + 1310781: "MeComm", + 1310782: "MeRegister", + 1310783: "VACDSM-SWS", + 1310784: "VACDSM-APP", + 1310785: "VPPS-QUA", + 1310786: "CIMPLEX", + 1310787: "ACAP", + 1310788: "DCTP", + 1310789: "VPPS Via", + 1310790: "Virtual Presence Protocol", + 1310791: "GNU Gereration Foundation NCP", + 1310792: "MRM", + 1310793: "entrust-aaas", + 1310794: "entrust-aams", + 1310795: "XFR", + 1310796: "CORBA IIOP", + 1310797: "CORBA IIOP SSL", + 1310798: "MDC Port Mapper", + 1310799: "Hardware Control Protocol Wismar", + 1310800: "asipregistry", + 1310801: "REALM-RUSD", + 1310802: "NMAP", + 1310803: "VATP", + 1310804: "MS Exchange Routing", + 1310805: "Hyperwave-ISP", + 1310806: "connendp", + 1310807: "Linux-HA (High-Availability Linux)", + 1310808: "IEEE-MMS-SSL", + 1310809: "RUSHD", + 1310810: "UUIDGEN", + 1310811: "OLSR", + 1310812: "Access Network", + 1310813: "errlog copy server daemon", + 1310814: "AgentX", + 1310815: "Secure Internet Live Conferencing (SILC)", + 1310816: "Borland DSJ", + 1310817: "Entrust Key Management Service Handler", + 1310818: "Entrust Administration Service Handler", + 1310819: "Cisco TDP", + 1310820: "IBM NetView DM 6000 Server Client", + 1310821: "IBM NetView DM 6000 send tcp", + 1310822: "IBM NetView DM 6000 receive tcp", + 1310823: "netGW", + 1310824: "Network based Rev. Cont. Sys.", + 1310825: "Flexible License Manager", + 1310826: "Fujitsu Device Control", + 1310827: "Russell Info Sci Calendar Manager", + 1310828: "Kerberos 5 admin changepw", + 1310830: "rfile", + 1310832: "pump", + 1310833: "qrh", + 1310834: "rrh", + 1310835: "kerberos v5 server propagation", + 1310836: "nlogin", + 1310837: "con", + 1310839: "ns", + 1310840: "kpwd Kerberos (v4) passwd", + 1310841: "quotad", + 1310842: "cycleserv", + 1310843: "omserv", + 1310844: "webster", + 1310845: "phone", + 1310846: "vid", + 1310847: "cadlock", + 1310848: "rtip", + 1310849: "cycleserv2", + 1310850: "submit", + 1310851: "rpasswd", + 1310852: "entomb", + 1310853: "wpages", + 1310854: "Hummingbird Exceed jconfig", + 1310855: "wpgs", + 1310856: "concert", + 1310857: "QSC", + 1310858: "controlit", + 1310859: "mdbs_daemon", + 1310860: "Device", + 1310861: "FCP", + 1310862: "itm-mcell-s", + 1310863: "PKIX-3 CA RA", + 1310864: "DHCP Failover 2", + 1310865: "SUP server", + 1310866: "rsync", + 1310867: "ICL coNETion locate server", + 1310868: "ICL coNETion server info", + 1310869: "AccessBuilder", + 1310870: "OMG Initial Refs", + 1310871: "Samba SWAT Tool", + 1310872: "IDEAFARM-CHAT", + 1310873: "IDEAFARM-CATCH", + 1310874: "xact-backup", + 1310875: "SecureNet Pro sensor", + 1310878: "Netnews Administration System", + 1310879: "Telnet Protocol over TLS SSL", + 1310880: "IMAP4 Protocol over TLS SSL", + 1310881: "ICP Protocol over TLS SSL", + 1310882: "POP3 Protocol over TLS SSL", + 1310883: "bhoetty", + 1310884: "Cray Unified Resource Manager", + 1310887: "Microsoft Authentication via SSL", + 1310888: "Google(SSL)", + 1310889: "Yahoo Authentication via SSL", + 1310890: "AOL Authentication via SSL", + 1310891: "FIX", + 1310892: "STUN", + 1310893: "Dynamic Host Configuration Protocol (DHCP)", + 1310894: "Megaco", + 1310895: "Rstatd", + 1310896: "RSVP", + 1310897: "SOAP", + 1310898: "Ess Apple Authentication via SSL", + 1310899: "TFTP", + 1310900: "Daytime", + 1310902: "MicrosoftOnline Authentication via SSL", + 1310903: "Microsoft WINS", + 1310904: "Remote Procedure Call (RPC)", + 1310905: "SSL/TLS", + 1310906: "Google APIs(SSL)", + 1310907: "Sina Authentication via SSL", + 1310908: "Google App Engine(SSL)", + 1310909: "Google User Content(SSL)", + 1310910: "Blackberry Authentication via SSL", + 1310912: "Adobe Authentication via SSL", + 1310914: "Lets Encrypt", + 1507329: "QQ Private Protocol", + 1507330: "Thunder Private Protocol", + 1507333: "Jabber Private Protocol", + 1572865: "Classmates", + 1572866: "Yik Yak", + 1572867: "Facebook", + 1572868: "Flickr", + 1572870: "Friendfeed", + 1572871: "Hi5", + 1572872: "LinkedIn", + 1572873: "Livejournal", + 1572874: "Twitter", + 1572875: "Plurk", + 1572876: "MySpace", + 1572880: "Khan Academy", + 1572881: "Pinterest", + 1572882: "Tumblr", + 1572883: "MeetMe", + 1572884: "VKontakte", + 1572885: "Odnoklassniki", + 1572886: "Niwota", + 1572887: "Tagged", + 1572889: "PerfSpot", + 1572890: "Me2day", + 1572891: "Mekusharim", + 1572892: "Draugiem", + 1572893: "Badoo", + 1572894: "Meetup", + 1572895: "Foursquare", + 1572896: "Ning", + 1572897: "i-Part/iPair", + 1572898: "Wretch", + 1572899: "Dudu", + 1572900: "Mig33", + 1572901: "Hatena", + 1572902: "eHarmony", + 1572903: "Fotolog ", + 1572905: "Tencent QQ", + 1572906: "Pixnet", + 1572907: "Nk.Pl", + 1572909: "Twoo", + 1572910: "Plaxo", + 1572911: "Cyworld", + 1572912: "Jivesoftware", + 1572913: "WordPress", + 1572914: "FMyLife", + 1572915: "Dcinside", + 1572916: "Class Chinaren", + 1572917: "Bai Sohu", + 1572918: "Yammer", + 1572919: "Douban", + 1572920: "Gamer", + 1572921: "Xuite", + 1572922: "ChatMe", + 1572923: "Clien.net", + 1572927: "AdultFriendFinder", + 1572928: "Fling.com", + 1572929: "Delicious", + 1572930: "Mei.fm", + 1572931: "Streetlife", + 1572967: "Daum-blog", + 1572968: "Naver-blog", + 1572970: "Panoramio", + 1572974: "Blogger", + 1572975: "FC2", + 1572976: "Yahoo Blog", + 1572977: "Friendster", + 1572978: "Ameba", + 1572980: "Bebo social network", + 1572981: "Kaixin", + 1572983: "Orkut", + 1572985: "Aol-Answers", + 1572987: "CoolTalk social network", + 1572988: "RenRen.com", + 1572989: "TweetDeck", + 1572990: "Hootsuite", + 1572998: "Xing", + 1572999: "Lokalisten", + 1573000: "meinVZ/studiVZ", + 1573004: "Viadeo", + 1573005: "Tuenti", + 1573006: "Hyves", + 1573007: "Mixi.jp", + 1573008: "Yahoo-mbga.jp", + 1573009: "GREE", + 1573010: "Netlog", + 1573011: "2ch", + 1573013: "Reddit", + 1573014: "LoveTheseCurves", + 1573015: "Weibo", + 1573016: "Google+", + 1573017: "Skyrock", + 1573018: "51.com", + 1573019: "Jackd", + 1573020: "Touch", + 1573021: "Skout", + 1573022: "Instagram", + 1573023: "Jiayuan", + 1573024: "Zoosk", + 1573025: "DatingDNA", + 1573026: "500px", + 1573028: "iAround", + 1573029: "pairs", + 1573030: "Path", + 1573031: "WeHeartIt", + 1573032: "Fancy", + 1573033: "Vine", + 1573034: "SnappyTV", + 1573035: "Miliao", + 1573036: "After School", + 1573074: "Weico", + 16777215: "Unknown_Other", +} diff --git a/core/unifi/go.sum b/core/unifi/go.sum index 0b286a58..1041afa2 100644 --- a/core/unifi/go.sum +++ b/core/unifi/go.sum @@ -1,5 +1,11 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/core/unifi/site.go b/core/unifi/site.go index 2789a8b6..20018b03 100644 --- a/core/unifi/site.go +++ b/core/unifi/site.go @@ -1,6 +1,9 @@ package unifi -import "strings" +import ( + "fmt" + "strings" +) // GetSites returns a list of configured sites on the UniFi controller. func (u *Unifi) GetSites() (Sites, error) { @@ -29,6 +32,36 @@ func (u *Unifi) GetSites() (Sites, error) { return response.Data, nil } +// GetSiteDPI garners dpi data for sites. +func (u *Unifi) GetSiteDPI(sites Sites) ([]*DPITable, error) { + data := []*DPITable{} + + for _, site := range sites { + u.DebugLog("Polling Controller, retreiving Site DPI data, site %s (%s) ", site.Name, site.Desc) + + var response struct { + Data []*DPITable `json:"data"` + } + + siteDPIpath := fmt.Sprintf(APISiteDPI, site.Name) + if err := u.GetData(siteDPIpath, &response, `{"type":"by_app"}`); err != nil { + return nil, err + } + + if l := len(response.Data); l > 1 { + return nil, fmt.Errorf("dpi data table contains more than 1 item; please open a bug report") + } else if l != 1 { + continue + } + + response.Data[0].SourceName = site.SourceName + response.Data[0].SiteName = site.SiteName + data = append(data, response.Data[0]) + } + + return data, nil +} + // Sites is a struct to match Devices and Clients. type Sites []*Site diff --git a/core/unifi/types.go b/core/unifi/types.go index 394278a0..ed298f40 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -15,6 +15,10 @@ const ( APIStatusPath string = "/status" // APISiteList is the path to the api site list. APISiteList string = "/api/stat/sites" + // APISiteDPI is site DPI data. + APISiteDPI string = "/api/s/%s/stat/sitedpi" + // APISiteDPI is site DPI data. + APIClientDPI string = "/api/s/%s/stat/stadpi" // APIClientPath is Unifi Clients API Path APIClientPath string = "/api/s/%s/stat/sta" // APIDevicePath is where we get data about Unifi devices. diff --git a/core/unifi/udm.go b/core/unifi/udm.go index 172d0908..16842809 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -133,75 +133,45 @@ type UDM struct { // NetworkTable is the list of networks on a gateway. type NetworkTable []struct { - ID string `json:"_id"` - AttrNoDelete FlexBool `json:"attr_no_delete"` - AttrHiddenID string `json:"attr_hidden_id"` - Name string `json:"name"` - SiteID string `json:"site_id"` - VlanEnabled FlexBool `json:"vlan_enabled"` - Purpose string `json:"purpose"` - IPSubnet string `json:"ip_subnet"` - Ipv6InterfaceType string `json:"ipv6_interface_type"` - DomainName string `json:"domain_name"` - IsNat FlexBool `json:"is_nat"` - DhcpdEnabled FlexBool `json:"dhcpd_enabled"` - DhcpdStart string `json:"dhcpd_start"` - DhcpdStop string `json:"dhcpd_stop"` - Dhcpdv6Enabled FlexBool `json:"dhcpdv6_enabled"` - Ipv6RaEnabled FlexBool `json:"ipv6_ra_enabled"` - LteLanEnabled FlexBool `json:"lte_lan_enabled"` - Networkgroup string `json:"networkgroup"` - DhcpdLeasetime FlexInt `json:"dhcpd_leasetime"` - DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"` - DhcpdGatewayEnabled FlexBool `json:"dhcpd_gateway_enabled"` - DhcpdTimeOffsetEnabled FlexBool `json:"dhcpd_time_offset_enabled"` - Ipv6PdStart string `json:"ipv6_pd_start"` - Ipv6PdStop string `json:"ipv6_pd_stop"` - DhcpdDNS1 string `json:"dhcpd_dns_1"` - DhcpdDNS2 string `json:"dhcpd_dns_2"` - DhcpdDNS3 string `json:"dhcpd_dns_3"` - DhcpdDNS4 string `json:"dhcpd_dns_4"` - Enabled FlexBool `json:"enabled"` - DhcpRelayEnabled FlexBool `json:"dhcp_relay_enabled"` - Mac string `json:"mac"` - IsGuest FlexBool `json:"is_guest"` - IP string `json:"ip"` - Up FlexBool `json:"up"` - DPIStatsTable DPIStatsTable `json:"dpistats_table,omitempty"` - NumSta FlexInt `json:"num_sta"` - RxBytes FlexInt `json:"rx_bytes"` - RxPackets FlexInt `json:"rx_packets"` - TxBytes FlexInt `json:"tx_bytes"` - TxPackets FlexInt `json:"tx_packets"` -} - -// DPIStatsTable is the Deep Packet Inspection data for each "network" -type DPIStatsTable struct { - LastUpdated FlexInt `json:"last_updated"` - ByCat []struct { - Cat FlexInt `json:"cat"` - Apps []FlexInt `json:"apps"` - RxBytes FlexInt `json:"rx_bytes"` - TxBytes FlexInt `json:"tx_bytes"` - RxPackets FlexInt `json:"rx_packets"` - TxPackets FlexInt `json:"tx_packets"` - } `json:"by_cat"` - ByApp []struct { - App FlexInt `json:"app"` - Cat FlexInt `json:"cat"` - Clients []struct { - Mac string `json:"mac"` - RxBytes FlexInt `json:"rx_bytes"` - TxBytes FlexInt `json:"tx_bytes"` - RxPackets FlexInt `json:"rx_packets"` - TxPackets FlexInt `json:"tx_packets"` - } `json:"clients"` - KnownClients FlexInt `json:"known_clients"` - RxBytes FlexInt `json:"rx_bytes"` - TxBytes FlexInt `json:"tx_bytes"` - RxPackets FlexInt `json:"rx_packets"` - TxPackets FlexInt `json:"tx_packets"` - } `json:"by_app"` + ID string `json:"_id"` + AttrNoDelete FlexBool `json:"attr_no_delete"` + AttrHiddenID string `json:"attr_hidden_id"` + Name string `json:"name"` + SiteID string `json:"site_id"` + VlanEnabled FlexBool `json:"vlan_enabled"` + Purpose string `json:"purpose"` + IPSubnet string `json:"ip_subnet"` + Ipv6InterfaceType string `json:"ipv6_interface_type"` + DomainName string `json:"domain_name"` + IsNat FlexBool `json:"is_nat"` + DhcpdEnabled FlexBool `json:"dhcpd_enabled"` + DhcpdStart string `json:"dhcpd_start"` + DhcpdStop string `json:"dhcpd_stop"` + Dhcpdv6Enabled FlexBool `json:"dhcpdv6_enabled"` + Ipv6RaEnabled FlexBool `json:"ipv6_ra_enabled"` + LteLanEnabled FlexBool `json:"lte_lan_enabled"` + Networkgroup string `json:"networkgroup"` + DhcpdLeasetime FlexInt `json:"dhcpd_leasetime"` + DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"` + DhcpdGatewayEnabled FlexBool `json:"dhcpd_gateway_enabled"` + DhcpdTimeOffsetEnabled FlexBool `json:"dhcpd_time_offset_enabled"` + Ipv6PdStart string `json:"ipv6_pd_start"` + Ipv6PdStop string `json:"ipv6_pd_stop"` + DhcpdDNS1 string `json:"dhcpd_dns_1"` + DhcpdDNS2 string `json:"dhcpd_dns_2"` + DhcpdDNS3 string `json:"dhcpd_dns_3"` + DhcpdDNS4 string `json:"dhcpd_dns_4"` + Enabled FlexBool `json:"enabled"` + DhcpRelayEnabled FlexBool `json:"dhcp_relay_enabled"` + Mac string `json:"mac"` + IsGuest FlexBool `json:"is_guest"` + IP string `json:"ip"` + Up FlexBool `json:"up"` + NumSta FlexInt `json:"num_sta"` + RxBytes FlexInt `json:"rx_bytes"` + RxPackets FlexInt `json:"rx_packets"` + TxBytes FlexInt `json:"tx_bytes"` + TxPackets FlexInt `json:"tx_packets"` } // UDMStat holds the "stat" data for a dream machine. diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index a08552c7..2b3ba865 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -97,10 +97,10 @@ func (u *Unifi) GetServerData() error { } // GetData makes a unifi request and unmarshals the response into a provided pointer. -func (u *Unifi) GetData(apiPath string, v interface{}) error { +func (u *Unifi) GetData(apiPath string, v interface{}, params ...string) error { start := time.Now() - body, err := u.GetJSON(apiPath) + body, err := u.GetJSON(apiPath, params...) if err != nil { return err } @@ -134,8 +134,8 @@ func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err er } // GetJSON returns the raw JSON from a path. This is useful for debugging. -func (u *Unifi) GetJSON(apiPath string) ([]byte, error) { - req, err := u.UniReq(apiPath, "") +func (u *Unifi) GetJSON(apiPath string, params ...string) ([]byte, error) { + req, err := u.UniReq(apiPath, strings.Join(params, " ")) if err != nil { return []byte{}, err } From 46a325c6d592d004eecff5f4fe3c476467bbeb1a Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Fri, 27 Dec 2019 20:35:43 -0800 Subject: [PATCH 118/194] update readme --- core/unifi/README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/unifi/README.md b/core/unifi/README.md index e3570381..87f58e06 100644 --- a/core/unifi/README.md +++ b/core/unifi/README.md @@ -5,9 +5,13 @@ an authenticated http Client you may use to query the device for data. Also contains some built-in methods for de-serializing common client and device data. The data is provided in a large struct you can consume in your application. -If more features are requested, I'll certainly consider them. Do you need to do -more than just collect data? [Let me know](https://github.com/golift/unifi/issues/new)! -Pull requests and feedback are welcomed! +This library is designed to PULL data FROM the controller. It has no methods that +update settings or change things on the controller. +[Someone expressed interest](https://github.com/golift/unifi/issues/31) in +adding methods to update data, and I'm okay with that. I'll even help add them. +[Tell me what you want to do](https://github.com/golift/unifi/issues/new), and we'll make it happen. + +Pull requests, feature requests, code reviews and feedback are welcomed! Here's a working example: ```golang From 0e594d8b2aa1832521983eff3b1d261cbb62fc4f Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Fri, 27 Dec 2019 20:38:02 -0800 Subject: [PATCH 119/194] update build --- core/unifi/.travis.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/core/unifi/.travis.yml b/core/unifi/.travis.yml index c7d4eacc..3c936a6f 100644 --- a/core/unifi/.travis.yml +++ b/core/unifi/.travis.yml @@ -1,15 +1,11 @@ language: go go: -- 1.12.x +- 1.13.x before_install: -- mkdir -p $GOPATH/bin - # Download the `dep` binary to bin folder in $GOPATH -- curl -sLo $GOPATH/bin/dep https://github.com/golang/dep/releases/download/v0.5.3/dep-linux-amd64 -- chmod +x $GOPATH/bin/dep # download super-linter: golangci-lint - curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin latest install: -- dep ensure + - go mod vendor script: - golangci-lint run --enable-all -e G402 -D gochecknoglobals - go test ./... From baa2b765bc361560b984853c111621777a411c5d Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Fri, 27 Dec 2019 20:42:26 -0800 Subject: [PATCH 120/194] unindent --- core/unifi/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/.travis.yml b/core/unifi/.travis.yml index 3c936a6f..4346066d 100644 --- a/core/unifi/.travis.yml +++ b/core/unifi/.travis.yml @@ -5,7 +5,7 @@ before_install: # download super-linter: golangci-lint - curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin latest install: - - go mod vendor +- go mod vendor script: - golangci-lint run --enable-all -e G402 -D gochecknoglobals - go test ./... From 115ee799a30c1ead6586c95e99a76e4bbf6c4c6b Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Fri, 27 Dec 2019 20:56:27 -0800 Subject: [PATCH 121/194] add v4 folder --- core/unifi/v4/LICENSE | 23 + core/unifi/v4/README.md | 64 + core/unifi/v4/clients.go | 156 ++ core/unifi/v4/devices.go | 107 ++ core/unifi/v4/dpi.go | 2366 +++++++++++++++++++++++++++++ core/unifi/v4/examples/convert.sh | 26 + core/unifi/v4/examples/ids.json | 66 + core/unifi/v4/examples/uap.json | 738 +++++++++ core/unifi/v4/examples/ugw.json | 371 +++++ core/unifi/v4/examples/usw.json | 1720 +++++++++++++++++++++ core/unifi/v4/go.mod | 9 + core/unifi/v4/go.sum | 11 + core/unifi/v4/ids.go | 150 ++ core/unifi/v4/site.go | 124 ++ core/unifi/v4/types.go | 132 ++ core/unifi/v4/types_test.go | 41 + core/unifi/v4/uap.go | 566 +++++++ core/unifi/v4/uap_test.go | 53 + core/unifi/v4/udm.go | 183 +++ core/unifi/v4/unifi.go | 160 ++ core/unifi/v4/unifi_test.go | 62 + core/unifi/v4/usg.go | 252 +++ core/unifi/v4/usg_test.go | 60 + core/unifi/v4/usw.go | 377 +++++ core/unifi/v4/usw_test.go | 75 + 25 files changed, 7892 insertions(+) create mode 100644 core/unifi/v4/LICENSE create mode 100644 core/unifi/v4/README.md create mode 100644 core/unifi/v4/clients.go create mode 100644 core/unifi/v4/devices.go create mode 100644 core/unifi/v4/dpi.go create mode 100755 core/unifi/v4/examples/convert.sh create mode 100644 core/unifi/v4/examples/ids.json create mode 100644 core/unifi/v4/examples/uap.json create mode 100644 core/unifi/v4/examples/ugw.json create mode 100644 core/unifi/v4/examples/usw.json create mode 100644 core/unifi/v4/go.mod create mode 100644 core/unifi/v4/go.sum create mode 100644 core/unifi/v4/ids.go create mode 100644 core/unifi/v4/site.go create mode 100644 core/unifi/v4/types.go create mode 100644 core/unifi/v4/types_test.go create mode 100644 core/unifi/v4/uap.go create mode 100644 core/unifi/v4/uap_test.go create mode 100644 core/unifi/v4/udm.go create mode 100644 core/unifi/v4/unifi.go create mode 100644 core/unifi/v4/unifi_test.go create mode 100644 core/unifi/v4/usg.go create mode 100644 core/unifi/v4/usg_test.go create mode 100644 core/unifi/v4/usw.go create mode 100644 core/unifi/v4/usw_test.go diff --git a/core/unifi/v4/LICENSE b/core/unifi/v4/LICENSE new file mode 100644 index 00000000..9187a167 --- /dev/null +++ b/core/unifi/v4/LICENSE @@ -0,0 +1,23 @@ +MIT License + +Copyright (c) 2019 Go Lift - Building Strong Go Tools +Copyright (c) 2018 David Newhall II +Copyright (c) 2016 Garrett Bjerkhoel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/core/unifi/v4/README.md b/core/unifi/v4/README.md new file mode 100644 index 00000000..87f58e06 --- /dev/null +++ b/core/unifi/v4/README.md @@ -0,0 +1,64 @@ +# Go Library: `unifi` + +It connects to a Unifi Controller, given a url, username and password. Returns +an authenticated http Client you may use to query the device for data. Also +contains some built-in methods for de-serializing common client and device +data. The data is provided in a large struct you can consume in your application. + +This library is designed to PULL data FROM the controller. It has no methods that +update settings or change things on the controller. +[Someone expressed interest](https://github.com/golift/unifi/issues/31) in +adding methods to update data, and I'm okay with that. I'll even help add them. +[Tell me what you want to do](https://github.com/golift/unifi/issues/new), and we'll make it happen. + +Pull requests, feature requests, code reviews and feedback are welcomed! + +Here's a working example: +```golang +package main + +import "log" +import "golift.io/unifi" + +func main() { + c := *unifi.Config{ + User: "admin", + Pass: "superSecret1234", + URL: "https://127.0.0.1:8443/", + // Log with log.Printf or make your own interface that accepts (msg, fmt) + ErrorLog: log.Printf, + DebugLog: log.Printf, + } + uni, err := unifi.NewUnifi(c) + if err != nil { + log.Fatalln("Error:", err) + } + + sites, err := uni.GetSites() + if err != nil { + log.Fatalln("Error:", err) + } + clients, err := uni.GetClients(sites) + if err != nil { + log.Fatalln("Error:", err) + } + devices, err := uni.GetDevices(sites) + if err != nil { + log.Fatalln("Error:", err) + } + + log.Println(len(sites), "Unifi Sites Found: ", sites) + log.Println(len(clients), "Clients connected:") + for i, client := range clients { + log.Println(i+1, client.ID, client.Hostname, client.IP, client.Name, client.LastSeen) + } + + log.Println(len(devices.USWs), "Unifi Switches Found") + log.Println(len(devices.USGs), "Unifi Gateways Found") + + log.Println(len(devices.UAPs), "Unifi Wireless APs Found:") + for i, uap := range devices.UAPs { + log.Println(i+1, uap.Name, uap.IP) + } +} +``` diff --git a/core/unifi/v4/clients.go b/core/unifi/v4/clients.go new file mode 100644 index 00000000..ca4ea34d --- /dev/null +++ b/core/unifi/v4/clients.go @@ -0,0 +1,156 @@ +package unifi + +import ( + "fmt" +) + +// GetClients returns a response full of clients' data from the UniFi Controller. +func (u *Unifi) GetClients(sites Sites) (Clients, error) { + data := make([]*Client, 0) + + for _, site := range sites { + var response struct { + Data []*Client `json:"data"` + } + + u.DebugLog("Polling Controller, retreiving UniFi Clients, site %s (%s) ", site.Name, site.Desc) + + clientPath := fmt.Sprintf(APIClientPath, site.Name) + if err := u.GetData(clientPath, &response); err != nil { + return nil, err + } + + for i, d := range response.Data { + // Add special SourceName value. + response.Data[i].SourceName = u.URL + // Add the special "Site Name" to each client. This becomes a Grafana filter somewhere. + response.Data[i].SiteName = site.Desc + " (" + site.Name + ")" + // Fix name and hostname fields. Sometimes one or the other is blank. + response.Data[i].Hostname = pick(d.Hostname, d.Name, d.Mac) + response.Data[i].Name = pick(d.Name, d.Hostname) + } + + data = append(data, response.Data...) + } + + return data, nil +} + +// GetClientsDPI garners dpi data for clients. +func (u *Unifi) GetClientsDPI(sites Sites) ([]*DPITable, error) { + var data []*DPITable + + for _, site := range sites { + u.DebugLog("Polling Controller, retreiving Client DPI data, site %s (%s) ", site.Name, site.Desc) + + var response struct { + Data []*DPITable `json:"data"` + } + + clientDPIpath := fmt.Sprintf(APIClientDPI, site.Name) + if err := u.GetData(clientDPIpath, &response, `{"type":"by_app"}`); err != nil { + return nil, err + } + + for _, d := range response.Data { + d.SourceName = site.SourceName + d.SiteName = site.SiteName + data = append(data, d) + } + } + + return data, nil +} + +// Clients contains a list that contains all of the unifi clients from a controller. +type Clients []*Client + +// Client defines all the data a connected-network client contains. +type Client struct { + SourceName string `json:"-"` + Anomalies int64 `json:"anomalies,omitempty"` + ApMac string `json:"ap_mac"` + ApName string `json:"-"` + AssocTime int64 `json:"assoc_time"` + Blocked bool `json:"blocked,omitempty"` + Bssid string `json:"bssid"` + BytesR int64 `json:"bytes-r"` + Ccq int64 `json:"ccq"` + Channel FlexInt `json:"channel"` + DevCat FlexInt `json:"dev_cat"` + DevFamily FlexInt `json:"dev_family"` + DevID FlexInt `json:"dev_id"` + DevVendor FlexInt `json:"dev_vendor,omitempty"` + DhcpendTime int `json:"dhcpend_time,omitempty"` + Satisfaction FlexInt `json:"satisfaction,omitempty"` + Essid string `json:"essid"` + FirstSeen int64 `json:"first_seen"` + FixedIP string `json:"fixed_ip"` + GwMac string `json:"gw_mac"` + GwName string `json:"-"` + Hostname string `json:"hostname"` + ID string `json:"_id"` + IP string `json:"ip"` + IdleTime int64 `json:"idle_time"` + Is11R FlexBool `json:"is_11r"` + IsGuest FlexBool `json:"is_guest"` + IsGuestByUAP FlexBool `json:"_is_guest_by_uap"` + IsGuestByUGW FlexBool `json:"_is_guest_by_ugw"` + IsGuestByUSW FlexBool `json:"_is_guest_by_usw"` + IsWired FlexBool `json:"is_wired"` + LastSeen int64 `json:"last_seen"` + LastSeenByUAP int64 `json:"_last_seen_by_uap"` + LastSeenByUGW int64 `json:"_last_seen_by_ugw"` + LastSeenByUSW int64 `json:"_last_seen_by_usw"` + LatestAssocTime int64 `json:"latest_assoc_time"` + Mac string `json:"mac"` + Name string `json:"name"` + Network string `json:"network"` + NetworkID string `json:"network_id"` + Noise int64 `json:"noise"` + Note string `json:"note"` + Noted FlexBool `json:"noted"` + OsClass FlexInt `json:"os_class"` + OsName FlexInt `json:"os_name"` + Oui string `json:"oui"` + PowersaveEnabled FlexBool `json:"powersave_enabled"` + QosPolicyApplied FlexBool `json:"qos_policy_applied"` + Radio string `json:"radio"` + RadioName string `json:"radio_name"` + RadioProto string `json:"radio_proto"` + RadioDescription string `json:"-"` + RoamCount int64 `json:"roam_count"` + Rssi int64 `json:"rssi"` + RxBytes int64 `json:"rx_bytes"` + RxBytesR int64 `json:"rx_bytes-r"` + RxPackets int64 `json:"rx_packets"` + RxRate int64 `json:"rx_rate"` + Signal int64 `json:"signal"` + SiteID string `json:"site_id"` + SiteName string `json:"-"` + SwDepth int `json:"sw_depth"` + SwMac string `json:"sw_mac"` + SwName string `json:"-"` + SwPort FlexInt `json:"sw_port"` + TxBytes int64 `json:"tx_bytes"` + TxBytesR int64 `json:"tx_bytes-r"` + TxPackets int64 `json:"tx_packets"` + TxRetries int64 `json:"tx_retries"` + TxPower int64 `json:"tx_power"` + TxRate int64 `json:"tx_rate"` + Uptime int64 `json:"uptime"` + UptimeByUAP int64 `json:"_uptime_by_uap"` + UptimeByUGW int64 `json:"_uptime_by_ugw"` + UptimeByUSW int64 `json:"_uptime_by_usw"` + UseFixedIP FlexBool `json:"use_fixedip"` + UserGroupID string `json:"usergroup_id"` + UserID string `json:"user_id"` + Vlan FlexInt `json:"vlan"` + WifiTxAttempts int64 `json:"wifi_tx_attempts"` + WiredRxBytes int64 `json:"wired-rx_bytes"` + WiredRxBytesR int64 `json:"wired-rx_bytes-r"` + WiredRxPackets int64 `json:"wired-rx_packets"` + WiredTxBytes int64 `json:"wired-tx_bytes"` + WiredTxBytesR int64 `json:"wired-tx_bytes-r"` + WiredTxPackets int64 `json:"wired-tx_packets"` +} diff --git a/core/unifi/v4/devices.go b/core/unifi/v4/devices.go new file mode 100644 index 00000000..d877d9c4 --- /dev/null +++ b/core/unifi/v4/devices.go @@ -0,0 +1,107 @@ +package unifi + +import ( + "encoding/json" + "fmt" +) + +// GetDevices returns a response full of devices' data from the UniFi Controller. +func (u *Unifi) GetDevices(sites Sites) (*Devices, error) { + devices := new(Devices) + + for _, site := range sites { + var response struct { + Data []json.RawMessage `json:"data"` + } + + devicePath := fmt.Sprintf(APIDevicePath, site.Name) + if err := u.GetData(devicePath, &response); err != nil { + return nil, err + } + + loopDevices := u.parseDevices(response.Data, site.SiteName) + devices.UAPs = append(devices.UAPs, loopDevices.UAPs...) + devices.USGs = append(devices.USGs, loopDevices.USGs...) + devices.USWs = append(devices.USWs, loopDevices.USWs...) + devices.UDMs = append(devices.UDMs, loopDevices.UDMs...) + } + + return devices, nil +} + +// parseDevices parses the raw JSON from the Unifi Controller into device structures. +func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { + devices := new(Devices) + + for _, r := range data { + // Loop each item in the raw JSON message, detect its type and unmarshal it. + assetType := "" + + if o := make(map[string]interface{}); u.unmarshalDevice("map", r, &o) != nil { + continue + } else if t, ok := o["type"].(string); ok { + assetType = t + } + + u.DebugLog("Unmarshalling Device Type: %v, site %s ", assetType, siteName) + // 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, SourceName: u.URL} + 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, SourceName: u.URL} + 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, SourceName: u.URL} + if u.unmarshalDevice(assetType, r, dev) == nil { + dev.Name = pick(dev.Name, dev.Mac) + devices.USWs = append(devices.USWs, dev) + } + case "udm": + dev := &UDM{SiteName: siteName, SourceName: u.URL} + if u.unmarshalDevice(assetType, r, dev) == nil { + dev.Name = pick(dev.Name, dev.Mac) + devices.UDMs = append(devices.UDMs, dev) + } + default: + u.ErrorLog("unknown asset type - %v - skipping", assetType) + } + } + + return devices +} + +// unmarshalDevice handles logging for the unmarshal operations in parseDevices(). +func (u *Unifi) unmarshalDevice(dev string, data json.RawMessage, v interface{}) (err error) { + if err = json.Unmarshal(data, v); err != nil { + u.ErrorLog("json.Unmarshal(%v): %v", dev, err) + u.ErrorLog("Enable Debug Logging to output the failed payload.") + + json, err := data.MarshalJSON() + u.DebugLog("Failed Payload: %s (marshal err: %v)", json, err) + u.DebugLog("The above payload can prove useful during torubleshooting when you open an Issue:") + u.DebugLog("==- https://github.com/golift/unifi/issues/new -==") + } + + return err +} + +// pick returns the first non empty string in a list. +// used in a few places around this library. +func pick(strings ...string) string { + for _, s := range strings { + if s != "" { + return s + } + } + + return "" +} diff --git a/core/unifi/v4/dpi.go b/core/unifi/v4/dpi.go new file mode 100644 index 00000000..86170d03 --- /dev/null +++ b/core/unifi/v4/dpi.go @@ -0,0 +1,2366 @@ +package unifi + +import "strconv" + +// DPITable contains DPI data for clients or sites, or .. things. +type DPITable struct { + SourceName string `json:"-"` + SiteName string `json:"-"` + Name string `json:"-"` + MAC string `json:"mac"` + ByCat []DPIData `json:"by_cat"` + ByApp []DPIData `json:"by_app"` + LastUpdated int64 `json:"last_updated"` +} + +// DPIData is the DPI data in the DPI table. +type DPIData struct { + Cat int `json:"cat"` + App int `json:"app"` + RxBytes int64 `json:"rx_bytes"` + TxBytes int64 `json:"tx_bytes"` + RxPackets int64 `json:"rx_packets"` + TxPackets int64 `json:"tx_packets"` +} + +// DPIMap allows binding methods to the DPICat and DPIApps variables. +type DPIMap map[int]string + +// Get returns a value, or an unknown placeholder. +func (d DPIMap) Get(cat int) string { + if v, ok := d[cat]; ok { + return v + } + + return "Unknown_" + strconv.Itoa(cat) +} + +// GetApp returns an app value, or an unknown placeholder. +func (d DPIMap) GetApp(cat, app int) string { + if v, ok := d[cat<<16+app]; ok { + return v + } + + return "Unknown_" + strconv.Itoa(cat<<16+app) +} + +// Keys returns the map keys in a slice. +func (d DPIMap) Keys() []string { + out := []string{} + for k := range d { + out = append(out, strconv.Itoa(k)) + } + + return out +} + +// DPICats maps the categories to descriptions. +// From: https://fw-download.ubnt.com/data/usg-dpi/1628-debian-v1.442.0-05f5a57eaef344358bd5a8e84a184c18.tar +var DPICats = DPIMap{ + 0: "Instant Messengers", + 1: "Peer-to-Peer Networks", + 3: "File Sharing", + 4: "Media Streaming", + 5: "Email Messaging", + 6: "VoIP Services", + 7: "Database Tools", + 8: "Online Games", + 9: "Management Protocols", + 10: "Remote Access", + 11: "Tunneling and Proxy", + 12: "Investment Platforms", + 13: "Web Services", + 14: "Security Updates", + 15: "Web IM", + 17: "Business Tools", + 18: "Network Protocols_18", + 19: "Network Protocols_19", + 20: "Network Protocols_20", + 23: "Private Protocols", + 24: "Social Networks", + 255: "Unknown_255", +} + +// DPIApps maps the applications to names. +// From: https://fw-download.ubnt.com/data/usg-dpi/1628-debian-v1.442.0-05f5a57eaef344358bd5a8e84a184c18.tar +var DPIApps = DPIMap{ + 1: "MSN", + 2: "Yahoo Messenger", + 3: "AIM/ICQ/iIM", + 4: "QQ/TM", + 5: "DingTalk/Laiwang", + 6: "IRC", + 7: "Yoics", + 8: "Rediff BOL", + 9: "Google Talk", + 10: "Gadu-Gadu", + 11: "Yixin", + 12: "POPO", + 13: "Tlen", + 14: "Wlt", + 15: "RenRen", + 16: "Omegle", + 17: "IPMSG", + 18: "Aliww", + 19: "Mail.ru IM", + 20: "Kubao", + 21: "Lava-Lava", + 22: "PaltalkScene", + 23: "UcTalk", + 24: "WinpopupX", + 25: "BeeTalk", + 26: "Squiggle", + 27: "Apple iMessage", + 28: "Pidgin", + 29: "ISPQ", + 30: "Momo", + 31: "ChatON", + 32: "Caihong", + 33: "KC", + 34: "IMVU", + 35: "Instan-t", + 36: "PiIM", + 37: "Xfire", + 38: "Raidcall", + 39: "Slack", + 41: "WhatsApp", + 42: "Userplane", + 43: "24im", + 44: "Camfrog", + 45: "Snow", + 46: "Digsby", + 49: "Message Send Protocol", + 52: "SOMA", + 53: "Hike", + 54: "Fetion", + 55: "Heyyo", + 56: "Alicall", + 57: "Qeshow", + 58: "MissLee", + 59: "Jctrans", + 61: "BaiduHi", + 62: "TELTEL", + 64: "9158", + 65: "Kltx", + 66: "IM+", + 67: "Imi", + 68: "Netcall", + 69: "ECP", + 72: "Etnano", + 77: "ProvideSupport", + 78: "Dudu IM", + 80: "Weibo IM", + 81: "WO", + 82: "Guagua", + 83: "Hangouts", + 84: "ClubCooee", + 85: "Palringo", + 86: "KikMessenger", + 87: "Doshow", + 88: "Mibbit", + 89: "YY", + 90: "Ispeak", + 91: "VzoChat", + 92: "Trillian", + 93: "HipChat", + 94: "IntraMessenger", + 95: "BitWise", + 96: "Barablu", + 97: "Whoshere", + 98: "LiiHo", + 99: "Appme", + 100: "Verychat", + 101: "Voxer", + 102: "TextMe", + 103: "Bump", + 104: "CoolMessenger", + 105: "NateOn", + 106: "WeChat", + 107: "Snapchat", + 108: "Wangxin", + 65538: "BitTorrent Series", + 65540: "DirectConnect", + 65542: "eDonkey Series", + 65543: "FastTrack", + 65544: "Gnutella", + 65545: "WinMX", + 65546: "Foxy", + 65547: "Winny", + 65548: "POCO", + 65549: "iMesh/Lphant", + 65550: "ClubBox", + 65551: "Vagaa", + 65553: "Thunder", + 65554: "myMusic", + 65555: "QQDownload", + 65556: "WebTorrent", + 65557: "easyMule", + 65559: "Fileguri", + 65563: "Soulseek", + 65565: "GNUnet", + 65566: "XNap", + 65567: "Avicora", + 65568: "Kceasy", + 65569: "Aria2", + 65570: "Arctic", + 65572: "Bitflu", + 65573: "BTG", + 65574: "Pando", + 65577: "Deepnet Explorer", + 65578: "aMule", + 65580: "Ares", + 65581: "Azureus", + 65582: "BCDC++", + 65583: "BitBuddy", + 65584: "BitComet", + 65585: "BitTornado", + 65587: "ApexDC++", + 65588: "Bearshare", + 65590: "BitLord", + 65591: "BitSpirit", + 65594: "Shareaza", + 65598: "eMule", + 65600: "eMule Plus", + 65604: "FileScope", + 65609: "GoGoBox", + 65612: "Hydranode", + 65617: "Kazaa Lite Tools K++", + 65620: "BitRocket", + 65621: "MlDonkey", + 65622: "MooPolice", + 65630: "Phex", + 65633: "RevConnect", + 65634: "Rufus", + 65635: "SababaDC", + 65636: "Shareaza Plus", + 65640: "BTSlave", + 65642: "TorrentStorm", + 65648: "uTorrent", + 65652: "ZipTorrent", + 65655: "BitPump", + 65665: "Tuotu", + 65685: "Vuze", + 65686: "Enhanced CTorrent", + 65688: "Bittorrent X", + 65689: "DelugeTorrent", + 65690: "CTorrent", + 65691: "Propagate Data Client", + 65692: "EBit", + 65693: "Electric Sheep", + 65695: "FoxTorrent", + 65696: "GSTorrent", + 65698: "Halite", + 65700: "KGet", + 65701: "KTorrent", + 65703: "LH-ABC", + 65704: "libTorrent", + 65705: "LimeWire", + 65707: "MonoTorrent", + 65708: "MoonlightTorrent", + 65709: "Net Transport", + 65714: "qBittorrent", + 65715: "Qt 4 Torrent example", + 65716: "Retriever", + 65718: "Swiftbit", + 65720: "SwarmScope", + 65721: "SymTorrent", + 65722: "Sharktorrent", + 65724: "TorrentDotNET", + 65725: "Transmission", + 65726: "uLeecher", + 65727: "BitLet", + 65728: "FireTorrent", + 65730: "XanTorrent", + 65731: "Xtorrent", + 65732: "Pruna", + 65733: "Soribada", + 65734: "Gample", + 65735: "DIYHARD", + 65736: "LottoFile", + 65737: "ShareBox", + 65738: "Bondisk", + 65739: "Filei", + 65740: "KDISK", + 65741: "Ondisk", + 65742: "FILEJO", + 65743: "FILEDOK", + 65744: "Tomatopang/Santa25", + 65745: "Webhard", + 65746: "TPLE", + 65747: "DiskPump", + 65748: "NETFOLDER", + 65749: "QFILE", + 65750: "DISKMAN", + 65751: "DBGO", + 65752: "Congaltan", + 65753: "Diskpot", + 65754: "Ipopclub", + 65755: "Yesfile", + 65756: "Nedisk", + 65757: "Me2disk", + 65758: "Odisk", + 65759: "Tomfile", + 65760: "Adrive.co.kr", + 65761: "ZIOfile", + 65762: "APPLEFILE", + 65763: "SUPERDOWN", + 65764: "Hidisk", + 65765: "Downs", + 65766: "DownDay", + 65767: "BOMULBOX", + 65768: "FILEHAM", + 65769: "Tdisk", + 65770: "Filehon", + 65771: "Jjangfile", + 65772: "Onehard.com", + 65773: "Pdpop", + 65774: "AirFile", + 65775: "FILEZZIM", + 65776: "Atomfile.co.kr", + 65777: "QDOWN.com", + 65778: "Alfile.net", + 65779: "Bigfile.co.kr", + 65780: "Hardmoa.com", + 65781: "Redfile.co.kr", + 65782: "FILETV.co.kr", + 65783: "Now.co.kr", + 65784: "JustBeamIt", + 65785: "reep.io", + 65786: "GnucDNA/Gimme", + 65787: "MyNapster", + 196609: "FTP Applications", + 196610: "GetRight", + 196611: "FlashGet", + 196612: "AsianDVDClub", + 196613: "Web File Transfer", + 196614: "FileZilla", + 196615: "Kuaipan", + 196616: "DBank", + 196617: "115.com", + 196618: "Weiyun", + 196619: "Rayfile", + 196620: "0zz0", + 196621: "Herosh", + 196622: "2Shared", + 196624: "BIZHARD", + 196626: "UPlusBox", + 196627: "Filebox.ro", + 196628: "Qnext", + 196629: "OneDrive", + 196630: "YunFile", + 196631: "Filehosting", + 196632: "Dev-Host", + 196633: "Solidfiles", + 196634: "IBackup", + 196635: "FileSwap", + 196637: "Temp-Share", + 196638: "WikiUpload", + 196640: "MEGA", + 196641: "Copy.com", + 196642: "4Shared", + 196643: "HiCloud", + 196644: "Depositfiles", + 196645: "Docstoc", + 196646: "360 Cloud", + 196647: "Symantec Nomdb", + 196648: "Baidu Cloud", + 196649: "GitHub", + 196650: "FileDropper", + 196651: "CrashPlan", + 196652: "Net2FTP", + 196653: "Mediafire", + 196655: "Carbonite", + 196656: "Mozy", + 196657: "SOS Online Backup", + 196670: "NFS", + 196672: "WD My Cloud", + 196676: "Box", + 196678: "Scribd", + 196680: "Rapidshare", + 196681: "Sendspace", + 196683: "Hightail", + 196684: "Diino", + 196686: "Fluxiom", + 196689: "Nomadesk", + 196692: "Dropbox", + 196693: "Filesend.to", + 196694: "Firestorage", + 196695: "Naver Cloud", + 196696: "Filesend.net", + 196697: "Crocko", + 196700: "Fileserve", + 196701: "Netload", + 196702: "Megashares", + 196703: "TransferBigFiles", + 196705: "Filemail", + 196706: "Zamzar", + 196708: "Divshare", + 196709: "DL Free", + 196711: "Nakido", + 196713: "Gigaup", + 196714: "Filestube", + 196716: "Filer.cx", + 196717: "Cx.com", + 196718: "Elephantdrive", + 196722: "Zshare", + 196723: "Freakshare", + 196724: "Uploading", + 196725: "Bitshare", + 196726: "Letitbit.net", + 196727: "Extabit", + 196728: "Filefactory", + 196729: "Furk", + 196731: "GoldFile", + 196732: "GigaSize", + 196733: "Turbobit", + 196735: "Hitfile", + 196737: "Zippyshare", + 196738: "SoundCloud", + 196739: "SpeedyShare", + 196741: "WinSCP", + 196742: "FilePost.net", + 196743: "GlumboUploads", + 196744: "RapidGator.net", + 196745: "GoZilla", + 196746: "Clip2net", + 196747: "Datei.to", + 196748: "Totodisk", + 196749: "LeapFile", + 196750: "BigUpload", + 196751: "OnlineFileFolder", + 196752: "ASUSWebStorage", + 196753: "File-Upload.net", + 196754: "File-Works", + 196755: "Zumodrive", + 196756: "PutLocker", + 196757: "Wetransfer", + 196758: "iCloud", + 196759: "CloudMe", + 196760: "Beanywhere", + 196761: "Sugarsync", + 196762: "DriveHQ", + 196763: "Yandex.Disk", + 196764: "Backblaze", + 196765: "AirSet", + 196766: "SpiderOak", + 196767: "1337X", + 196768: "MailBigFile", + 196769: "GoldCoupon.co.kr", + 196770: "Egnyte", + 196771: "SmugMug", + 196772: "SlideShare.net", + 196773: "4Sync", + 196774: "IDrive", + 196775: "Mendeley", + 196777: "Daum-cloud", + 196778: "TeamBeam", + 262145: "Windows Media Player", + 262146: "RealPlayer", + 262147: "Winamp", + 262148: "QuickTime", + 262149: "Weather Channel", + 262150: "PPTV (PPLive)", + 262151: "QQLive", + 262152: "LOVEFiLM", + 262153: "ITV", + 262154: "iTunes", + 262155: "Adobe Flash", + 262156: "Channel 5", + 262157: "iQIYI/PPS", + 262158: "Headweb", + 262159: "Viaplay", + 262160: "KKBox", + 262161: "WATCHEVER", + 262162: "Maxdome", + 262163: "Twitch.tv", + 262164: "TED", + 262165: "RTP", + 262166: "SBS", + 262167: "UUSee", + 262168: "SopCast", + 262169: "KeyHoleTV", + 262170: "Sina Video", + 262171: "Metacafe", + 262172: "Wuaki.tv", + 262173: "SHOUTcast", + 262174: "BBC-iplayer", + 262175: "Live365", + 262176: "Dailymotion", + 262177: "Filmin", + 262178: "Flixster", + 262179: "Hulu", + 262180: "GuaGua", + 262181: "NUBEOX", + 262182: "Kugou", + 262183: "MoveNetworks", + 262184: "Babelgum", + 262185: "Livestation", + 262186: "Apple Music", + 262187: "Miro", + 262188: "Smithsonian Channel", + 262189: "NHL", + 262190: "NicoNico", + 262191: "Ooyala", + 262192: "Photobucket", + 262193: "MLSsoccer", + 262194: "Channel 4", + 262195: "VideoDetective", + 262196: "Ustream.tv", + 262197: "Veetle", + 262198: "VeohTV", + 262199: "iTunes Festival", + 262200: "SiriusXM", + 262201: "Break.com", + 262202: "CinemaNow/FilmOn", + 262203: "Letv", + 262204: "RTSP", + 262205: "Funshion", + 262206: "17", + 262207: "MTV.com", + 262208: "Sohu TV", + 262209: "MP4", + 262210: "MMS/WMSP", + 262211: "FLV", + 262212: "PIPI", + 262213: "Hulkshare", + 262214: "Tudou", + 262215: "Ifeng Video ", + 262216: "WSJ Live", + 262217: "Cradio", + 262218: "Roku", + 262219: "Amazon Prime Music", + 262220: "Crackle", + 262221: "Blip.tv", + 262223: "Audible", + 262224: "Web Streaming", + 262225: "DIRECTV", + 262226: "Vyclone", + 262227: "China Streaming Video", + 262228: "Crunchyroll", + 262229: "EmpFlix", + 262230: "Porn.com", + 262231: "EskimoTube", + 262232: "NewBigTube", + 262233: "Madbitties", + 262234: "RTMP", + 262235: "Hustlertube", + 262236: "TnaFlix", + 262237: "Xtube", + 262238: "Yobt.tv", + 262239: "Youjizz", + 262240: "v.163.com", + 262241: "Yahoo Video", + 262245: "Pandora", + 262246: "Deezer", + 262247: "VLC", + 262250: "Livesearch.tv/CoolStreaming", + 262251: "Qello", + 262252: "CNTV", + 262254: "Thunderkankan", + 262256: "Youtube", + 262258: "56.com", + 262259: "RMVB", + 262260: "Youku.com", + 262261: "SWF", + 262262: "AVI", + 262263: "MP3", + 262264: "WMA", + 262265: "MOV", + 262266: "WMV", + 262267: "ASF", + 262268: "Vudu", + 262270: "PBS Video", + 262271: "Freecast", + 262272: "Ku6", + 262274: "Spotify", + 262275: "LastFM", + 262276: "Netflix", + 262277: "Uitzendinggemist", + 262278: "RTL.nl", + 262279: "TudouVa", + 262280: "GYAO", + 262281: "BARKS", + 262283: "Baofeng", + 262284: "Qvod/Bobohu", + 262285: "Grooveshark", + 262286: "Microsoft Silverlight", + 262287: "6.cn", + 262288: "Rhapsody", + 262289: "Kideos", + 262290: "Imgo TV", + 262291: "Joy.cn", + 262292: "Yinyuetai", + 262293: "Hichannel", + 262294: "ADNstream", + 262295: "Livestream", + 262296: "YoukuVa ", + 262297: "Kodi", + 262298: "Voddler", + 262299: "National Geographic Kids", + 262301: "Flixwagon", + 262302: "M4V", + 262303: "Podcast", + 262305: "Shazam", + 262306: "TuneIn", + 262307: "PBS Kids", + 262308: "BaiduMusic", + 262310: "DoubanFM", + 262311: "IMDb.com", + 262312: "XVideos.com", + 262313: "xHamster.com", + 262314: "PornHub.com", + 262315: "LiveJasmin.com", + 262316: "XNXX.com", + 262317: "YouPorn.com", + 262318: "MajorLeagueGaming", + 262319: "Wowtv.co.kr", + 262320: "iMBC", + 262321: "AfreecaTV", + 262322: "Arirang", + 262323: "KCTVjeju", + 262324: "CJB.co.kr", + 262325: "MBN", + 262326: "MYSolive", + 262327: "KBS", + 262328: "Mwave", + 262329: "YTN", + 262330: "Musicsoda", + 262331: "FreeOnes.com", + 262332: "Streamate.com", + 262333: "Airplay", + 262334: "DAAP", + 262335: "M1905", + 262336: "VEVO", + 262337: "Amazon Instant Video", + 262338: "MixBit", + 262339: "Baomihua", + 262340: "FORA.tv", + 262341: "Vimeo", + 262342: "Vube", + 262343: "RedTube.com", + 262344: "Tube8", + 262345: "Mgoon", + 262346: "Trailers", + 262347: "HBOGO", + 262348: "MLB.com", + 262349: "Kaltura.com", + 262350: "Plex.tv", + 262351: "DouyuTV", + 262358: "Kids.gov", + 262367: "Periscope", + 262373: "HBO NOW", + 262374: "MiaoPai", + 262389: "UniFi Video Camera", + 327681: "SMTP", + 327682: "POP3", + 327683: "IMAP4", + 327684: "NNTP", + 327685: "Twig", + 327686: "GroupWise", + 327687: "au one net", + 327688: "Virtru", + 327689: "PChome", + 327690: "DTI MyMail", + 327691: "Ymail", + 327692: "IIJ MailViewer", + 327693: "Telenet Mail", + 327694: "Open Mail", + 327695: "InfoSphere Webmail", + 327696: "Goo Mail", + 327697: "Nifty", + 327698: "QQ Mail", + 327699: "Roundcubemail", + 327700: "Zenno", + 327701: "Itm-asp", + 327702: "Biglobe", + 327703: "SquirrelMail", + 327704: "Zoho Mail", + 327705: "Inter7", + 327706: "TOK2", + 327707: "Smoug", + 327708: "1und1", + 327709: "Plala", + 327710: "WAKWAK", + 327711: "Eyejot", + 327712: "AsahiNet", + 327713: "Aikq", + 327714: "Yandex.Mail", + 327715: "Arcor", + 327716: "Bluewin", + 327717: "Directbox", + 327718: "Freenet", + 327720: "Smart Mail", + 327722: "WEB.DE", + 327723: "MS Exchange Server", + 327732: "Webmail.de", + 327742: "NETEASE Mail", + 327743: "Gmx Mail", + 327744: "Excite", + 327745: "InfoSeek Mail", + 327746: "Livedoor", + 327747: "Nate Mail", + 327749: "Optimum", + 327751: "Secureserver", + 327753: "Sina Mail", + 327755: "Rambler", + 327760: "Daum Mail", + 327761: "Mail.com", + 327762: "OCN", + 327763: "MailChimp", + 327764: "Rediff Mail", + 327770: "Korea Mail", + 327772: "MyEmail", + 327773: "JumboMail", + 327775: "Gmail", + 327776: "AOL Mail", + 327777: "hiBox", + 327778: "COX", + 327779: "Hushmail", + 327780: "Mail.ru", + 327781: "HiNet Mail", + 327782: "Horde", + 327783: "Fastmail", + 327784: "Comcast", + 327785: "Laposte", + 327786: "Yahoo Mail", + 327787: "Usermin Mail", + 327788: "Tistory", + 327789: "Orange", + 327790: "012mail", + 327791: "T-Online", + 327792: "Jubii Mail", + 327793: "Whalemail", + 327794: "Lavabit", + 327795: "Tiscali", + 393217: "Skype", + 393218: "H.323", + 393220: "Facetime", + 393221: "Juiker", + 393222: "Sqwiggle", + 393223: "ooVoo", + 393225: "TeamSpeak", + 393226: "Ventrilo", + 393228: "SIP", + 393229: "NetMeeting", + 393230: "Inter-Asterisk", + 393231: "Net2Phone", + 393232: "MSRP", + 393234: "LINE", + 393235: "Fring", + 393236: "Goober", + 393238: "Viber", + 393239: "Kakao", + 393240: "iCall", + 393242: "Nimbuzz", + 393243: "Bobsled", + 393244: "indoona", + 393245: "Wi-Fi Calling", + 393246: "Tango", + 393247: "Ooma", + 458753: "MSSQL", + 458754: "MySQL", + 458755: "Oracle", + 458756: "PostgreSQL", + 458757: "SAP", + 458760: "Etelos", + 458761: "Centriccrm", + 458766: "MongoDB", + 458767: "Salesforce", + 458768: "MariaDB", + 524289: "QQ Game", + 524290: "Our Game", + 524291: "Cga.com", + 524292: "FIFA", + 524293: "PopKart", + 524294: "Archlord", + 524295: "AddictingGames.com", + 524296: "Realgame", + 524297: "Audition", + 524298: "Koramgame", + 524299: "BnB Game", + 524300: "Chinagame", + 524301: "CS Game", + 524302: "Diablo", + 524303: "Legend", + 524304: "Lineage", + 524306: "Quake Game", + 524307: "Diablo3", + 524308: "Sina Web Game", + 524310: "WOW Game", + 524311: "Ispeakgame", + 524312: "Torchlight2", + 524313: "MapleStory", + 524314: "TowerOfSaviors", + 524315: "Wolfenstein", + 524316: "Second Life", + 524317: "Kimi", + 524318: "Pokemon Go", + 524319: "PartyPoker", + 524320: "Pogo", + 524321: "PokerStars", + 524322: "Zango", + 524323: "Little Fighter 2", + 524324: "BomberClone", + 524325: "Doom", + 524326: "FSJOY", + 524327: "175pt", + 524328: "Zhuxian", + 524329: "GameTea/GameABC", + 524330: "Talesrunner", + 524331: "PK Game", + 524332: "Concerto Gate", + 524333: "TLBB", + 524334: "YBOnline", + 524335: "Xunyou", + 524336: "Mwo", + 524337: "Mobile Strike", + 524338: "WuLin", + 524339: "DNF Game", + 524340: "Bo Game", + 524341: "Gran Turismo", + 524343: "Electronic Arts", + 524344: "ZhengTu", + 524345: "SGOL", + 524346: "XY2Online", + 524347: "Asherons Call", + 524348: "Kali", + 524349: "EverQuest", + 524350: "XBOX", + 524351: "BrettspielWelt", + 524352: "Bet-at-Home", + 524353: "City of Heroes", + 524354: "ClubPenguin", + 524355: "StepMania", + 524356: "Battle.net", + 524358: "Apprentice", + 524359: "Monster Hunter Frontier Z", + 524360: "FreeLotto Game", + 524361: "Halo", + 524362: "iSketch", + 524363: "RuneScape", + 524364: "FUNMILY", + 524365: "Yeapgame", + 524366: "Grand Theft Auto", + 524367: "Lineage2", + 524368: "GM99 Game", + 524369: "RayCity", + 524370: "Rockstar Games", + 524371: "Aleph One", + 524372: "Wayi", + 524373: "CMWEBGAME", + 524374: "Call of Duty", + 524375: "CAPTAN", + 524376: "Supercell", + 524377: "Need for Speed", + 524379: "Madden NFL", + 524380: "Half-Life", + 524381: "Team Fortress", + 524383: "Final Fantasy", + 524384: "Mythic", + 524385: "NetPanzer", + 524386: "Sdo.com", + 524388: "Pokemon Netbattle", + 524389: "RunUO-Ultima", + 524390: "Soldat Dedicated", + 524391: "Blizzard Entertainment", + 524392: "RIFT", + 524393: "TetriNET", + 524394: "Tibia", + 524395: "PlanetSide", + 524396: "TripleA", + 524398: "Unreal", + 524399: "Valve Steam", + 524400: "WesNOth", + 524401: "Xpilot", + 524402: "Swtor", + 524403: "EVEOnline", + 524404: "Hearthstone", + 524405: "Guild Wars", + 524406: "Zhong Hua Hero", + 524407: "Wizard101", + 524408: "SD Gundam", + 524409: "Prius", + 524410: "Age of Conan", + 524411: "RF Returns", + 524412: "AION", + 524413: "POPO Game", + 524414: "War-Rock", + 524415: "TEN Game", + 524416: "LUNA2", + 524417: "Karos", + 524418: "SPOnline", + 524419: "RO Game", + 524420: "StarCraft2", + 524421: "Itaiwanmj", + 524422: "CMWEBGAME Game", + 524423: "Beanfun Game", + 524424: "JXW", + 524425: "Nobol", + 524426: "DragonNest", + 524427: "BBonline", + 524428: "Hangame", + 524429: "Homygame", + 524430: "Sony PlayStation", + 524431: "Garena", + 524432: "91555", + 524433: "JJ Game", + 524434: "YHgame", + 524435: "Mdm365", + 524436: "7fgame", + 524437: "Dokee", + 524438: "VSA", + 524439: "Funtown", + 524440: "SF Game", + 524441: "173kh", + 524442: "Boyaapoker", + 524443: "GameCenter", + 524444: "Minecraft", + 524445: "Dark Souls", + 524446: "The Secret World", + 524447: "World2", + 524448: "CrossFire", + 524449: "XYQ", + 524450: "Nexon", + 524451: "Vindictus", + 524452: "DotA", + 524453: "PAYDAY", + 524454: "Wayi Game", + 524455: "War Thunder", + 524456: "Warframe", + 524457: "TT-Play Game", + 524458: "TT-Play", + 524459: "Robocraft", + 524460: "World of Tanks", + 524461: "Divinity", + 524462: "Left 4 Dead 2", + 524463: "DayZ", + 524464: "Heroes of the Storm", + 524466: "TXWY Game", + 524476: "Smite", + 524478: "FreeStyle 2 Street Basketball", + 524479: "Yeapgame Game", + 524483: "BlackShot", + 524486: "Combat Arms", + 524490: "Blade and Soul", + 524491: "FUNMILY Game", + 524500: "Elsword", + 524501: "Echo of Soul", + 524502: "Aura Kingdom", + 524503: "Aeria Games", + 524504: "9-yin", + 524505: "Tera", + 524506: "PSO2", + 524507: "Mabinogi", + 524510: "Ubisoft", + 524512: "Sony Entertainment Network", + 524513: "WSOP", + 524514: "TexasHoldemPoker", + 524515: "DarkSummoner", + 524516: "AjaxPlay", + 524517: "AirlineMogul", + 524518: "Evony", + 524519: "BasketBallZone", + 524520: "Y8 Game", + 524521: "Y8-Y8", + 524522: "KIZI-GAMES", + 524523: "Ibibo", + 524524: "Hattrick Game", + 524525: "Godgame", + 524526: "Aswordtw", + 524527: "Qme RO", + 524529: "THE WORLD", + 524530: "Qme JH", + 524531: "Qme COS", + 524532: "Qme SG", + 524533: "Origin", + 524534: "LoL", + 524535: "THISISGAME", + 524536: "Miniclip Game", + 524537: "888games", + 524538: "WilliamHill", + 524539: "Betfair Game", + 524540: "Kongregate Game", + 524541: "Roblox Game", + 524542: "King Game", + 524543: "Chess Game", + 524593: "Overwatch", + 524632: "Battlefield", + 524633: "Star Wars Battlefront", + 524639: "Rainbow Six Siege", + 524640: "ARK Survival Evolved", + 524641: "The Division", + 524648: "Super Mario Run", + 524649: "Nintendo", + 524651: "Clash of Clans", + 524652: "Clash Royale", + 524736: "Grand Theft Auto: San Andreas", + 524782: "Destiny 2", + 524790: "NBA 2K18", + 524794: "Uncharted: The Lost Legacy", + 524795: "NHL 18", + 524796: "NBA Live 18", + 524801: "Wargaming.net", + 589828: "IGMP", + 589829: "SNMP", + 589885: "DNS", + 589888: "Multicast DNS", + 589890: "Finger protocol", + 589916: "DCE-RPC", + 589933: "SSDP", + 589934: "SMB", + 589936: "SMB2", + 589942: "ICMP", + 589951: "UPnP", + 655361: "pcAnywhere", + 655362: "VNC", + 655363: "TeamViewer", + 655364: "MS Remote Desktop Protocol (RDP)", + 655365: "Chrome Remote Desktop", + 655366: "NTRglobal", + 655367: "RemoteCall", + 655368: "LiveCare", + 655369: "GoToMyPC", + 655370: "Pulseway", + 655371: "Radmin", + 655372: "Beinsync", + 655373: "Fastviewer", + 655374: "CrossTec Remote Control", + 655375: "GoToMeeting", + 655376: "ShowMyPC", + 655377: "Join.me", + 655378: "Telnet", + 655379: "Techinline", + 655380: "ISL Online", + 655381: "Secure Shell (SSH)", + 655385: "IBM Remote monitoring and Control", + 655395: "Netviewer", + 655396: "VT100", + 655397: "AnyDesk", + 655398: "X11", + 655399: "Alpemix", + 655402: "Instanthousecall", + 655403: "Ammyy", + 655404: "Anyplace Control", + 655405: "BeamYourScreen", + 655406: "Laplink Everywhere", + 655407: "GoToAssist", + 655408: "MSP Anywhere", + 720898: "VNN", + 720899: "Spotflux", + 720900: "SoftEther/PacketiX", + 720901: "TinyVPN", + 720902: "HTTP-Tunnel", + 720903: "Tor", + 720904: "Ping Tunnel", + 720905: "Wujie/UltraSurf", + 720906: "Freegate", + 720907: "Hidemyass", + 720909: "Vedivi", + 720910: "ZenMate", + 720911: "Hamachi", + 720912: "Disconnect.me", + 720914: "Asproxy", + 720915: "OpenDoor", + 720916: "NSTX DNS Tunnel", + 720917: "Coralcdn", + 720918: "Glype", + 720919: "GPass", + 720920: "Kproxy", + 720921: "Megaproxy", + 720922: "FreeSafeIP", + 720924: "GreenVPN", + 720925: "Surrogafier", + 720926: "Vtunnel", + 720927: "GomVPN", + 720928: "BypassThat", + 720929: "GetPrivate", + 720930: "JAP/JonDo", + 720933: "SofaWare", + 720934: "FlyProxy", + 720936: "Kerberos", + 720939: "EasyHideIP", + 720942: "CPROXY", + 720943: "AnonyMouse", + 720945: "Avoidr", + 720946: "Hidedoor", + 720948: "CGIProxy", + 720949: "ProxyTopSite", + 720950: "Phproxy", + 720951: "OpenVPN", + 720952: "CCProxy", + 720953: "Proxy Rental", + 720954: "PD-Proxy", + 720955: "Proxy4Free", + 720957: "Hideman", + 720959: "Rtmpt", + 720960: "LogMeIn", + 720961: "HotspotShield", + 720962: "ExpressVPN", + 720963: "GogoNET", + 720964: "HTTP Proxy Server", + 720965: "Hola", + 720966: "Texasproxy", + 720967: "Ourproxy", + 720968: "Proxify", + 720969: "Fast Proxy", + 720970: "Zalmos", + 720971: "Easy Proxy", + 720972: "Proxy Era", + 720973: "DotVPN", + 720974: "BrowSec", + 720976: "Unblock Proxy", + 720977: "Air-Proxy", + 720978: "Suresome", + 720979: "Defilter", + 720980: "SSLunblock", + 720983: "K12History", + 720984: "SurfEasy", + 720985: "Frozenway", + 720986: "CyberGhostVPN", + 720987: "SecurityKISS", + 720988: "WebWarper", + 720989: "Guardster", + 720990: "ProxFree", + 720991: "TunnelBear", + 720992: "AstrillVPN", + 720993: "Hide ALL IP", + 720994: "ZfreeZ", + 720995: "IPVanish", + 720996: "PrivateTunnel", + 720997: "SaferSurf", + 720998: "SecureLine VPN", + 720999: "Steganos VPN", + 721000: "StrongVPN", + 721001: "ZeroTier", + 721002: "Ngrok", + 721003: "Pagekite", + 721004: "Goproxing", + 721005: "VPN.HT", + 721006: "Betternet", + 721007: "Hide My IP", + 721008: "Stay Invisible", + 721009: "Zapyo", + 721010: "NordVPN", + 721011: "Avast SecureLine", + 721013: "Tunnello", + 721014: "Opera VPN", + 786434: "DZH", + 786435: "10JQKA", + 786437: "Qianlong", + 786438: "Compass.cn", + 786439: "Huaan", + 786440: "StockStar ", + 786441: "TDX", + 786443: "Hexun", + 786444: "Hypwise", + 786449: "Kiwoom", + 786450: "Windin", + 786451: "SamsungPoP", + 786453: "StockTrace", + 786454: "JRJ", + 786455: "TradeFields", + 786456: "Bloomberg", + 786457: "Netdania", + 786458: "TradeInterceptor", + 851969: "WhiteHat Aviator", + 851970: "HTC Widget", + 851971: "Doodle", + 851972: "Level3", + 851973: "FuzeMeeting", + 851974: "Mobile01", + 851975: "Speedtest.net", + 851976: "Google Chrome", + 851977: "Babelfish", + 851978: "Google Translate", + 851980: "Mozilla Firefox", + 851981: "Apple Safari", + 851982: "Opera browser", + 851984: "Google Books", + 851985: "eBay", + 851986: "hao123", + 851987: "WebSocket", + 851988: "Tmall", + 851989: "PayPal.com", + 851990: "Ask.com", + 851991: "BBC", + 851992: "Alibaba.com", + 851993: "CNN.com", + 851995: "Sogou.com", + 851996: "Evernote", + 851997: "About.com", + 851998: "Alipay.com", + 851999: "Imgur", + 852000: "Adcash", + 852001: "Huffington Post", + 852002: "360buy", + 852003: "ESPN", + 852004: "Books", + 852005: "Craigslist.org", + 852006: "Google Analytics", + 852007: "Bing Maps", + 852008: "ETtoday ", + 852009: "104 Job Bank", + 852010: "NOWnews", + 852011: "518 Job Bank", + 852012: "Chinatimes.com", + 852013: "GOHAPPY", + 852014: "591", + 852015: "8591", + 852016: "Chinatrust", + 852017: "Donga.com", + 852018: "Gmarket", + 852019: "Chosun.com", + 852020: "Cafe24.com", + 852021: "11st", + 852022: "MK.co.kr", + 852023: "Auction", + 852024: "Hankyung", + 852025: "Ppomppu", + 852026: "MT.co.kr", + 852027: "Zum.com", + 852028: "Hankooki", + 852029: "JOBKOREA", + 852031: "Khan.co.kr", + 852032: "Incruit", + 852033: "YES24", + 852034: "Amazon CloudFront", + 852035: "Pcstore", + 852036: "Myfreshnet.com", + 852037: "Microsoft.com", + 852038: "Life.com.tw", + 852039: "Libertytimes", + 852040: "Lativ", + 852041: "Inven", + 852042: "cnYES", + 852043: "Babyhome", + 852044: "8comic.com", + 852045: "Ck101.com", + 852046: "Taiwanlottery", + 852047: "Momoshop", + 852048: "Eyny.com", + 852049: "Yam.com", + 852050: "PChome.com", + 852051: "Gamme", + 852052: "Apple.com", + 852053: "Hinet.net", + 852054: "Google Earth", + 852055: "Saramin", + 852056: "KoreaHerald", + 852057: "Plus28.com", + 852058: "ChunghwaPost ", + 852059: "Gomaji ", + 852060: "NewSen", + 852061: "Etnews.com", + 852062: "Seoul.co.kr", + 852063: "YONHAPNEWS", + 852064: "Etoday.co.kr", + 852065: "Yesky.com", + 852066: "1111 Job Bank", + 852067: "Emart", + 852068: "KBstar", + 852069: "HERALDCORP", + 852070: "ActiveX", + 852071: "MSN.com", + 852072: "Edaily", + 852073: "Segye", + 852074: "Bobaedream", + 852075: "Nocutnews", + 852076: "MONETA.co.kr", + 852077: "Kukinews", + 852078: "Java Applet", + 852079: "Todayhumor", + 852080: "Inews24", + 852081: "KoreaTimes", + 852082: "OhmyNews", + 852083: "Aladin.co.kr", + 852084: "SK Encar", + 852085: "eTorrent", + 852086: "TVREPORT", + 852087: "Mydaily", + 852088: "Microsoft Live.com", + 852089: "News1.kr", + 852090: "Munhwa", + 852091: "Dreamwiz", + 852092: "Dailian.co.kr", + 852093: "Rediff.com", + 852094: "Akamai.net", + 852096: "Microsoft Edge", + 852097: "Yugma", + 852098: "TPB PirateBrowser", + 852099: "Android browser", + 852100: "Wikispaces", + 852101: "Wikidot", + 852102: "Google Play", + 852103: "Wetpaint", + 852104: "Windows Store", + 852105: "Webshots", + 852106: "Kindle Cloud Reader", + 852107: "Nice264", + 852108: "Symbian browser", + 852109: "Vyew", + 852110: "TikiWiki", + 852111: "Castfire", + 852112: "Mercari", + 852113: "SugarCRM", + 852115: "Stumbleupon", + 852116: "Yahoo Shopping", + 852117: "Clothes Aoyama", + 852118: "Rakuten Shopping", + 852119: "Spark", + 852120: "Socialtext", + 852121: "CacaoWeb", + 852122: "PBworks", + 852123: "Fool", + 852124: "Showbie", + 852125: "MorningStar", + 852126: "Screaming Frog SEO Spider", + 852127: "MoinMoin", + 852128: "AppStore", + 852129: "Ragingbull", + 852130: "Daum", + 852131: "Google Docs", + 852133: "Naver", + 852134: "Editgrid", + 852135: "Jaspersoft", + 852136: "Clarizen", + 852139: "Interpark", + 852140: "Hyundaihmall", + 852141: "Groupon", + 852142: "Gsshop", + 852143: "Wemakeprice", + 852144: "Lotte.com", + 852145: "Coupang", + 852147: "Google Alerts", + 852149: "Dnshop.com", + 852150: "ZoomSpider crawler", + 852151: "Win Web Crawler", + 852152: "HTTrack crawler", + 852153: "Abot crawler", + 852154: "Googlebot crawler", + 852155: "Microsoft bingbot crawler", + 852156: "Yahoo Slurp crawler", + 852157: "Beanfun", + 852158: "QUIC", + 852159: "ifeng.com", + 852160: "Conduit Mobile", + 852161: "Rakuten Point", + 852162: "Gamebase", + 852163: "Kingstone", + 852164: "Udn.com", + 852165: "Fril", + 852166: "Sportsseoul", + 852167: "Babylon ", + 852168: "Yahoo Finance", + 852170: "Creative Cloud", + 852171: "Jira", + 852172: "PHPwiki", + 852173: "Rakuten Edy", + 852174: "WebCT", + 852175: "Youseemore", + 852176: "Zwiki-editing", + 852177: "Adobe.com", + 852178: "Backpackit/Campfire", + 852180: "ERoom-net", + 852182: "DiDiTaxi", + 852184: "Glide", + 852186: "Mediawiki", + 852187: "fitbit", + 852188: "LastPass", + 852189: "National Geographic", + 852190: "HTTP", + 852191: "AOL Toolbar", + 852192: "Yandex.Browser", + 852193: "Uber", + 852194: "Web-crawler", + 852195: "RSS", + 852196: "WeatherBug", + 852197: "Yahoo Toolbar", + 852198: "Alexa Toolbar", + 852199: "Internet Archive", + 852200: "Wikipedia", + 852201: "Wiktionary", + 852202: "Amazon", + 852203: "Google Toolbar", + 852205: "Zoho", + 852206: "Microsoft Internet Explorer", + 852207: "Localmind", + 852208: "LinkedIn Pulse", + 852209: "BookU", + 852210: "Zappos", + 852211: "Expedia", + 852212: "AdF.ly", + 852213: "Baidu", + 852214: "Yahoo", + 852215: "Taobao", + 852216: "163.com", + 852217: "Sina.com", + 852218: "Bing.com", + 852219: "Ruten", + 852220: "Shop.com", + 852221: "Appledaily", + 852222: "CWB", + 852223: "CNA", + 852224: "Harvey Norman", + 852225: "Hackpad", + 852226: "JB Hi-Fi", + 852227: "MyDeal.com.au", + 852228: "AUSHOP", + 852229: "CrazySales", + 852230: "Giphy", + 852231: "Riffsy", + 852232: "Gumtree", + 852233: "Priceline", + 852234: "Carousell", + 852235: "Wish", + 852236: "Shein Shopping", + 852237: "Romwe", + 852238: "The Iconic", + 852239: "Boohoo", + 852240: "Aliexpress", + 852241: "ASOS", + 852242: "Catch of the Day", + 852273: "Amazon AppStream", + 917505: "TrendMicro Titanium-6-ICRC", + 917506: "TrendMicro Titanium-7-ICRC", + 917507: "TrendMicro Titanium-8-ICRC", + 917508: "BitDefender", + 917509: "360Safe", + 917510: "Rising", + 917511: "TortoiseSVN", + 917513: "Microsoft Windows Update", + 917514: "Norton", + 917515: "Sophos", + 917516: "Yum", + 917517: "MIUI", + 917518: "Adobe", + 917519: "InstallAnyWhere", + 917520: "Kaspersky", + 917521: "McAfee", + 917522: "TrendMicro", + 917523: "F-Secure", + 917524: "NOD32", + 917525: "Avast", + 917526: "Jiangmin", + 917527: "Avira", + 917528: "Emsisoft", + 917529: "Panda", + 917530: "AVG", + 917531: "PCTools", + 917532: "TrendMicro Titanium-10-ICRC", + 917533: "Outpost", + 917534: "Spybot", + 917535: "Duba", + 917536: "Apple", + 917538: "Google Update", + 917539: "TrendMicro Titanium-6-WTP", + 917540: "JAVA Update", + 917541: "SONY PC/Xperia Companion", + 917542: "SketchUp", + 917543: "Webroot", + 917544: "TrendMicro Titanium-7-WTP", + 917545: "TrendMicro Titanium-8-WTP", + 917546: "TrendMicro Titanium-10-WTP", + 917547: "TrendMicro Titanium-11-ICRC", + 917548: "TrendMicro Titanium-11-WTP", + 917549: "TrendMicro Titanium-12-ICRC", + 917550: "TrendMicro Titanium-12-WTP", + 983043: "eBuddy.com", + 983044: "iLoveIM.com", + 983047: "imo.im", + 983048: "Chikka", + 983050: "QQ Web Messenger", + 983051: "AOL Web Messenger", + 983054: "ICQ Web Messenger", + 983057: "AirAim", + 983058: "Instan-t Web Messenger", + 983065: "TaoBao AliWW", + 983069: "Gadu-Gadu Web Messenger", + 983070: "Karoo Lark", + 983072: "Web IM+", + 1114113: "WatchGuard WSM Management", + 1114114: "WatchGuard Web Management UI", + 1114115: "WatchGuard Authentication Access", + 1114117: "WatchGuard external Webblocker database fetch", + 1114118: "Livelink", + 1114119: "Altiris", + 1114120: "AMS", + 1114121: "Apache Synapse", + 1114122: "WatchGuard CLI ", + 1114124: "Webex", + 1114125: "Webex-WebOffice", + 1114128: "Avamar", + 1114129: "Avaya", + 1114130: "BackupExec", + 1114131: "Bitcoin Core", + 1114133: "Microsoft OS license", + 1114134: "Microsoft Office 2013 license", + 1114138: "BZFlag", + 1114140: "CAJO", + 1114141: "Cisco HSRP", + 1114142: "SkyDesk", + 1114144: "Microsoft Office", + 1114150: "openQRM", + 1114151: "Citrix", + 1114152: "CodeMeter", + 1114155: "Corba", + 1114158: "Cups", + 1114160: "Cvsup", + 1114161: "DameWare", + 1114167: "Db2", + 1114168: "Docker", + 1114169: "Dclink", + 1114170: "Urchin Web Analytics", + 1114172: "Applications Manager", + 1114174: "Zoom", + 1114176: "EForward-document transport system", + 1114177: "EMWIN", + 1114179: "Adobe Connect", + 1114182: "Big Brother", + 1114185: "Fuze Meeting", + 1114187: "FritzBox", + 1114188: "Skype for Business", + 1114191: "Websense", + 1114195: "Whisker", + 1114201: "HP-JetDirect", + 1114203: "VMWare", + 1114205: "IBM HTTP", + 1114206: "IBM SmartCloud", + 1114212: "IMS", + 1114213: "Informix", + 1114222: "Limelight", + 1114229: "Lawson-m3", + 1114238: "Meeting-maker", + 1114239: "Zendesk", + 1114246: "Microsoft DTC", + 1114248: "Microsoft Netlogon", + 1114250: "Microsoft Remote Web Workplace", + 1114251: "Office Sway", + 1114252: "Sharepoint-wiki", + 1114253: "Microsoft SSDP", + 1114255: "GatherPlace", + 1114269: "Xgrid", + 1114272: "Backweb", + 1114273: "Bugzilla", + 1114274: "NCube", + 1114275: "WinboxRouterOS", + 1114277: "WSO2", + 1114279: "NetFlow", + 1114289: "concur", + 1114290: "NetSupport", + 1114308: "DirectAdmin", + 1114309: "EasyBits", + 1114310: "Eiq-sec-analyzer", + 1114311: "Netbotz", + 1114312: "Aspera FASP", + 1114318: "Perforce", + 1114320: "TiVoConnect", + 1114321: "Polycom", + 1114322: "WebSphere", + 1114330: "Radacct RADIUS", + 1114334: "Securemeeting", + 1114337: "SANE", + 1114339: "WebHost", + 1114340: "CPanel", + 1114342: "Sibelius", + 1114343: "Siebel-crm", + 1114347: "SMS", + 1114350: "Spirent", + 1114351: "SPSS", + 1114352: "Subversion", + 1114355: "Tripwire", + 1114359: "WatchGuard Webblocker database transfer", + 1114361: "WatchGuard Security Event Processor logging", + 1114363: "Genesys Meeting Center", + 1114365: "Nagios", + 1114366: "Microsoft Office 365", + 1114396: "ChatWork", + 1179649: "TCP Port Service Multiplexer", + 1179650: "Management Utility", + 1179651: "Compression Process", + 1179652: "Zeroconf", + 1179653: "Echo", + 1179654: "Discard", + 1179655: "Active Users", + 1179656: "L2TP", + 1179657: "puparp", + 1179658: "vsinet", + 1179659: "maitrd", + 1179660: "Character Generator", + 1179663: "applix", + 1179664: "Net Assistant", + 1179665: "any private mail system", + 1179666: "BackOrifice", + 1179667: "AltaVista Firewall97", + 1179668: "NSW User System FE", + 1179669: "MSG ICP", + 1179670: "MSG Authentication", + 1179671: "Display Support Protocol", + 1179672: "any private printer server", + 1179673: "Time", + 1179674: "Route Access Protocol", + 1179675: "Resource Location Protocol", + 1179676: "graphics", + 1179677: "Host Name Server", + 1179678: "NIC Name", + 1179679: "MPM FLAGS Protocol", + 1179680: "Message Processing Module [recv]", + 1179681: "MPM [default send]", + 1179682: "NI FTP", + 1179683: "Digital Audit Daemon", + 1179684: "Login Host Protocol (TACACS)", + 1179685: "Remote Mail Checking Protocol", + 1179686: "IMP Logical Address Maintenance", + 1179687: "XNS Time Protocol", + 1179688: "Domain Name Server", + 1179689: "XNS Clearinghouse", + 1179690: "ISI Graphics Language", + 1179691: "XNS Authentication", + 1179692: "Mail Transfer Protocol (MTP)", + 1179693: "XNS Mail", + 1179694: "any private file service", + 1179695: "NI MAIL", + 1179696: "ACA Services", + 1179697: "VIA Systems - FTP whois++", + 1179698: "Communications Integrator (CI)", + 1179699: "TACACS-Database Service", + 1179700: "Oracle SQL-NET", + 1179701: "Bootstrap Protocol Server", + 1179702: "Bootstrap Protocol Client", + 1179703: "profile", + 1179704: "Gopher", + 1179705: "Remote Job Service", + 1179706: "any private dial out service", + 1179707: "Distributed External Object Store", + 1179708: "any private RJE service netrjs", + 1179709: "Vet TCP", + 1179710: "Finger", + 1179711: "World Wide Web HTTP", + 1179712: "Torpark", + 1179713: "XFER Utility", + 1179714: "MIT ML Device", + 1179715: "Common Trace Facility", + 1179716: "Micro Focus Cobol", + 1179717: "any private terminal link ttylink", + 1179718: "Kerberos", + 1179719: "SU MIT Telnet Gateway", + 1179720: "DNSIX Securit Attribute Token Map", + 1179721: "MIT Dover Spooler", + 1179722: "Network Printing Protocol", + 1179723: "Device Control Protocol", + 1179724: "Tivoli Object Dispatcher", + 1179725: "BSD supdupd(8)", + 1179726: "DIXIE Protocol Specification", + 1179727: "Swift Remote Virtural File Protocol", + 1179728: "linuxconf", + 1179729: "Metagram Relay", + 1179731: "NIC Host Name Server", + 1179732: "ISO-TSAP Class 0", + 1179733: "Genesis Point-to-Point Trans Net", + 1179734: "ACR-NEMA Digital Imag. & Comm. 300", + 1179735: "Mailbox Name Nameserver", + 1179736: "msantipiracy", + 1179737: "Eudora compatible PW changer", + 1179739: "SNA Gateway Access Server", + 1179740: "PostOffice V.2", + 1179742: "Portmapper RPC Bind", + 1179743: "McIDAS Data Transmission Protocol", + 1179744: "Ident Tap Authentication Service", + 1179745: "Audio News Multicast", + 1179746: "Simple File Transfer Protocol", + 1179747: "ANSA REX Notify", + 1179748: "UUCP Path Service", + 1179749: "SQL Services", + 1179751: "blackjack", + 1179752: "Encore Expedited Remote Pro.Call", + 1179753: "Smakynet", + 1179754: "Network Time Protocol", + 1179755: "ANSA REX Trader", + 1179756: "Locus PC-Interface Net Map Ser", + 1179757: "Unisys Unitary Login", + 1179758: "Locus PC-Interface Conn Server", + 1179759: "GSS X License Verification", + 1179760: "Password Generator Protocol", + 1179761: "Cisco FNATIVE", + 1179762: "Cisco TNATIVE", + 1179763: "Cisco SYSMAINT", + 1179764: "Statistics Service", + 1179765: "INGRES-NET Service", + 1179766: "NCS local location broker", + 1179767: "PROFILE Naming System", + 1179768: "NetBIOS Name Service", + 1179769: "NetBIOS Datagram Service", + 1179770: "NetBIOS Session Service", + 1179771: "EMFIS Data Service", + 1179772: "EMFIS Control Service", + 1179773: "Britton-Lee IDM", + 1179774: "Internet Message Access Protocol", + 1179775: "Universal Management Architecture", + 1179776: "UAAC Protocol", + 1179777: "iso-ip0", + 1179778: "iso-ip", + 1179779: "Jargon", + 1179780: "AED 512 Emulation Service", + 1179781: "SQL-net", + 1179782: "HEMS", + 1179783: "Background File Transfer Program (BFTP)", + 1179784: "SGMP", + 1179785: "NetSC-prod", + 1179786: "NetSC-dev", + 1179787: "SQL Service", + 1179788: "KNET VM Command Message Protocol", + 1179789: "PCMail Server", + 1179790: "NSS-Routing", + 1179791: "SGMP-traps", + 1179793: "SNMPTRAP", + 1179794: "CMIP TCP Manager", + 1179795: "CMIP TCP Agent", + 1179796: "Xerox", + 1179797: "Sirius Systems", + 1179798: "namp", + 1179799: "rsvd", + 1179800: "send", + 1179801: "Network PostScript", + 1179802: "Network Innovations Multiplex", + 1179803: "Network Innovations CL 1", + 1179804: "xyplex-mux", + 1179805: "mailq", + 1179806: "vmnet", + 1179807: "genrad-mux", + 1179808: "X Display Manager Control Protocol", + 1179809: "NextStep Window Server", + 1179810: "Border Gateway Protocol", + 1179811: "Intergraph", + 1179812: "unify", + 1179813: "Unisys Audit SITP", + 1179814: "ocbinder", + 1179815: "ocserver", + 1179816: "remote-kis", + 1179817: "KIS Protocol", + 1179818: "Application Communication Interface", + 1179819: "Plus Fives MUMPS", + 1179820: "Queued File Transport", + 1179821: "Gateway Access Control Protocol", + 1179822: "Prospero Directory Service", + 1179823: "OSU Network Monitoring System", + 1179824: "Spider Remote Monitoring Protocol", + 1179825: "Internet Relay Chat", + 1179826: "DNSIX Network Level Module Audit", + 1179827: "DNSIX Session Mgt Module Audit Redir", + 1179828: "Directory Location Service", + 1179829: "Directory Location Service Monitor", + 1179830: "SMUX", + 1179831: "IBM System Resource Controller", + 1179832: "AppleTalk Routing Maintenance", + 1179833: "AppleTalk Name Binding", + 1179834: "AppleTalk Unused", + 1179835: "AppleTalk Echo", + 1179836: "AppleTalk Zone Information", + 1179838: "Trivial Authenticated Mail Protocol", + 1179839: "ANSI Z39.50", + 1179840: "Texas Instruments", + 1179841: "ATEXSSTR", + 1179842: "IPX", + 1179843: "vmpwscs", + 1179844: "Insignia Solutions", + 1179845: "Computer Associates Intl License Server", + 1179846: "dBASE Unix", + 1179847: "Netix Message Posting Protocol", + 1179848: "Unisys ARPs", + 1179849: "Interactive Mail Access Protocol v3", + 1179850: "Berkeley rlogind with SPX auth", + 1179851: "Berkeley rshd with SPX auth", + 1179852: "Certificate Distribution Center", + 1179853: "masqdialer", + 1179854: "direct", + 1179855: "Survey Measurement", + 1179856: "inbusiness", + 1179857: "link", + 1179858: "Display Systems Protocol", + 1179859: "VAT", + 1179860: "bhfhs", + 1179862: "RAP (Route Access Protocol)", + 1179863: "Checkpoint Firewall-1", + 1179864: "Efficient Short Remote Operations", + 1179865: "openport", + 1179866: "Checkpoint Firewall-1 Management", + 1179867: "arcisdms", + 1179868: "hdap", + 1179869: "Border Gateway Multicast Protocol (BGMP)", + 1179870: "X-Bone CTL", + 1179871: "SCSI on ST", + 1179872: "Tobit David Service Layer", + 1179873: "Tobit David Replica", + 1179874: "http-mgmt", + 1179875: "personal-link", + 1179876: "Cable Port A X", + 1179877: "rescap", + 1179878: "corerjd", + 1179879: "FXP-1", + 1179880: "K-BLOCK", + 1179881: "Novastor Backup", + 1179882: "entrusttime", + 1179883: "bhmds", + 1179884: "AppleShare IP WebAdmin", + 1179885: "VSLMP", + 1179886: "magenta-logic", + 1179887: "opalis-robot", + 1179888: "DPSI", + 1179889: "decAuth", + 1179890: "zannet", + 1179891: "PKIX TimeStamp", + 1179892: "PTP Event", + 1179893: "PTP General", + 1179894: "Programmable Interconnect Point (PIP)", + 1179895: "RTSPS", + 1179896: "Texar Security Port", + 1179897: "Prospero Data Access Protocol", + 1179898: "Perf Analysis Workbench", + 1179899: "Zebra server", + 1179900: "Fatmen Server", + 1179901: "Cabletron Management Protocol", + 1179902: "mftp", + 1179903: "MATIP Type A", + 1245185: "PPTP", + 1245186: "BakBone NetVault", + 1245187: "DTAG or bhoedap4", + 1245188: "ndsauth", + 1245189: "bh611", + 1245190: "datex-asn", + 1245191: "Cloanto Net 1", + 1245192: "bhevent", + 1245193: "shrinkwrap", + 1245194: "Windows RPC", + 1245195: "Tenebris Network Trace Service", + 1245196: "scoi2odialog", + 1245197: "semantix", + 1245198: "SRS Send", + 1245200: "aurora-cmgr", + 1245201: "DTK", + 1245202: "odmr", + 1245203: "mortgageware", + 1245204: "qbikgdp", + 1245205: "rpc2portmap", + 1245206: "Coda authentication server (codaauth2)", + 1245207: "ClearCase", + 1245208: "ListProcessor", + 1245209: "Legent Corporation", + 1245210: "hassle", + 1245211: "Amiga Envoy Network Inquiry Proto", + 1245212: "NEC Corporation", + 1245213: "TIA EIA IS-99 modem client", + 1245214: "TIA EIA IS-99 modem server", + 1245215: "HP Performance data collector", + 1245216: "HP Performance data managed node", + 1245217: "HP Performance data alarm manager", + 1245218: "A Remote Network Server System", + 1245219: "IBM Application", + 1245220: "ASA Message Router Object Def.", + 1245221: "Appletalk Update-Based Routing Pro.", + 1245222: "Unidata LDM", + 1245223: "Lightweight Directory Access Protocol", + 1245224: "uis", + 1245225: "SynOptics SNMP Relay Port", + 1245226: "SynOptics Port Broker Port", + 1245228: "Meta5", + 1245229: "EMBL Nucleic Data Transfer", + 1245230: "NETscout Control Protocol", + 1245231: "Novell Netware over IP", + 1245232: "Multi Protocol Trans. Net.", + 1245233: "kryptolan", + 1245234: "ISO Transport Class 2 Non-Control over TCP", + 1245235: "Workstation Solutions", + 1245236: "Uninterruptible Power Supply", + 1245237: "Genie Protocol", + 1245238: "decap", + 1245239: "nced", + 1245240: "ncld", + 1245241: "Interactive Mail Support Protocol", + 1245242: "timbuktu", + 1245243: "Prospero Resource Manager Sys. Man.", + 1245244: "Prospero Resource Manager Node Man.", + 1245245: "DECLadebug Remote Debug Protocol", + 1245246: "Remote MT Protocol", + 1245247: "Trap Convention Port", + 1245248: "smsp", + 1245249: "infoseek", + 1245250: "bnet", + 1245251: "silverplatter", + 1245252: "onmux", + 1245253: "hyper-g", + 1245254: "ariel1", + 1245255: "smpte", + 1245256: "ariel2", + 1245257: "ariel3", + 1245258: "IBM Operations Planning and Control Start", + 1245259: "IBM Operations Planning and Control Track", + 1245260: "icad-el", + 1245261: "smartsdp", + 1245262: "Server Location", + 1245263: "ocs_cmu", + 1245264: "ocs_amu", + 1245265: "utmpsd", + 1245266: "utmpcd", + 1245267: "iasd", + 1245268: "Usenet Network News Transfer", + 1245269: "mobileip-agent", + 1245270: "mobilip-mn", + 1245271: "dna-cml", + 1245272: "comscm", + 1245273: "dsfgw", + 1245274: "dasp", + 1245275: "sgcp", + 1245276: "decvms-sysmgt", + 1245277: "cvc_hostd", + 1245278: "HTTP Protocol over TLS SSL", + 1245279: "Simple Network Paging Protocol", + 1245280: "Win2k+ Server Message Block", + 1245281: "ddm-rdb", + 1245282: "ddm-dfm", + 1245283: "DDM-SSL", + 1245284: "AS Server Mapper", + 1245285: "tserver", + 1245286: "Cray Network Semaphore server", + 1245287: "Cray SFS config server", + 1245288: "creativeserver", + 1245289: "contentserver", + 1245290: "creativepartnr", + 1245291: "macon-tcp", + 1245292: "scohelp", + 1245294: "ampr-rcmd", + 1245295: "skronk", + 1245296: "datasurfsrv", + 1245297: "datasurfsrvsec", + 1245298: "Alpes", + 1245299: "kpasswd", + 1245300: "SMTP Protocol over TLS SSL (was SSMTP)", + 1245301: "digital-vrc", + 1245302: "mylex-mapd", + 1245303: "Photuris Key Management", + 1245304: "Radio Control Protocol", + 1245305: "scx-proxy", + 1245306: "mondex", + 1245307: "ljk-login", + 1245308: "hybrid-pop", + 1245309: "tn-tl-w1", + 1245310: "Tcpnethaspsrv Protocol", + 1245311: "tn-tl-fd1", + 1245312: "ss7ns", + 1245313: "spsc", + 1245314: "iafserver", + 1245315: "WCCP", + 1245316: "loadsrv", + 1245317: "serialnumberd", + 1245318: "dvs", + 1245319: "bgs-nsi", + 1245320: "ulpnet", + 1245321: "Integra Software Management Environment", + 1245322: "Air Soft Power Burst", + 1245324: "sstats", + 1245325: "saft Simple Asynchronous File Transfer", + 1245326: "gss-http", + 1245327: "nest-protocol", + 1245328: "micom-pfs", + 1245329: "go-login", + 1245330: "Transport Independent Convergence for FNA", + 1245331: "pov-ray", + 1245332: "intecourier", + 1245333: "pim-rp-disc", + 1245334: "dantz", + 1245335: "siam", + 1245336: "ISO ILL Protocol", + 1245337: "VPN Key Exchange", + 1245338: "Simple Transportation Management Framework (STMF)", + 1245339: "asa-appl-proto", + 1245340: "intrinsa", + 1245341: "Citadel", + 1245342: "mailbox-lm", + 1245343: "ohimsrv", + 1245344: "crs", + 1245345: "xvttp", + 1245346: "snare", + 1245347: "FirstClass Protocol", + 1245348: "passgo", + 1245349: "BSD rexecd(8)", + 1245350: "BSD rlogind(8)", + 1245351: "BSD rshd(8)", + 1245352: "spooler", + 1245353: "videotex", + 1245354: "like tenex link but across", + 1245355: "ntalk", + 1245356: "unixtime", + 1245357: "Routing Information Protocol (RIP)", + 1245358: "ripng", + 1245359: "ulp", + 1245360: "ibm-db2", + 1245361: "NetWare Core Protocol (NCP)", + 1245362: "Timeserver", + 1245363: "newdate", + 1245364: "Stock IXChange", + 1245365: "Customer IXChange", + 1245366: "irc-serv", + 1245370: "readnews", + 1245371: "netwall for emergency broadcasts", + 1245372: "MegaMedia Admin", + 1245373: "iiop", + 1245374: "opalis-rdv", + 1245375: "Networked Media Streaming Protocol", + 1245376: "gdomap", + 1245377: "Apertus Technologies Load Determination", + 1245378: "uucpd", + 1245379: "uucp-rlogin", + 1245380: "Commerce", + 1245381: "klogin", + 1245382: "krcmd", + 1245383: "Kerberos encrypted remote shell", + 1245384: "DHCPv6 Client", + 1245385: "DHCPv6 Server", + 1245386: "AFP over TCP", + 1245387: "idfp", + 1245388: "new-who", + 1245389: "cybercash", + 1245390: "deviceshare", + 1245391: "pirp", + 1245392: "Real Time Stream Control Protocol", + 1245393: "dsf", + 1245394: "Remote File System (RFS)", + 1245395: "openvms-sysipc", + 1245396: "sdnskmp", + 1245397: "teedtap", + 1245398: "rmonitord", + 1245399: "monitor", + 1245400: "chcmd", + 1245402: "snews", + 1245403: "plan 9 file service", + 1245404: "whoami", + 1245405: "streettalk", + 1245406: "banyan-rpc", + 1245407: "Microsoft shuttle", + 1245408: "Microsoft rome", + 1245409: "demon", + 1245410: "udemon", + 1245411: "sonar", + 1245412: "banyan-vip", + 1245413: "FTP Software Agent System", + 1245414: "vemmi", + 1245415: "ipcd", + 1245416: "vnas", + 1245417: "ipdd", + 1245418: "decbsrv", + 1245419: "sntp-heartbeat", + 1245420: "Bundle Discovery Protocol", + 1245421: "scc-security", + 1245422: "Philips Video-Conferencing", + 1245423: "keyserver", + 1245424: "IMAP4+SSL", + 1245425: "password-chg", + 1245426: "submission", + 1245427: "cal", + 1245428: "eyelink", + 1245429: "tns-cml", + 1245430: "FileMaker Pro", + 1245431: "eudora-set", + 1245432: "HTTP RPC Ep Map", + 1245433: "tpip", + 1245434: "cab-protocol", + 1245435: "smsd", + 1245436: "PTC Name Service", + 1245437: "SCO Web Server Manager 3", + 1245438: "Aeolon Core Protocol", + 1245439: "Sun IPC server", + 1310721: "nqs", + 1310722: "Sender-Initiated Unsolicited File Transfer", + 1310723: "npmp-trap", + 1310724: "npmp-local", + 1310725: "npmp-gui", + 1310726: "HMMP Indication", + 1310727: "HMMP Operation", + 1310728: "SSLshell", + 1310729: "Internet Configuration Manager", + 1310730: "SCO System Administration Server", + 1310731: "SCO Desktop Administration Server", + 1310732: "DEI-ICDA", + 1310733: "Digital EVM", + 1310734: "SCO WebServer Manager", + 1310735: "ESCP", + 1310736: "Collaborator", + 1310737: "Aux Bus Shunt", + 1310738: "Crypto Admin", + 1310739: "DEC DLM", + 1310740: "ASIA", + 1310741: "PassGo Tivoli", + 1310742: "QMQP (qmail)", + 1310743: "3Com AMP3", + 1310744: "RDA", + 1310745: "IPP (Internet Printing Protocol)", + 1310746: "bmpp", + 1310747: "Service Status update (Sterling Software)", + 1310748: "ginad", + 1310749: "RLZ DBase", + 1310750: "LDAP Protocol over TLS SSL (was SLDAP)", + 1310751: "lanserver", + 1310752: "mcns-sec", + 1310753: "Multicast Source Discovery Protocol (MSDP)", + 1310754: "entrust-sps", + 1310755: "repcmd", + 1310756: "ESRO-EMSDP V1.3", + 1310757: "SANity", + 1310758: "dwr", + 1310759: "PSSC", + 1310760: "Label Distribution Protocol (LDP)", + 1310761: "DHCP Failover", + 1310762: "Registry Registrar Protocol (RRP)", + 1310763: "Aminet", + 1310764: "OBEX", + 1310765: "IEEE MMS", + 1310766: "HELLO_PORT", + 1310767: "AODV", + 1310768: "TINC", + 1310769: "SPMP", + 1310770: "RMC", + 1310771: "TenFold", + 1310772: "URL Rendezvous", + 1310773: "MacOS Server Admin", + 1310774: "HAP", + 1310775: "PFTP", + 1310776: "PureNoise", + 1310777: "Secure Aux Bus", + 1310778: "Sun DR", + 1310779: "doom Id Software", + 1310780: "campaign contribution disclosures - SDR Technologies", + 1310781: "MeComm", + 1310782: "MeRegister", + 1310783: "VACDSM-SWS", + 1310784: "VACDSM-APP", + 1310785: "VPPS-QUA", + 1310786: "CIMPLEX", + 1310787: "ACAP", + 1310788: "DCTP", + 1310789: "VPPS Via", + 1310790: "Virtual Presence Protocol", + 1310791: "GNU Gereration Foundation NCP", + 1310792: "MRM", + 1310793: "entrust-aaas", + 1310794: "entrust-aams", + 1310795: "XFR", + 1310796: "CORBA IIOP", + 1310797: "CORBA IIOP SSL", + 1310798: "MDC Port Mapper", + 1310799: "Hardware Control Protocol Wismar", + 1310800: "asipregistry", + 1310801: "REALM-RUSD", + 1310802: "NMAP", + 1310803: "VATP", + 1310804: "MS Exchange Routing", + 1310805: "Hyperwave-ISP", + 1310806: "connendp", + 1310807: "Linux-HA (High-Availability Linux)", + 1310808: "IEEE-MMS-SSL", + 1310809: "RUSHD", + 1310810: "UUIDGEN", + 1310811: "OLSR", + 1310812: "Access Network", + 1310813: "errlog copy server daemon", + 1310814: "AgentX", + 1310815: "Secure Internet Live Conferencing (SILC)", + 1310816: "Borland DSJ", + 1310817: "Entrust Key Management Service Handler", + 1310818: "Entrust Administration Service Handler", + 1310819: "Cisco TDP", + 1310820: "IBM NetView DM 6000 Server Client", + 1310821: "IBM NetView DM 6000 send tcp", + 1310822: "IBM NetView DM 6000 receive tcp", + 1310823: "netGW", + 1310824: "Network based Rev. Cont. Sys.", + 1310825: "Flexible License Manager", + 1310826: "Fujitsu Device Control", + 1310827: "Russell Info Sci Calendar Manager", + 1310828: "Kerberos 5 admin changepw", + 1310830: "rfile", + 1310832: "pump", + 1310833: "qrh", + 1310834: "rrh", + 1310835: "kerberos v5 server propagation", + 1310836: "nlogin", + 1310837: "con", + 1310839: "ns", + 1310840: "kpwd Kerberos (v4) passwd", + 1310841: "quotad", + 1310842: "cycleserv", + 1310843: "omserv", + 1310844: "webster", + 1310845: "phone", + 1310846: "vid", + 1310847: "cadlock", + 1310848: "rtip", + 1310849: "cycleserv2", + 1310850: "submit", + 1310851: "rpasswd", + 1310852: "entomb", + 1310853: "wpages", + 1310854: "Hummingbird Exceed jconfig", + 1310855: "wpgs", + 1310856: "concert", + 1310857: "QSC", + 1310858: "controlit", + 1310859: "mdbs_daemon", + 1310860: "Device", + 1310861: "FCP", + 1310862: "itm-mcell-s", + 1310863: "PKIX-3 CA RA", + 1310864: "DHCP Failover 2", + 1310865: "SUP server", + 1310866: "rsync", + 1310867: "ICL coNETion locate server", + 1310868: "ICL coNETion server info", + 1310869: "AccessBuilder", + 1310870: "OMG Initial Refs", + 1310871: "Samba SWAT Tool", + 1310872: "IDEAFARM-CHAT", + 1310873: "IDEAFARM-CATCH", + 1310874: "xact-backup", + 1310875: "SecureNet Pro sensor", + 1310878: "Netnews Administration System", + 1310879: "Telnet Protocol over TLS SSL", + 1310880: "IMAP4 Protocol over TLS SSL", + 1310881: "ICP Protocol over TLS SSL", + 1310882: "POP3 Protocol over TLS SSL", + 1310883: "bhoetty", + 1310884: "Cray Unified Resource Manager", + 1310887: "Microsoft Authentication via SSL", + 1310888: "Google(SSL)", + 1310889: "Yahoo Authentication via SSL", + 1310890: "AOL Authentication via SSL", + 1310891: "FIX", + 1310892: "STUN", + 1310893: "Dynamic Host Configuration Protocol (DHCP)", + 1310894: "Megaco", + 1310895: "Rstatd", + 1310896: "RSVP", + 1310897: "SOAP", + 1310898: "Ess Apple Authentication via SSL", + 1310899: "TFTP", + 1310900: "Daytime", + 1310902: "MicrosoftOnline Authentication via SSL", + 1310903: "Microsoft WINS", + 1310904: "Remote Procedure Call (RPC)", + 1310905: "SSL/TLS", + 1310906: "Google APIs(SSL)", + 1310907: "Sina Authentication via SSL", + 1310908: "Google App Engine(SSL)", + 1310909: "Google User Content(SSL)", + 1310910: "Blackberry Authentication via SSL", + 1310912: "Adobe Authentication via SSL", + 1310914: "Lets Encrypt", + 1507329: "QQ Private Protocol", + 1507330: "Thunder Private Protocol", + 1507333: "Jabber Private Protocol", + 1572865: "Classmates", + 1572866: "Yik Yak", + 1572867: "Facebook", + 1572868: "Flickr", + 1572870: "Friendfeed", + 1572871: "Hi5", + 1572872: "LinkedIn", + 1572873: "Livejournal", + 1572874: "Twitter", + 1572875: "Plurk", + 1572876: "MySpace", + 1572880: "Khan Academy", + 1572881: "Pinterest", + 1572882: "Tumblr", + 1572883: "MeetMe", + 1572884: "VKontakte", + 1572885: "Odnoklassniki", + 1572886: "Niwota", + 1572887: "Tagged", + 1572889: "PerfSpot", + 1572890: "Me2day", + 1572891: "Mekusharim", + 1572892: "Draugiem", + 1572893: "Badoo", + 1572894: "Meetup", + 1572895: "Foursquare", + 1572896: "Ning", + 1572897: "i-Part/iPair", + 1572898: "Wretch", + 1572899: "Dudu", + 1572900: "Mig33", + 1572901: "Hatena", + 1572902: "eHarmony", + 1572903: "Fotolog ", + 1572905: "Tencent QQ", + 1572906: "Pixnet", + 1572907: "Nk.Pl", + 1572909: "Twoo", + 1572910: "Plaxo", + 1572911: "Cyworld", + 1572912: "Jivesoftware", + 1572913: "WordPress", + 1572914: "FMyLife", + 1572915: "Dcinside", + 1572916: "Class Chinaren", + 1572917: "Bai Sohu", + 1572918: "Yammer", + 1572919: "Douban", + 1572920: "Gamer", + 1572921: "Xuite", + 1572922: "ChatMe", + 1572923: "Clien.net", + 1572927: "AdultFriendFinder", + 1572928: "Fling.com", + 1572929: "Delicious", + 1572930: "Mei.fm", + 1572931: "Streetlife", + 1572967: "Daum-blog", + 1572968: "Naver-blog", + 1572970: "Panoramio", + 1572974: "Blogger", + 1572975: "FC2", + 1572976: "Yahoo Blog", + 1572977: "Friendster", + 1572978: "Ameba", + 1572980: "Bebo social network", + 1572981: "Kaixin", + 1572983: "Orkut", + 1572985: "Aol-Answers", + 1572987: "CoolTalk social network", + 1572988: "RenRen.com", + 1572989: "TweetDeck", + 1572990: "Hootsuite", + 1572998: "Xing", + 1572999: "Lokalisten", + 1573000: "meinVZ/studiVZ", + 1573004: "Viadeo", + 1573005: "Tuenti", + 1573006: "Hyves", + 1573007: "Mixi.jp", + 1573008: "Yahoo-mbga.jp", + 1573009: "GREE", + 1573010: "Netlog", + 1573011: "2ch", + 1573013: "Reddit", + 1573014: "LoveTheseCurves", + 1573015: "Weibo", + 1573016: "Google+", + 1573017: "Skyrock", + 1573018: "51.com", + 1573019: "Jackd", + 1573020: "Touch", + 1573021: "Skout", + 1573022: "Instagram", + 1573023: "Jiayuan", + 1573024: "Zoosk", + 1573025: "DatingDNA", + 1573026: "500px", + 1573028: "iAround", + 1573029: "pairs", + 1573030: "Path", + 1573031: "WeHeartIt", + 1573032: "Fancy", + 1573033: "Vine", + 1573034: "SnappyTV", + 1573035: "Miliao", + 1573036: "After School", + 1573074: "Weico", + 16777215: "Unknown_Other", +} diff --git a/core/unifi/v4/examples/convert.sh b/core/unifi/v4/examples/convert.sh new file mode 100755 index 00000000..de5b2975 --- /dev/null +++ b/core/unifi/v4/examples/convert.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# Usage: +# ./convert.sh [prefix] +# should contain a go struct, like uap_type.go +# It converts the go struct to an influx thing, like you see in uap_influx.go. +# [prefix] is optional. I used it to do all the stat_ uap metrics. +# Very crude, just helps skip a lot of copy/paste. +# +path=$1 +pre=$2 + +# Reads in the file one line at a time. +while IFS='' read -r line; do + # Split each piece of the file out. + name=$(echo "${line}" | awk '{print $1}') + type=$(echo "${line}" | awk '{print $2}') + json=$(echo "${line}" | awk '{print $3}') + json=$(echo "${json}" | cut -d\" -f2) + + # Don't print junk lines. (it still prints some junk lines) + if [ "$json" != "" ]; then + # Add a .Val suffix if this is a FlexInt or FlexBool. + [[ "$type" = Flex* ]] && suf=.Val + echo "\"${pre}${json}\": u.Stat.${name}${suf}," + fi +done < ${path} diff --git a/core/unifi/v4/examples/ids.json b/core/unifi/v4/examples/ids.json new file mode 100644 index 00000000..5dbb0fe2 --- /dev/null +++ b/core/unifi/v4/examples/ids.json @@ -0,0 +1,66 @@ +{ + "_id": "5d2416c78f0385ccf1c6df44", + "archived": false, + "timestamp": 1562646211, + "flow_id": 1591464006222389, + "in_iface": "eth1", + "event_type": "alert", + "src_ip": "196.196.244.84", + "src_mac": "f0:9f:c2:c4:bb:f1", + "src_port": 51413, + "dest_ip": "192.168.3.2", + "dst_mac": "40:a8:f0:68:c3:58", + "dest_port": 36881, + "proto": "UDP", + "app_proto": "failed", + "host": "f0:22:22:22:22:22", + "usgip": "11.22.33.44", + "unique_alertid": "1341902566-2019-07-08T21:23:31.229941-0700", + "srcipCountry": "SE", + "dstipCountry": false, + "usgipCountry": "US", + "srcipGeo": { + "continent_code": "EU", + "country_code": "SE", + "country_code3": "SWE", + "country_name": "Sweden", + "region": "26", + "city": "Stockholm", + "postal_code": "168 65", + "latitude": 59.349998474121094, + "longitude": 17.91670036315918, + "dma_code": 0, + "area_code": 0 + }, + "dstipGeo": false, + "usgipGeo": { + "continent_code": "NA", + "country_code": "US", + "country_code3": "USA", + "country_name": "United States", + "region": "CA", + "city": "Other", + "postal_code": "99999", + "latitude": 99.139400482177734, + "longitude": -99.39669799804688, + "dma_code": 862, + "area_code": 999 + }, + "srcipASN": "AS42607 Internet Carrier Limited", + "dstipASN": "", + "usgipASN": "AS7922 Comcast Cable Communications, LLC", + "catname": "spamhaus", + "inner_alert_action": "allowed", + "inner_alert_gid": 1, + "inner_alert_signature_id": 2400022, + "inner_alert_rev": 2673, + "inner_alert_signature": "ET DROP Spamhaus DROP Listed Traffic Inbound group 23", + "inner_alert_category": "Misc Attack", + "inner_alert_severity": 2, + "key": "EVT_IPS_IpsAlert", + "subsystem": "www", + "site_id": "574e86994566ffb914a2683c", + "time": 1562646211000, + "datetime": "2019-07-09T04:23:31Z", + "msg": "IPS Alert 2: Misc Attack. Signature ET DROP Spamhaus DROP Listed Traffic Inbound group 23. From: 196.196.244.84:51413, to: 192.168.3.2:36881, protocol: UDP" +}, diff --git a/core/unifi/v4/examples/uap.json b/core/unifi/v4/examples/uap.json new file mode 100644 index 00000000..dbc6c4ae --- /dev/null +++ b/core/unifi/v4/examples/uap.json @@ -0,0 +1,738 @@ +{ + "_id": "574e8bde4566ffb914a26853", + "adopted": true, + "antenna_table": [ + { + "default": true, + "id": 4, + "name": "Combined", + "wifi0_gain": 3, + "wifi1_gain": 3 + } + ], + "bandsteering_mode": "prefer_5g", + "board_rev": 18, + "cfgversion": "08cd8d6b71ebe82f", + "config_network": { + "type": "dhcp", + "ip": "10.1.10.67" + }, + "countrycode_table": [ + 840, + 124, + 630 + ], + "ethernet_table": [ + { + "mac": "80:22:a8:22:ae:22", + "num_port": 2, + "name": "eth0" + } + ], + "fw_caps": 4128063, + "has_eth1": false, + "has_speaker": false, + "inform_ip": "192.168.3.1", + "inform_url": "http://unifi:8080/inform", + "ip": "192.168.1.8", + "led_override": "default", + "mac": "80:22:22:22:22:22", + "mesh_sta_vap_enabled": true, + "model": "U7PG2", + "name": "wap-lower", + "outdoor_mode_override": "default", + "port_table": [ + { + "port_idx": 1, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "attr_no_edit": true, + "media": "GE", + "name": "Main", + "poe_caps": 0, + "port_poe": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "port_delta": { + "time_delta": 21 + }, + "enable": true, + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 2, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "media": "GE", + "name": "Secondary", + "poe_caps": 0, + "port_poe": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "port_delta": { + "time_delta": 21 + }, + "enable": true, + "masked": false, + "aggregated_by": false + } + ], + "radio_table": [ + { + "radio": "ng", + "name": "wifi0", + "channel": "auto", + "ht": "40", + "tx_power_mode": "auto", + "tx_power": "0", + "max_txpower": 22, + "min_txpower": 6, + "nss": 3, + "min_rssi_enabled": false, + "builtin_antenna": true, + "builtin_ant_gain": 3, + "current_antenna_gain": 0, + "radio_caps": 16420, + "wlangroup_id": "574e869d4566ffb914a26843" + }, + { + "radio": "na", + "name": "wifi1", + "channel": "auto", + "ht": "80", + "tx_power_mode": "high", + "tx_power": "0", + "max_txpower": 22, + "min_txpower": 6, + "nss": 3, + "min_rssi_enabled": false, + "is_11ac": true, + "has_dfs": true, + "has_fccdfs": true, + "builtin_antenna": true, + "builtin_ant_gain": 3, + "current_antenna_gain": 0, + "radio_caps": 50479140, + "wlangroup_id": "574e869d4566ffb914a26843" + } + ], + "scan_radio_table": [], + "serial": "xxxyyyzzz", + "site_id": "574e86994566ffb914a2683c", + "type": "uap", + "version": "4.0.42.10433", + "vwire_table": [], + "wifi_caps": 49141, + "wlangroup_id_na": "574e869d4566ffb914a26843", + "wlangroup_id_ng": "574e869d4566ffb914a26843", + "required_version": "3.4.1", + "hw_caps": 0, + "unsupported": false, + "unsupported_reason": 0, + "sys_error_caps": 0, + "has_fan": false, + "has_temperature": false, + "device_id": "574e8bde4566ffb914a26853", + "state": 1, + "last_seen": 1562225381, + "upgradable": false, + "adoptable_when_upgraded": false, + "rollupgrade": false, + "known_cfgversion": "08cd8d6b71ebe82f", + "uptime": 3105845, + "_uptime": 3105845, + "locating": false, + "connect_request_ip": "192.168.1.8", + "connect_request_port": "43913", + "sys_stats": { + "loadavg_1": "0.04", + "loadavg_15": "0.14", + "loadavg_5": "0.10", + "mem_buffer": 0, + "mem_total": 128622592, + "mem_used": 67178496 + }, + "system-stats": { + "cpu": "24.7", + "mem": "52.2", + "uptime": "3105845" + }, + "ssh_session_table": [], + "scanning": false, + "spectrum_scanning": false, + "guest_token": "4D630D2A1AF84771FCBB8EEB4C47E030", + "meshv3_peer_mac": "", + "satisfaction": 95, + "isolated": false, + "radio_table_stats": [ + { + "name": "wifi0", + "channel": 6, + "radio": "ng", + "ast_txto": null, + "ast_cst": null, + "ast_be_xmit": 398, + "cu_total": 20, + "cu_self_rx": 14, + "cu_self_tx": 4, + "gain": 3, + "state": "RUN", + "extchannel": 1, + "tx_power": 22, + "tx_packets": 183, + "tx_retries": 108, + "num_sta": 2, + "guest-num_sta": 0, + "user-num_sta": 2 + }, + { + "name": "wifi1", + "channel": 36, + "radio": "na", + "ast_txto": null, + "ast_cst": null, + "ast_be_xmit": 398, + "cu_total": 12, + "cu_self_rx": 10, + "cu_self_tx": 2, + "gain": 3, + "state": "RUN", + "extchannel": 1, + "tx_power": 22, + "tx_packets": 22466, + "tx_retries": 858, + "num_sta": 4, + "guest-num_sta": 0, + "user-num_sta": 4 + } + ], + "uplink": { + "full_duplex": true, + "ip": "0.0.0.0", + "mac": "80:22:22:22:22:22", + "max_vlan": 96, + "name": "eth0", + "netmask": "0.0.0.0", + "num_port": 2, + "rx_bytes": 3752803309, + "rx_dropped": 102338, + "rx_errors": 0, + "rx_multicast": 0, + "rx_packets": 245302304, + "speed": 1000, + "tx_bytes": 1604707458, + "tx_dropped": 341, + "tx_errors": 0, + "tx_packets": 194278357, + "up": true, + "max_speed": 1000, + "type": "wire", + "tx_bytes-r": 9693222, + "rx_bytes-r": 92418, + "uplink_mac": "f0:22:22:22:22:22", + "uplink_remote_port": 15 + }, + "vap_table": [ + { + "avg_client_signal": 0, + "bssid": "82:22:22:22:22:22", + "ccq": 0, + "channel": 36, + "essid": "Extra Free", + "extchannel": 1, + "id": "574e96834566ffb914a26875", + "mac_filter_rejections": 0, + "name": "ath3", + "num_satisfaction_sta": 0, + "num_sta": 0, + "radio": "na", + "radio_name": "wifi1", + "rx_bytes": 61253, + "rx_crypts": 0, + "rx_dropped": 0, + "rx_errors": 0, + "rx_frags": 0, + "rx_nwids": 47658, + "rx_packets": 576, + "rx_tcp_stats": { + "goodbytes": 0, + "lat_avg": 0, + "lat_max": 0, + "lat_min": 4294967295, + "stalls": 0 + }, + "satisfaction": -1, + "satisfaction_now": -1, + "state": "RUN", + "tx_bytes": 922841, + "tx_combined_retries": 0, + "tx_data_mpdu_bytes": 0, + "tx_dropped": 18128, + "tx_errors": 7, + "tx_packets": 736, + "tx_power": 22, + "tx_retries": 0, + "tx_rts_retries": 0, + "tx_success": 0, + "tx_tcp_stats": { + "goodbytes": 0, + "lat_avg": 0, + "lat_max": 0, + "lat_min": 4294967295, + "stalls": 0 + }, + "tx_total": 0, + "up": true, + "usage": "guest", + "wifi_tx_attempts": 0, + "wifi_tx_dropped": 0, + "wifi_tx_latency_mov": { + "avg": 0, + "max": 0, + "min": 4294967295, + "total": 0, + "total_count": 0 + }, + "t": "vap", + "wlanconf_id": "574e96834566ffb914a26875", + "is_guest": true, + "is_wep": false, + "ap_mac": "80:22:a8:22:22:22", + "map_id": null, + "site_id": "574e86994566ffb914a2683c" + }, + { + "avg_client_signal": -65, + "bssid": "80:22:a8:22:22:22", + "ccq": 333, + "channel": 36, + "essid": "Extra Fast", + "extchannel": 1, + "id": "574e96614566ffb914a26874", + "mac_filter_rejections": 0, + "name": "ath2", + "num_satisfaction_sta": 4, + "num_sta": 4, + "radio": "na", + "radio_name": "wifi1", + "rx_bytes": 3358763522, + "rx_crypts": 161639, + "rx_dropped": 161639, + "rx_errors": 161639, + "rx_frags": 0, + "rx_nwids": 37605, + "rx_packets": 99128603, + "rx_tcp_stats": { + "goodbytes": 16243150352, + "lat_avg": 7, + "lat_max": 100, + "lat_min": 10, + "stalls": 0 + }, + "satisfaction": 96, + "satisfaction_now": 97, + "state": "RUN", + "tx_bytes": 834859686, + "tx_combined_retries": 9067488, + "tx_data_mpdu_bytes": 48117828355, + "tx_dropped": 109, + "tx_errors": 4076905, + "tx_packets": 111980588, + "tx_power": 22, + "tx_retries": 9067488, + "tx_rts_retries": 0, + "tx_success": 62855481, + "tx_tcp_stats": { + "goodbytes": 2154118473, + "lat_avg": 18, + "lat_max": 120, + "lat_min": 10, + "stalls": 0 + }, + "tx_total": 62855552, + "up": true, + "usage": "user", + "wifi_tx_attempts": 71923040, + "wifi_tx_dropped": 71, + "wifi_tx_latency_mov": { + "avg": 565, + "max": 31757, + "min": 98, + "total": 10183098, + "total_count": 18019 + }, + "t": "vap", + "wlanconf_id": "574e96614566ffb914a26874", + "is_guest": false, + "is_wep": false, + "ap_mac": "80:22:22:22:22:22", + "map_id": null, + "site_id": "574e86994566ffb914a2683c" + }, + { + "avg_client_signal": 0, + "bssid": "82:22:a8:22:22:22", + "ccq": 0, + "channel": 6, + "essid": "Extra Free", + "extchannel": 1, + "id": "574e96834566ffb914a26875", + "mac_filter_rejections": 0, + "name": "ath1", + "num_satisfaction_sta": 0, + "num_sta": 0, + "radio": "ng", + "radio_name": "wifi0", + "reasons_bar_chart": { + "phy_rate": 0, + "signal": 0, + "sleepy_client": 0, + "sta_arp_timeout": 0, + "sta_dns_timeout": 0, + "sta_ip_timeout": 0, + "stream_eff": 0, + "tcp_latency": 0, + "tcp_packet_loss": 0, + "wifi_latency": 0, + "wifi_retries": 0 + }, + "reasons_bar_chart_now": { + "phy_rate": 0, + "signal": 0, + "sleepy_client": 0, + "sta_arp_timeout": 0, + "sta_dns_timeout": 0, + "sta_ip_timeout": 0, + "stream_eff": 0, + "tcp_latency": 0, + "tcp_packet_loss": 0, + "wifi_latency": 0, + "wifi_retries": 0 + }, + "rx_bytes": 0, + "rx_crypts": 0, + "rx_dropped": 0, + "rx_errors": 0, + "rx_frags": 0, + "rx_nwids": 120385, + "rx_packets": 0, + "rx_tcp_stats": { + "goodbytes": 0, + "lat_avg": 0, + "lat_max": 0, + "lat_min": 4294967295, + "stalls": 0 + }, + "satisfaction": -1, + "satisfaction_now": -1, + "state": "RUN", + "tx_bytes": 0, + "tx_combined_retries": 0, + "tx_data_mpdu_bytes": 0, + "tx_dropped": 20262, + "tx_errors": 0, + "tx_packets": 0, + "tx_power": 22, + "tx_retries": 0, + "tx_rts_retries": 0, + "tx_success": 0, + "tx_tcp_stats": { + "goodbytes": 0, + "lat_avg": 0, + "lat_max": 0, + "lat_min": 4294967295, + "stalls": 0 + }, + "tx_total": 0, + "up": true, + "usage": "guest", + "wifi_tx_attempts": 0, + "wifi_tx_dropped": 0, + "wifi_tx_latency_mov": { + "avg": 0, + "max": 0, + "min": 4294967295, + "total": 0, + "total_count": 0 + }, + "t": "vap", + "wlanconf_id": "574e96834566ffb914a26875", + "is_guest": true, + "is_wep": false, + "ap_mac": "80:22:a8:22:22:22", + "map_id": null, + "site_id": "574e86994566ffb914a2683c" + }, + { + "avg_client_signal": -68, + "bssid": "80:22:22:22:22:22", + "ccq": 966, + "channel": 6, + "essid": "Extra Fast", + "extchannel": 1, + "id": "574e96614566ffb914a26874", + "mac_filter_rejections": 0, + "name": "ath0", + "num_satisfaction_sta": 2, + "num_sta": 2, + "radio": "ng", + "radio_name": "wifi0", + "reasons_bar_chart": { + "phy_rate": 0, + "signal": 0, + "sleepy_client": 0, + "sta_arp_timeout": 0, + "sta_dns_timeout": 0, + "sta_ip_timeout": 0, + "stream_eff": 0, + "tcp_latency": 0, + "tcp_packet_loss": 0, + "wifi_latency": 0, + "wifi_retries": 1 + }, + "reasons_bar_chart_now": { + "phy_rate": 0, + "signal": 0, + "sleepy_client": 0, + "sta_arp_timeout": 0, + "sta_dns_timeout": 0, + "sta_ip_timeout": 0, + "stream_eff": 0, + "tcp_latency": 0, + "tcp_packet_loss": 0, + "wifi_latency": 0, + "wifi_retries": 1 + }, + "rx_bytes": 1017366419, + "rx_crypts": 11013, + "rx_dropped": 12764, + "rx_errors": 12764, + "rx_frags": 0, + "rx_nwids": 177145, + "rx_packets": 22542668, + "rx_tcp_stats": { + "goodbytes": 114220296, + "lat_avg": 5, + "lat_max": 10, + "lat_min": 10, + "stalls": 0 + }, + "satisfaction": 93, + "satisfaction_now": 94, + "state": "RUN", + "tx_bytes": 965488630, + "tx_combined_retries": 8202639, + "tx_data_mpdu_bytes": 1145631754, + "tx_dropped": 43, + "tx_errors": 0, + "tx_packets": 22623798, + "tx_power": 22, + "tx_retries": 7194267, + "tx_rts_retries": 1008372, + "tx_success": 9545999, + "tx_tcp_stats": { + "goodbytes": 182912739, + "lat_avg": 5, + "lat_max": 10, + "lat_min": 10, + "stalls": 0 + }, + "tx_total": 9547096, + "up": true, + "usage": "user", + "wifi_tx_attempts": 16740276, + "wifi_tx_dropped": 1095, + "wifi_tx_latency_mov": { + "avg": 673, + "max": 13612, + "min": 0, + "total": 263176, + "total_count": 391 + }, + "t": "vap", + "wlanconf_id": "574e96614566ffb914a26874", + "is_guest": false, + "is_wep": false, + "ap_mac": "80:22:22:22:22:22", + "map_id": null, + "site_id": "574e86994566ffb914a2683c" + } + ], + "downlink_table": [], + "vwire_vap_table": [], + "bytes-d": 204913232, + "tx_bytes-d": 1921569, + "rx_bytes-d": 202991663, + "bytes-r": 9757772, + "last_uplink": { + "uplink_mac": "f0:22:22:22:22:22", + "uplink_remote_port": 15 + }, + "stat": { + "site_id": "574e86994566ffb914a2683c", + "o": "ap", + "oid": "80:22:a8:22:22:22", + "ap": "80:22:a8:22:22:22", + "time": 1562207100000, + "datetime": "2019-07-04T02:25:00Z", + "guest-wifi0-rx_packets": 0, + "guest-wifi1-rx_packets": 0, + "user-wifi1-rx_packets": 31373230, + "user-wifi0-rx_packets": 169790, + "user-rx_packets": 31543020, + "guest-rx_packets": 0, + "wifi0-rx_packets": 169790, + "wifi1-rx_packets": 31373230, + "rx_packets": 31543020, + "guest-wifi0-rx_bytes": 0, + "guest-wifi1-rx_bytes": 0, + "user-wifi1-rx_bytes": 42049645434, + "user-wifi0-rx_bytes": 16755639, + "user-rx_bytes": 42066401073, + "guest-rx_bytes": 0, + "wifi0-rx_bytes": 16755639, + "wifi1-rx_bytes": 42049645434, + "rx_bytes": 42066401073, + "guest-wifi0-rx_errors": 0, + "guest-wifi1-rx_errors": 0, + "user-wifi1-rx_errors": 150651, + "user-wifi0-rx_errors": 0, + "user-rx_errors": 150651, + "guest-rx_errors": 0, + "wifi0-rx_errors": 0, + "wifi1-rx_errors": 150651, + "rx_errors": 150651, + "guest-wifi0-rx_dropped": 0, + "guest-wifi1-rx_dropped": 0, + "user-wifi1-rx_dropped": 150651, + "user-wifi0-rx_dropped": 0, + "user-rx_dropped": 150651, + "guest-rx_dropped": 0, + "wifi0-rx_dropped": 0, + "wifi1-rx_dropped": 150651, + "rx_dropped": 150651, + "guest-wifi0-rx_crypts": 0, + "guest-wifi1-rx_crypts": 0, + "user-wifi1-rx_crypts": 150651, + "user-wifi0-rx_crypts": 0, + "user-rx_crypts": 150651, + "guest-rx_crypts": 0, + "wifi0-rx_crypts": 0, + "wifi1-rx_crypts": 150651, + "rx_crypts": 150651, + "guest-wifi0-rx_frags": 0, + "guest-wifi1-rx_frags": 0, + "user-wifi1-rx_frags": 0, + "user-wifi0-rx_frags": 0, + "user-rx_frags": 0, + "guest-rx_frags": 0, + "wifi0-rx_frags": 0, + "wifi1-rx_frags": 0, + "rx_frags": 0, + "guest-wifi0-tx_packets": 0, + "guest-wifi1-tx_packets": 0, + "user-wifi1-tx_packets": 7125589, + "user-wifi0-tx_packets": 210389, + "user-tx_packets": 7335978, + "guest-tx_packets": 0, + "wifi0-tx_packets": 210389, + "wifi1-tx_packets": 7125589, + "tx_packets": 7335978, + "guest-wifi0-tx_bytes": 0, + "guest-wifi1-tx_bytes": 0, + "user-wifi1-tx_bytes": 3011293823, + "user-wifi0-tx_bytes": 25966558, + "user-tx_bytes": 3037260381, + "guest-tx_bytes": 0, + "wifi0-tx_bytes": 25966558, + "wifi1-tx_bytes": 3011293823, + "tx_bytes": 3037260381, + "guest-wifi0-tx_errors": 0, + "guest-wifi1-tx_errors": 0, + "user-wifi1-tx_errors": 102193, + "user-wifi0-tx_errors": 0, + "user-tx_errors": 102193, + "guest-tx_errors": 0, + "wifi0-tx_errors": 0, + "wifi1-tx_errors": 102193, + "tx_errors": 102193, + "guest-wifi0-tx_dropped": 296, + "guest-wifi1-tx_dropped": 296, + "user-wifi1-tx_dropped": 0, + "user-wifi0-tx_dropped": 0, + "user-tx_dropped": 0, + "guest-tx_dropped": 592, + "wifi0-tx_dropped": 296, + "wifi1-tx_dropped": 296, + "tx_dropped": 592, + "guest-wifi0-tx_retries": 0, + "guest-wifi1-tx_retries": 0, + "user-wifi1-tx_retries": 519734, + "user-wifi0-tx_retries": 90225, + "user-tx_retries": 609959, + "guest-tx_retries": 0, + "wifi0-tx_retries": 90225, + "wifi1-tx_retries": 519734, + "tx_retries": 609959, + "guest-wifi0-mac_filter_rejections": 0, + "guest-wifi1-mac_filter_rejections": 0, + "user-wifi1-mac_filter_rejections": 0, + "user-wifi0-mac_filter_rejections": 0, + "user-mac_filter_rejections": 0, + "guest-mac_filter_rejections": 0, + "wifi0-mac_filter_rejections": 0, + "wifi1-mac_filter_rejections": 0, + "mac_filter_rejections": 0, + "guest-wifi0-wifi_tx_attempts": 0, + "guest-wifi1-wifi_tx_attempts": 0, + "user-wifi1-wifi_tx_attempts": 4419026, + "user-wifi0-wifi_tx_attempts": 255999, + "user-wifi_tx_attempts": 4675025, + "guest-wifi_tx_attempts": 0, + "wifi0-wifi_tx_attempts": 255999, + "wifi1-wifi_tx_attempts": 4419026, + "wifi_tx_attempts": 4675025, + "guest-wifi0-wifi_tx_dropped": 0, + "guest-wifi1-wifi_tx_dropped": 0, + "user-wifi1-wifi_tx_dropped": 25, + "user-wifi0-wifi_tx_dropped": 2, + "user-wifi_tx_dropped": 27, + "guest-wifi_tx_dropped": 0, + "wifi0-wifi_tx_dropped": 2, + "wifi1-wifi_tx_dropped": 25, + "wifi_tx_dropped": 27, + "bytes": 45103661454, + "duration": 17988000, + "user-wifi1-ath2-574e96614566ffb914a26874-rx_packets": 31373230, + "user-wifi1-ath2-574e96614566ffb914a26874-rx_bytes": 42049645434, + "user-wifi1-ath2-574e96614566ffb914a26874-tx_packets": 7125589, + "user-wifi1-ath2-574e96614566ffb914a26874-tx_bytes": 3011293823, + "user-wifi1-ath2-574e96614566ffb914a26874-tx_errors": 102193, + "user-wifi1-ath2-574e96614566ffb914a26874-tx_retries": 519734, + "user-wifi1-ath2-574e96614566ffb914a26874-wifi_tx_attempts": 4419026, + "user-wifi0-ath0-574e96614566ffb914a26874-rx_packets": 169790, + "user-wifi0-ath0-574e96614566ffb914a26874-rx_bytes": 16755639, + "user-wifi0-ath0-574e96614566ffb914a26874-tx_packets": 210389, + "user-wifi0-ath0-574e96614566ffb914a26874-tx_bytes": 25966558, + "user-wifi0-ath0-574e96614566ffb914a26874-tx_retries": 90225, + "user-wifi0-ath0-574e96614566ffb914a26874-wifi_tx_attempts": 255999, + "guest-wifi1-ath3-574e96834566ffb914a26875-tx_dropped": 296, + "guest-wifi0-ath1-574e96834566ffb914a26875-tx_dropped": 296, + "user-wifi1-ath2-574e96614566ffb914a26874-rx_errors": 150651, + "user-wifi1-ath2-574e96614566ffb914a26874-rx_dropped": 150651, + "user-wifi1-ath2-574e96614566ffb914a26874-rx_crypts": 150651, + "user-wifi0-ath0-574e96614566ffb914a26874-wifi_tx_dropped": 2, + "user-wifi1-ath2-574e96614566ffb914a26874-wifi_tx_dropped": 25 + }, + "tx_bytes": 3037260381, + "rx_bytes": 42066401073, + "bytes": 45103661454, + "vwireEnabled": false, + "uplink_table": [], + "num_sta": 6, + "user-num_sta": 6, + "guest-num_sta": 0 +} diff --git a/core/unifi/v4/examples/ugw.json b/core/unifi/v4/examples/ugw.json new file mode 100644 index 00000000..117b14f7 --- /dev/null +++ b/core/unifi/v4/examples/ugw.json @@ -0,0 +1,371 @@ +{ + "_id": "59a35da745663e6cc82600f6", + "adopted": true, + "cfgversion": "bf9f0335063fe6ea", + "config_network": { + "type": "dhcp", + "ip": "192.168.2.0" + }, + "ethernet_table": [ + { + "mac": "22:22:00:22:22:00", + "num_port": 1, + "name": "eth0" + }, + { + "mac": "22:22:00:22:22:00", + "num_port": 1, + "name": "eth1" + }, + { + "mac": "22:22:00:22:22:00", + "num_port": 1, + "name": "eth2" + } + ], + "fw_caps": 184323, + "inform_ip": "192.168.3.1", + "inform_url": "http://security:8080/inform", + "ip": "3.1.33.7", + "led_override": "default", + "license_state": "registered", + "mac": "22:22:00:22:22:00", + "model": "UGW3", + "name": "gateway", + "outdoor_mode_override": "default", + "serial": "xxxyyyzzz", + "site_id": "574e86994566ffb914a2683c", + "type": "ugw", + "usg_caps": 786431, + "version": "4.4.41.5193700", + "required_version": "4.0.0", + "ethernet_overrides": [ + { + "ifname": "eth1", + "networkgroup": "LAN" + }, + { + "ifname": "eth0", + "networkgroup": "WAN" + } + ], + "hw_caps": 0, + "board_rev": 16, + "unsupported": false, + "unsupported_reason": 0, + "device_id": "59a35da745663e6cc82600f6", + "state": 1, + "last_seen": 1562311857, + "upgradable": false, + "adoptable_when_upgraded": false, + "rollupgrade": false, + "known_cfgversion": "bf9f0335063fe6ea", + "uptime": 3191626, + "_uptime": 3191626, + "locating": false, + "connect_request_ip": "192.168.2.1", + "connect_request_port": "35615", + "sys_stats": { + "loadavg_1": "0.01", + "loadavg_15": "0.12", + "loadavg_5": "0.06", + "mem_buffer": 62406656, + "mem_total": 507412480, + "mem_used": 397500416 + }, + "system-stats": { + "cpu": "14", + "mem": "30", + "uptime": "3191066" + }, + "guest_token": "83342830AE9C0641DC39DD2759C122A1", + "speedtest-status": { + "latency": 14, + "rundate": 1562310531, + "runtime": 172, + "status_download": 2, + "status_ping": 2, + "status_summary": 2, + "status_upload": 2, + "xput_download": 157.36776733398438, + "xput_upload": 37.90521240234375 + }, + "speedtest-status-saved": true, + "wan1": { + "tx_bytes-r": 2852355, + "rx_bytes-r": 1224743, + "bytes-r": 4077098, + "max_speed": 1000, + "type": "wire", + "name": "wan", + "ifname": "eth0", + "ip": "3.1.33.7", + "netmask": "255.255.254.0", + "mac": "22:22:00:22:22:00", + "up": true, + "speed": 1000, + "full_duplex": true, + "rx_bytes": 2648236513108, + "rx_dropped": 34030, + "rx_errors": 0, + "rx_packets": 3068347172, + "tx_bytes": 3009601283006, + "tx_dropped": 0, + "tx_errors": 0, + "tx_packets": 2859713220, + "rx_multicast": 939111, + "enable": true, + "dns": [ + "1.1.1.1", + "8.8.8.8" + ], + "gateway": "3.1.33.8" + }, + "port_table": [ + { + "name": "wan", + "ifname": "eth0", + "ip": "3.1.33.7", + "netmask": "255.255.254.0", + "mac": "22:22:00:22:22:00", + "up": true, + "speed": 1000, + "full_duplex": true, + "rx_bytes": 2648236513108, + "rx_dropped": 34030, + "rx_errors": 0, + "rx_packets": 3068347172, + "tx_bytes": 3009601283006, + "tx_dropped": 0, + "tx_errors": 0, + "tx_packets": 2859713220, + "rx_multicast": 939111, + "enable": true, + "dns": [ + "216.146.35.35", + "216.146.36.36" + ], + "gateway": "3.1.33.8" + }, + { + "name": "lan", + "ifname": "eth1", + "ip": "192.168.2.1", + "netmask": "255.255.252.0", + "mac": "22:22:00:22:22:00", + "up": true, + "speed": 1000, + "full_duplex": true, + "rx_bytes": 2911311797255, + "rx_dropped": 3438, + "rx_errors": 0, + "rx_packets": 2659342049, + "tx_bytes": 2140222188895, + "tx_dropped": 0, + "tx_errors": 0, + "tx_packets": 2734245088, + "rx_multicast": 11929365, + "enable": true + }, + { + "name": "lan2", + "ifname": "eth2", + "ip": "0.0.0.0", + "netmask": "0.0.0.0", + "mac": "22:22:00:22:22:00", + "up": false, + "speed": 0, + "full_duplex": false, + "rx_bytes": 0, + "rx_dropped": 0, + "rx_errors": 0, + "rx_packets": 0, + "tx_bytes": 0, + "tx_dropped": 0, + "tx_errors": 0, + "tx_packets": 0, + "rx_multicast": 0, + "enable": false + } + ], + "network_table": [ + { + "_id": "574e8de34566ffb914a26862", + "is_nat": true, + "dhcpd_dns_enabled": false, + "purpose": "guest", + "dhcpd_leasetime": "86400", + "igmp_snooping": true, + "dhcpguard_enabled": false, + "dhcpd_start": "192.168.5.1", + "enabled": true, + "dhcpd_stop": "192.168.5.254", + "dhcpd_wins_enabled": false, + "domain_name": "guest.lan", + "dhcpd_enabled": true, + "ip_subnet": "192.168.5.0/23", + "vlan": "5", + "networkgroup": "LAN", + "name": "Public Wireless", + "site_id": "574e86994566ffb914a2683c", + "dhcpd_ip_1": "", + "vlan_enabled": true, + "dhcpd_gateway_enabled": false, + "dhcpd_time_offset_enabled": false, + "ipv6_interface_type": "none", + "dhcp_relay_enabled": false, + "mac": "22:22:00:22:22:00", + "is_guest": true, + "ip": "192.168.5.0", + "up": "true", + "num_sta": 1, + "rx_bytes": 578602537, + "rx_packets": 471151, + "tx_bytes": 182318948, + "tx_packets": 239651 + }, + { + "_id": "59a362f645663e6cc8260133", + "is_nat": true, + "dhcpd_dns_enabled": false, + "purpose": "corporate", + "dhcpd_leasetime": 86400, + "dhcpd_start": "192.168.68.2", + "dhcpd_stop": "192.168.68.250", + "enabled": true, + "domain_name": "secure.lan", + "dhcpd_enabled": true, + "vlan": "69", + "ip_subnet": "192.168.69.1/23", + "networkgroup": "LAN", + "name": "Security Network", + "site_id": "574e86994566ffb914a2683c", + "vlan_enabled": true, + "dhcpd_ntp_1": "192.168.69.1", + "dhcpd_gateway_enabled": false, + "dhcpd_time_offset_enabled": false, + "dhcp_relay_enabled": false, + "dhcpd_ntp_enabled": true, + "ipv6_interface_type": "none", + "dhcpd_unifi_controller": "192.168.3.1", + "igmp_snooping": true, + "mac": "22:22:00:22:22:00", + "is_guest": false, + "ip": "192.168.69.1", + "up": "true", + "num_sta": 11, + "rx_bytes": 5221725, + "rx_packets": 70663, + "tx_bytes": 0, + "tx_packets": 0 + }, + { + "_id": "574e869d4566ffb914a26841", + "purpose": "corporate", + "dhcpd_leasetime": "86400", + "igmp_snooping": false, + "dhcpd_ntp_1": "192.168.2.1", + "dhcpguard_enabled": false, + "dhcpd_gateway_enabled": false, + "dhcpd_time_offset_enabled": false, + "dhcpd_start": "192.168.1.1", + "dhcpd_unifi_controller": "192.168.3.1", + "dhcpd_stop": "192.168.1.254", + "enabled": true, + "domain_name": "home.lan", + "dhcpd_enabled": true, + "ip_subnet": "192.168.2.1/22", + "networkgroup": "LAN", + "dhcpd_ip_1": "", + "vlan_enabled": false, + "is_nat": true, + "dhcpd_dns_enabled": false, + "dhcp_relay_enabled": false, + "dhcpd_wins_enabled": false, + "upnp_lan_enabled": true, + "dhcpd_ntp_enabled": true, + "name": "Home Network", + "site_id": "574e86994566ffb914a2683c", + "attr_no_delete": true, + "attr_hidden_id": "LAN", + "ipv6_interface_type": "none", + "mac": "22:22:00:22:22:00", + "is_guest": false, + "ip": "192.168.2.1", + "up": "true", + "num_sta": 30, + "rx_bytes": 2099754971983, + "rx_packets": 2689749160, + "tx_bytes": 2877873632166, + "tx_packets": 2579198457 + } + ], + "uplink": { + "drops": 40, + "enable": true, + "full_duplex": true, + "gateways": [ + "3.1.33.8" + ], + "ip": "3.1.33.7", + "latency": 103, + "mac": "22:22:00:22:22:00", + "name": "eth0", + "nameservers": [ + "1.1.1.1", + "8.8.8.8" + ], + "netmask": "255.255.254.0", + "num_port": 1, + "rx_bytes": 2648236513108, + "rx_dropped": 34030, + "rx_errors": 0, + "rx_multicast": 939111, + "rx_packets": 3068347172, + "speed": 1000, + "speedtest_lastrun": 1562310531, + "speedtest_ping": 14, + "speedtest_status": "Success", + "tx_bytes": 3009601283006, + "tx_dropped": 0, + "tx_errors": 0, + "tx_packets": 2859713220, + "up": true, + "uptime": 559088, + "xput_down": 157.368, + "xput_up": 37.905, + "tx_bytes-r": 2852355, + "rx_bytes-r": 1224743, + "bytes-r": 4077098, + "max_speed": 1000, + "type": "wire" + }, + "stat": { + "site_id": "574e86994566ffb914a2683c", + "o": "gw", + "oid": "22:22:00:22:22:00", + "gw": "22:22:00:22:22:00", + "time": 1562207100000, + "datetime": "2019-07-04T02:25:00Z", + "duration": 104466000, + "wan-rx_packets": 151387924, + "wan-rx_bytes": 111251311739, + "wan-tx_packets": 182985900, + "wan-tx_bytes": 230372237709, + "lan-rx_packets": 173953163, + "lan-rx_bytes": 226862410885, + "lan-tx_packets": 137029474, + "lan-tx_bytes": 89478206254, + "wan-rx_dropped": 561, + "lan-rx_dropped": 29 + }, + "tx_bytes": 2648236513108, + "rx_bytes": 3009601283006, + "bytes": 5657837796114, + "num_sta": 41, + "user-num_sta": 41, + "guest-num_sta": 0, + "num_desktop": 7, + "num_mobile": 2, + "num_handheld": 8 +} diff --git a/core/unifi/v4/examples/usw.json b/core/unifi/v4/examples/usw.json new file mode 100644 index 00000000..d70d6ab3 --- /dev/null +++ b/core/unifi/v4/examples/usw.json @@ -0,0 +1,1720 @@ +{ + "_id": "59a35cee45663e6cc82600f0", + "adopted": true, + "board_rev": 7, + "cfgversion": "669564dd04994088", + "config_network": { + "type": "dhcp", + "ip": "192.168.1.6" + }, + "dot1x_portctrl_enabled": false, + "ethernet_table": [ + { + "mac": "22:22:00:22:22:00", + "num_port": 26, + "name": "eth0" + }, + { + "mac": "22:22:00:22:22:00", + "name": "srv0" + } + ], + "flowctrl_enabled": false, + "fw_caps": 712229, + "has_fan": true, + "has_temperature": true, + "inform_ip": "192.168.3.1", + "inform_url": "http://security:8080/inform", + "ip": "192.168.1.7", + "jumboframe_enabled": false, + "led_override": "default", + "license_state": "registered", + "mac": "22:22:00:22:22:00", + "model": "US24P250", + "name": "switch", + "outdoor_mode_override": "default", + "port_overrides": [ + { + "name": "APC UPS", + "poe_mode": "off", + "port_idx": 1, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "poe_mode": "auto", + "port_idx": 2, + "portconf_id": "574e869d4566ffb914a26847" + }, + { + "name": "Camera: Gate", + "poe_mode": "auto", + "port_idx": 3, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Bubba's Desktop", + "poe_mode": "auto", + "port_idx": 4, + "portconf_id": "574e869d4566ffb914a26845" + }, + { + "name": "Lexi's Desktop", + "poe_mode": "off", + "port_idx": 5, + "portconf_id": "574e869d4566ffb914a26845" + }, + { + "name": "Camera: Car", + "poe_mode": "auto", + "port_idx": 6, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Camera: Garage", + "poe_mode": "auto", + "port_idx": 7, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Office Tertiary Desk PD14", + "poe_mode": "off", + "port_idx": 8, + "portconf_id": "574e869d4566ffb914a26847" + }, + { + "name": "Camera: Pool", + "poe_mode": "auto", + "port_idx": 9, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Security: Home Port", + "poe_mode": "off", + "port_idx": 10, + "portconf_id": "574e869d4566ffb914a26847" + }, + { + "name": "8ch Relay Board", + "poe_mode": "auto", + "port_idx": 11, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Security: Secure Port", + "poe_mode": "off", + "port_idx": 12, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Upstairs WAP", + "poe_mode": "auto", + "port_idx": 13, + "portconf_id": "574e869d4566ffb914a26845" + }, + { + "name": "Downstairs WAP", + "poe_mode": "auto", + "port_idx": 15, + "portconf_id": "574e869d4566ffb914a26845" + }, + { + "name": "David's Desk", + "poe_mode": "off", + "port_idx": 16, + "portconf_id": "574e869d4566ffb914a26845" + }, + { + "name": "Camera: Door", + "poe_mode": "auto", + "port_idx": 17, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Camera: Porch", + "poe_mode": "auto", + "port_idx": 19, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Camera: Road", + "port_idx": 21, + "portconf_id": "59a362f645663e6cc8260134" + }, + { + "name": "Livingroom Stereo", + "poe_mode": "off", + "port_idx": 22, + "portconf_id": "574e869d4566ffb914a26845" + }, + { + "name": "Homerun Prime", + "poe_mode": "off", + "port_idx": 23, + "portconf_id": "574e869d4566ffb914a26845" + }, + { + "name": "gateway", + "poe_mode": "off", + "port_idx": 24, + "portconf_id": "574e869d4566ffb914a26845" + } + ], + "port_table": [ + { + "port_idx": 1, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 1202, + "rx_bytes": 227167212, + "rx_dropped": 0, + "rx_errors": 12, + "rx_multicast": 28260, + "rx_packets": 1153365, + "satisfaction": 85, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 417327, + "tx_bytes": 507571083, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2284158, + "tx_packets": 4465717, + "up": true, + "tx_bytes-r": 45, + "rx_bytes-r": 5, + "bytes-r": 50, + "name": "APC UPS", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 2, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26847", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": false, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 1175, + "rx_bytes": 1068032535, + "rx_dropped": 150, + "rx_errors": 0, + "rx_multicast": 3489, + "rx_packets": 11624994, + "satisfaction": 90, + "speed": 0, + "stp_pathcost": 0, + "stp_state": "disabled", + "tx_broadcast": 62176, + "tx_bytes": 41832520833, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 302928, + "tx_packets": 28160117, + "up": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "name": "Port 2", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 3, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 0", + "poe_current": "91.55", + "poe_enable": true, + "poe_good": true, + "poe_power": "4.84", + "poe_voltage": "52.88", + "rx_broadcast": 65216, + "rx_bytes": 3456851429405, + "rx_dropped": 157638, + "rx_errors": 0, + "rx_multicast": 164814, + "rx_packets": 2410688372, + "satisfaction": 90, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 353417, + "tx_bytes": 40005007443, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2419630, + "tx_packets": 564763412, + "up": true, + "tx_bytes-r": 12085, + "rx_bytes-r": 888603, + "bytes-r": 900689, + "name": "Camera: Gate", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 4, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": false, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 646153, + "rx_bytes": 4581272050, + "rx_dropped": 15683, + "rx_errors": 0, + "rx_multicast": 36698, + "rx_packets": 53602118, + "satisfaction": 90, + "speed": 0, + "stp_pathcost": 0, + "stp_state": "disabled", + "tx_broadcast": 452081, + "tx_bytes": 166341729228, + "tx_dropped": 10704730, + "tx_errors": 0, + "tx_multicast": 3414231, + "tx_packets": 122098881, + "up": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "name": "Bubba's Desktop", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 5, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": false, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 1186, + "rx_bytes": 913565372, + "rx_dropped": 2079, + "rx_errors": 0, + "rx_multicast": 9915, + "rx_packets": 8040327, + "satisfaction": 90, + "speed": 0, + "stp_pathcost": 0, + "stp_state": "disabled", + "tx_broadcast": 99303, + "tx_bytes": 13691997722, + "tx_dropped": 126800, + "tx_errors": 0, + "tx_multicast": 619240, + "tx_packets": 11897488, + "up": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "name": "Lexi's Desktop", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 6, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 2", + "poe_current": "75.07", + "poe_enable": true, + "poe_good": true, + "poe_power": "3.95", + "poe_voltage": "52.63", + "rx_broadcast": 15135, + "rx_bytes": 1683544880532, + "rx_dropped": 105097, + "rx_errors": 0, + "rx_multicast": 140206, + "rx_packets": 1145100603, + "satisfaction": 90, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 403490, + "tx_bytes": 25109031755, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2363833, + "tx_packets": 356126846, + "up": true, + "tx_bytes-r": 7672, + "rx_bytes-r": 504473, + "bytes-r": 512145, + "name": "Camera: Car", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 7, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 0", + "poe_current": "92.28", + "poe_enable": true, + "poe_good": true, + "poe_power": "4.85", + "poe_voltage": "52.56", + "rx_broadcast": 65316, + "rx_bytes": 2610602428826, + "rx_dropped": 157634, + "rx_errors": 0, + "rx_multicast": 164757, + "rx_packets": 1825440143, + "satisfaction": 90, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 353314, + "tx_bytes": 30130225938, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2419669, + "tx_packets": 424070512, + "up": true, + "tx_bytes-r": 9976, + "rx_bytes-r": 786139, + "bytes-r": 796116, + "name": "Camera: Garage", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 8, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26847", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": false, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 1970, + "rx_bytes": 57788865632, + "rx_dropped": 49, + "rx_errors": 1, + "rx_multicast": 5397, + "rx_packets": 81214364, + "satisfaction": 75, + "speed": 0, + "stp_pathcost": 0, + "stp_state": "disabled", + "tx_broadcast": 243126, + "tx_bytes": 106910126818, + "tx_dropped": 343060, + "tx_errors": 0, + "tx_multicast": 1620633, + "tx_packets": 96321547, + "up": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "name": "Office Tertiary Desk PD14", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 9, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 4", + "poe_current": "185.42", + "poe_enable": true, + "poe_good": true, + "poe_power": "9.81", + "poe_voltage": "52.88", + "rx_broadcast": 63647, + "rx_bytes": 2607385367644, + "rx_dropped": 157620, + "rx_errors": 0, + "rx_multicast": 164740, + "rx_packets": 1811240949, + "satisfaction": 90, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 354985, + "tx_bytes": 29502203517, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2419671, + "tx_packets": 414986830, + "up": true, + "tx_bytes-r": 9281, + "rx_bytes-r": 781308, + "bytes-r": 790589, + "name": "Camera: Pool", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 10, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26847", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 133159, + "rx_bytes": 2980426813696, + "rx_dropped": 86, + "rx_errors": 0, + "rx_multicast": 1194903, + "rx_packets": 2315914383, + "satisfaction": 90, + "speed": 1000, + "stp_pathcost": 20000, + "stp_state": "forwarding", + "tx_broadcast": 2154128, + "tx_bytes": 1464180769133, + "tx_dropped": 250473, + "tx_errors": 0, + "tx_multicast": 13471964, + "tx_packets": 2230137488, + "up": true, + "tx_bytes-r": 1250938, + "rx_bytes-r": 2919503, + "bytes-r": 4170441, + "name": "Security: Home Port", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 11, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 0", + "poe_current": "12.93", + "poe_enable": true, + "poe_good": true, + "poe_power": "0.69", + "poe_voltage": "53.01", + "rx_broadcast": 10728, + "rx_bytes": 252244504, + "rx_dropped": 0, + "rx_errors": 2, + "rx_multicast": 0, + "rx_packets": 2540659, + "satisfaction": 85, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 407892, + "tx_bytes": 496402591, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2312237, + "tx_packets": 6542398, + "up": true, + "tx_bytes-r": 120, + "rx_bytes-r": 79, + "bytes-r": 199, + "name": "8ch Relay Board", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 12, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 19342, + "rx_bytes": 190236042211, + "rx_dropped": 174281, + "rx_errors": 0, + "rx_multicast": 649832, + "rx_packets": 2704715442, + "satisfaction": 90, + "speed": 1000, + "stp_pathcost": 20000, + "stp_state": "forwarding", + "tx_broadcast": 395664, + "tx_bytes": 18974306738758, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 1886642, + "tx_packets": 13093826470, + "up": true, + "tx_bytes-r": 5653872, + "rx_bytes-r": 67700, + "bytes-r": 5721573, + "name": "Security: Secure Port", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 13, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 0", + "poe_current": "88.13", + "poe_enable": true, + "poe_good": true, + "poe_power": "4.65", + "poe_voltage": "52.76", + "rx_broadcast": 383577, + "rx_bytes": 550646722109, + "rx_dropped": 116302, + "rx_errors": 0, + "rx_multicast": 2950663, + "rx_packets": 892359442, + "satisfaction": 90, + "speed": 1000, + "stp_pathcost": 20000, + "stp_state": "forwarding", + "tx_broadcast": 2351476, + "tx_bytes": 1374251273399, + "tx_dropped": 614, + "tx_errors": 0, + "tx_multicast": 12430218, + "tx_packets": 1140545051, + "up": true, + "tx_bytes-r": 1098062, + "rx_bytes-r": 81853, + "bytes-r": 1179915, + "name": "Upstairs WAP", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 14, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": false, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 0, + "rx_bytes": 0, + "rx_dropped": 0, + "rx_errors": 0, + "rx_multicast": 0, + "rx_packets": 0, + "satisfaction": 100, + "speed": 0, + "stp_pathcost": 0, + "stp_state": "disabled", + "tx_broadcast": 0, + "tx_bytes": 0, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 0, + "tx_packets": 0, + "up": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "name": "Port 14", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 15, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 0", + "poe_current": "71.65", + "poe_enable": true, + "poe_good": true, + "poe_power": "3.77", + "poe_voltage": "52.63", + "rx_broadcast": 196313, + "rx_bytes": 155746936125, + "rx_dropped": 19700, + "rx_errors": 0, + "rx_multicast": 2064123, + "rx_packets": 254212324, + "satisfaction": 90, + "speed": 1000, + "stp_pathcost": 20000, + "stp_state": "forwarding", + "tx_broadcast": 2538787, + "tx_bytes": 229690921008, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 13311081, + "tx_packets": 260289095, + "up": true, + "tx_bytes-r": 20824, + "rx_bytes-r": 4227, + "bytes-r": 25051, + "name": "Downstairs WAP", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 16, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 11925, + "rx_bytes": 300038087723, + "rx_dropped": 6, + "rx_errors": 0, + "rx_multicast": 105090, + "rx_packets": 487779140, + "satisfaction": 90, + "speed": 1000, + "stp_pathcost": 20000, + "stp_state": "forwarding", + "tx_broadcast": 2698267, + "tx_bytes": 1161896194876, + "tx_dropped": 2542, + "tx_errors": 0, + "tx_multicast": 15097190, + "tx_packets": 936474098, + "up": true, + "tx_bytes-r": 792886, + "rx_bytes-r": 1134268, + "bytes-r": 1927154, + "name": "David's Desk", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 17, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 0", + "poe_current": "52.24", + "poe_enable": true, + "poe_good": true, + "poe_power": "2.75", + "poe_voltage": "52.69", + "rx_broadcast": 57982, + "rx_bytes": 3736764408104, + "rx_dropped": 157644, + "rx_errors": 1, + "rx_multicast": 157809, + "rx_packets": 2553432414, + "satisfaction": 75, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 360666, + "tx_bytes": 37300635720, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2433676, + "tx_packets": 525589037, + "up": true, + "tx_bytes-r": 11826, + "rx_bytes-r": 1204374, + "bytes-r": 1216200, + "name": "Camera: Door", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 18, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 106288, + "rx_bytes": 2133344721406, + "rx_dropped": 25, + "rx_errors": 12, + "rx_multicast": 311666, + "rx_packets": 2159594753, + "satisfaction": 75, + "speed": 1000, + "stp_pathcost": 20000, + "stp_state": "forwarding", + "tx_broadcast": 2629049, + "tx_bytes": 1194122124612, + "tx_dropped": 7147, + "tx_errors": 0, + "tx_multicast": 15063781, + "tx_packets": 1677508931, + "up": true, + "tx_bytes-r": 37435, + "rx_bytes-r": 1009309, + "bytes-r": 1046744, + "name": "Port 18", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 19, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 0", + "poe_current": "84.22", + "poe_enable": true, + "poe_good": true, + "poe_power": "4.43", + "poe_voltage": "52.56", + "rx_broadcast": 59295, + "rx_bytes": 1565104688294, + "rx_dropped": 157648, + "rx_errors": 0, + "rx_multicast": 157775, + "rx_packets": 1148468555, + "satisfaction": 90, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 359378, + "tx_bytes": 1645861732, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2433784, + "tx_packets": 21052239, + "up": true, + "tx_bytes-r": 8133, + "rx_bytes-r": 483735, + "bytes-r": 491868, + "name": "Camera: Porch", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 20, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": false, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 0, + "rx_bytes": 0, + "rx_dropped": 0, + "rx_errors": 0, + "rx_multicast": 0, + "rx_packets": 0, + "satisfaction": 100, + "speed": 0, + "stp_pathcost": 0, + "stp_state": "disabled", + "tx_broadcast": 0, + "tx_bytes": 0, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 0, + "tx_packets": 0, + "up": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "name": "Port 20", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 21, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "59a362f645663e6cc8260134", + "poe_mode": "auto", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Class 0", + "poe_current": "123.90", + "poe_enable": true, + "poe_good": true, + "poe_power": "6.56", + "poe_voltage": "52.95", + "rx_broadcast": 61014, + "rx_bytes": 3317256188719, + "rx_dropped": 157642, + "rx_errors": 0, + "rx_multicast": 157803, + "rx_packets": 2220162515, + "satisfaction": 90, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 357637, + "tx_bytes": 30626674529, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 2433710, + "tx_packets": 428205094, + "up": true, + "tx_bytes-r": 9771, + "rx_bytes-r": 1006105, + "bytes-r": 1015877, + "name": "Camera: Road", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 22, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 14465, + "rx_bytes": 794839703, + "rx_dropped": 3, + "rx_errors": 0, + "rx_multicast": 1080600, + "rx_packets": 5377988, + "satisfaction": 90, + "speed": 100, + "stp_pathcost": 200000, + "stp_state": "forwarding", + "tx_broadcast": 2720299, + "tx_bytes": 9381221794, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 14294088, + "tx_packets": 37961870, + "up": true, + "tx_bytes-r": 4900, + "rx_bytes-r": 536, + "bytes-r": 5436, + "name": "Livingroom Stereo", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 23, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 532640, + "rx_bytes": 331010131889, + "rx_dropped": 35400, + "rx_errors": 0, + "rx_multicast": 576408, + "rx_packets": 261698587, + "satisfaction": 90, + "speed": 1000, + "stp_pathcost": 20000, + "stp_state": "forwarding", + "tx_broadcast": 2202860, + "tx_bytes": 15811798849, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 14799244, + "tx_packets": 184788576, + "up": true, + "tx_bytes-r": 1611, + "rx_bytes-r": 3806, + "bytes-r": 5418, + "name": "Homerun Prime", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 24, + "media": "GE", + "port_poe": true, + "poe_caps": 7, + "speed_caps": 1048623, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "poe_mode": "off", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": true, + "is_uplink": true, + "jumbo": false, + "lldp_table": [ + { + "lldp_chassis_id": "22:22:00:22:22:00", + "lldp_port_id": "eth1", + "lldp_system_name": "gateway" + } + ], + "poe_class": "Unknown", + "poe_current": "0.00", + "poe_enable": false, + "poe_good": false, + "poe_power": "0.00", + "poe_voltage": "0.00", + "rx_broadcast": 186134, + "rx_bytes": 2149399426518, + "rx_dropped": 183, + "rx_errors": 0, + "rx_multicast": 4799002, + "rx_packets": 2730988091, + "satisfaction": 90, + "speed": 1000, + "stp_pathcost": 20000, + "stp_state": "forwarding", + "tx_broadcast": 2549473, + "tx_bytes": 2905955335082, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 11918890, + "tx_packets": 2655236464, + "up": true, + "tx_bytes-r": 2348698, + "rx_bytes-r": 393352, + "bytes-r": 2742050, + "name": "gateway", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 25, + "media": "SFP", + "port_poe": false, + "poe_caps": 0, + "speed_caps": 1048608, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": false, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "rx_broadcast": 0, + "rx_bytes": 0, + "rx_dropped": 0, + "rx_errors": 0, + "rx_multicast": 0, + "rx_packets": 0, + "satisfaction": 100, + "sfp_found": false, + "speed": 0, + "stp_pathcost": 0, + "stp_state": "disabled", + "tx_broadcast": 0, + "tx_bytes": 0, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 0, + "tx_packets": 0, + "up": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "name": "SFP 1", + "masked": false, + "aggregated_by": false + }, + { + "port_idx": 26, + "media": "SFP", + "port_poe": false, + "poe_caps": 0, + "speed_caps": 1048608, + "op_mode": "switch", + "portconf_id": "574e869d4566ffb914a26845", + "autoneg": true, + "dot1x_mode": "unknown", + "dot1x_status": "disabled", + "enable": true, + "flowctrl_rx": false, + "flowctrl_tx": false, + "full_duplex": false, + "is_uplink": false, + "jumbo": false, + "lldp_table": [], + "rx_broadcast": 0, + "rx_bytes": 0, + "rx_dropped": 0, + "rx_errors": 0, + "rx_multicast": 0, + "rx_packets": 0, + "satisfaction": 100, + "sfp_found": false, + "speed": 0, + "stp_pathcost": 0, + "stp_state": "disabled", + "tx_broadcast": 0, + "tx_bytes": 0, + "tx_dropped": 0, + "tx_errors": 0, + "tx_multicast": 0, + "tx_packets": 0, + "up": false, + "tx_bytes-r": 0, + "rx_bytes-r": 0, + "bytes-r": 0, + "name": "SFP 2", + "masked": false, + "aggregated_by": false + } + ], + "serial": "xxxyyyzzz", + "site_id": "574e86994566ffb914a2683c", + "stp_priority": "32768", + "stp_version": "rstp", + "type": "usw", + "version": "4.0.42.10433", + "required_version": "3.3.1", + "switch_caps": { + "feature_caps": 1022, + "max_mirror_sessions": 1, + "max_aggregate_sessions": 6 + }, + "hw_caps": 0, + "unsupported": false, + "unsupported_reason": 0, + "sys_error_caps": 0, + "device_id": "59a35cee45663e6cc82600f0", + "state": 1, + "last_seen": 1562309680, + "upgradable": false, + "adoptable_when_upgraded": false, + "rollupgrade": false, + "known_cfgversion": "669564dd04994088", + "uptime": 3188809, + "_uptime": 3188809, + "locating": false, + "connect_request_ip": "192.168.1.7", + "connect_request_port": "45941", + "sys_stats": { + "loadavg_1": "1.83", + "loadavg_15": "1.72", + "loadavg_5": "1.77", + "mem_buffer": 0, + "mem_total": 262397952, + "mem_used": 131473408 + }, + "system-stats": { + "cpu": "59.3", + "mem": "50.1", + "uptime": "3188809" + }, + "ssh_session_table": [], + "fan_level": 50, + "general_temperature": 43, + "overheating": false, + "total_max_power": 222, + "downlink_table": [ + { + "port_idx": 13, + "speed": 1000, + "full_duplex": true, + "mac": "22:22:00:22:22:00" + }, + { + "port_idx": 15, + "speed": 1000, + "full_duplex": true, + "mac": "22:22:00:22:22:00" + } + ], + "uplink": { + "full_duplex": true, + "ip": "192.168.1.7", + "mac": "22:22:00:22:22:00", + "name": "eth0", + "netmask": "255.255.252.0", + "num_port": 26, + "rx_bytes": 2149399426518, + "rx_dropped": 183, + "rx_errors": 0, + "rx_multicast": 0, + "rx_packets": 2730988091, + "speed": 1000, + "tx_bytes": 2905955335082, + "tx_dropped": 0, + "tx_errors": 0, + "tx_packets": 2655236464, + "up": true, + "port_idx": 24, + "media": "GE", + "max_speed": 1000, + "uplink_mac": "22:22:00:22:22:00", + "type": "wire", + "tx_bytes-r": 2348698, + "rx_bytes-r": 393352 + }, + "last_uplink": { + "uplink_mac": "22:22:00:22:22:00" + }, + "uplink_depth": 1, + "dhcp_server_table": [], + "stat": { + "site_id": "574e86994566ffb914a2683c", + "o": "sw", + "oid": "22:22:00:22:22:00", + "sw": "22:22:00:22:22:00", + "time": 1562207400000, + "datetime": "2019-07-04T02:30:00Z", + "rx_packets": 1521931792, + "rx_bytes": 1640634193054, + "rx_errors": 0, + "rx_dropped": 44998, + "rx_crypts": 0, + "rx_frags": 0, + "tx_packets": 1526591275, + "tx_bytes": 1641404646603, + "tx_errors": 0, + "tx_dropped": 230234, + "tx_retries": 0, + "rx_multicast": 477933, + "rx_broadcast": 134416, + "tx_multicast": 4372775, + "tx_broadcast": 1123817, + "bytes": 3282038839657, + "duration": 102277000, + "port_1-rx_packets": 37407, + "port_1-rx_bytes": 7345154, + "port_1-tx_packets": 142648, + "port_1-tx_bytes": 15425151, + "port_1-tx_multicast": 72854, + "port_1-tx_broadcast": 13075, + "port_3-rx_packets": 88198959, + "port_3-rx_bytes": 127291063971, + "port_3-tx_packets": 20230363, + "port_3-tx_bytes": 1436625813, + "port_3-rx_broadcast": 2037, + "port_3-tx_multicast": 78496, + "port_3-tx_broadcast": 11062, + "port_6-rx_packets": 37102295, + "port_6-rx_bytes": 54565186228, + "port_6-tx_packets": 11561353, + "port_6-tx_bytes": 814818610, + "port_6-rx_multicast": 4504, + "port_6-tx_multicast": 76688, + "port_6-tx_broadcast": 12634, + "port_7-rx_packets": 59149016, + "port_7-rx_bytes": 84615020479, + "port_7-tx_packets": 14033190, + "port_7-tx_bytes": 996438501, + "port_7-tx_multicast": 78496, + "port_7-tx_broadcast": 11058, + "port_9-rx_packets": 58736633, + "port_9-rx_bytes": 84549190443, + "port_9-tx_packets": 14151617, + "port_9-tx_bytes": 1004772261, + "port_9-tx_multicast": 78496, + "port_9-tx_broadcast": 11058, + "port_10-rx_packets": 267372091, + "port_10-rx_bytes": 281500610536, + "port_10-tx_packets": 563250041, + "port_10-tx_bytes": 567769155042, + "port_10-rx_multicast": 43302, + "port_10-tx_multicast": 424255, + "port_10-tx_broadcast": 119711, + "port_11-rx_packets": 81983, + "port_11-rx_bytes": 8144416, + "port_11-tx_packets": 209313, + "port_11-tx_bytes": 15405574, + "port_11-tx_multicast": 73730, + "port_11-tx_broadcast": 12758, + "port_12-rx_packets": 103277309, + "port_12-rx_bytes": 7258199289, + "port_12-tx_packets": 439910260, + "port_12-tx_bytes": 639760721999, + "port_12-tx_multicast": 60704, + "port_12-tx_broadcast": 12565, + "port_13-rx_packets": 246443105, + "port_13-rx_bytes": 198040237192, + "port_13-tx_packets": 78593344, + "port_13-tx_bytes": 57869606583, + "port_13-rx_multicast": 137299, + "port_13-rx_broadcast": 65040, + "port_13-tx_multicast": 355704, + "port_13-tx_broadcast": 72404, + "port_15-rx_packets": 91090086, + "port_15-rx_bytes": 129066815209, + "port_15-tx_packets": 21964312, + "port_15-tx_bytes": 8996022939, + "port_15-rx_broadcast": 6271, + "port_15-tx_multicast": 470685, + "port_15-tx_broadcast": 131171, + "port_16-rx_packets": 186203471, + "port_16-rx_bytes": 238718016683, + "port_16-tx_packets": 111909553, + "port_16-tx_bytes": 116205334442, + "port_16-tx_multicast": 484907, + "port_16-tx_broadcast": 137180, + "port_17-rx_packets": 88192775, + "port_17-rx_bytes": 129333707339, + "port_17-tx_packets": 18059043, + "port_17-tx_bytes": 1280177720, + "port_17-tx_multicast": 78951, + "port_17-tx_broadcast": 11288, + "port_18-rx_packets": 47274835, + "port_18-rx_bytes": 52416730761, + "port_18-tx_packets": 31288433, + "port_18-tx_bytes": 19604228682, + "port_18-rx_multicast": 10027, + "port_18-tx_multicast": 478207, + "port_18-tx_broadcast": 136852, + "port_19-rx_packets": 37113361, + "port_19-rx_bytes": 51866531433, + "port_19-tx_packets": 11858558, + "port_19-tx_bytes": 835844449, + "port_19-tx_multicast": 78952, + "port_19-tx_broadcast": 11216, + "port_21-rx_packets": 72039284, + "port_21-rx_bytes": 107639322810, + "port_21-tx_packets": 14367901, + "port_21-tx_bytes": 1026379138, + "port_21-rx_broadcast": 1926, + "port_21-tx_multicast": 78951, + "port_21-tx_broadcast": 11173, + "port_22-rx_packets": 176103, + "port_22-rx_bytes": 25390561, + "port_22-tx_packets": 1272735, + "port_22-tx_bytes": 294225324, + "port_22-rx_multicast": 35968, + "port_22-tx_multicast": 452266, + "port_22-tx_broadcast": 137038, + "port_23-rx_packets": 4246915, + "port_23-rx_bytes": 4976913808, + "port_23-rx_dropped": 1138, + "port_23-tx_packets": 2141027, + "port_23-tx_bytes": 251388436, + "port_23-rx_multicast": 18478, + "port_23-rx_broadcast": 17522, + "port_23-tx_multicast": 469756, + "port_23-tx_broadcast": 119922, + "port_24-rx_packets": 134576026, + "port_24-rx_bytes": 88659302916, + "port_24-tx_packets": 170136735, + "port_24-tx_bytes": 221668518676, + "port_24-rx_multicast": 153949, + "port_24-tx_multicast": 376773, + "port_24-tx_broadcast": 132998, + "port_1-rx_multicast": 881, + "port_3-rx_dropped": 5055, + "port_3-rx_multicast": 5283, + "port_6-rx_dropped": 3370, + "port_7-rx_dropped": 5052, + "port_7-rx_multicast": 5280, + "port_9-rx_dropped": 5052, + "port_9-rx_multicast": 5280, + "port_9-rx_broadcast": 2041, + "port_10-rx_broadcast": 4628, + "port_12-rx_dropped": 5055, + "port_12-rx_multicast": 19895, + "port_13-rx_dropped": 3759, + "port_17-rx_dropped": 5055, + "port_17-rx_multicast": 5055, + "port_17-rx_broadcast": 1811, + "port_19-rx_dropped": 5055, + "port_19-rx_multicast": 5055, + "port_19-rx_broadcast": 1883, + "port_21-rx_dropped": 5055, + "port_21-rx_multicast": 5055, + "port_7-rx_broadcast": 2041, + "port_18-rx_broadcast": 590, + "port_16-rx_multicast": 3329, + "port_15-rx_dropped": 800, + "port_15-rx_multicast": 17552, + "port_16-rx_broadcast": 262, + "port_11-rx_broadcast": 341, + "port_12-rx_broadcast": 534, + "port_6-rx_broadcast": 465, + "port_24-rx_broadcast": 4447, + "port_22-rx_broadcast": 404, + "port_10-tx_dropped": 195211, + "port_16-tx_dropped": 251, + "port_1-rx_broadcast": 20, + "port_4-rx_packets": 620138, + "port_4-rx_bytes": 96463826, + "port_4-rx_dropped": 552, + "port_4-tx_packets": 1510849, + "port_4-tx_bytes": 1559557263, + "port_4-tx_dropped": 34772, + "port_4-rx_multicast": 1741, + "port_4-rx_broadcast": 22153, + "port_4-tx_multicast": 103904, + "port_4-tx_broadcast": 18654 + }, + "tx_bytes": 2149399426518, + "rx_bytes": 2905955335082, + "bytes": 5055354761600, + "num_sta": 16, + "user-num_sta": 16, + "guest-num_sta": 0 +}, diff --git a/core/unifi/v4/go.mod b/core/unifi/v4/go.mod new file mode 100644 index 00000000..80ac2e5c --- /dev/null +++ b/core/unifi/v4/go.mod @@ -0,0 +1,9 @@ +module golift.io/unifi + +go 1.13 + +require ( + github.com/davecgh/go-spew v1.1.1 + github.com/pmezard/go-difflib v1.0.0 + github.com/stretchr/testify v1.4.0 +) diff --git a/core/unifi/v4/go.sum b/core/unifi/v4/go.sum new file mode 100644 index 00000000..1041afa2 --- /dev/null +++ b/core/unifi/v4/go.sum @@ -0,0 +1,11 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/core/unifi/v4/ids.go b/core/unifi/v4/ids.go new file mode 100644 index 00000000..6af0c8ab --- /dev/null +++ b/core/unifi/v4/ids.go @@ -0,0 +1,150 @@ +package unifi + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" +) + +// IDSList contains a list that contains all of the IDS Events on a controller. +type IDSList []*IDS + +// IDS holds an Intrusion Prevention System Event. +type IDS struct { + SourceName string `json:"-"` + ID string `json:"_id"` + Archived FlexBool `json:"archived"` + Timestamp int64 `json:"timestamp"` + FlowID int64 `json:"flow_id"` + InIface string `json:"in_iface"` + EventType string `json:"event_type"` + SrcIP string `json:"src_ip"` + SrcMac string `json:"src_mac"` + SrcPort int `json:"src_port,omitempty"` + DestIP string `json:"dest_ip"` + DstMac string `json:"dst_mac"` + DestPort int `json:"dest_port,omitempty"` + Proto string `json:"proto"` + AppProto string `json:"app_proto,omitempty"` + Host string `json:"host"` + Usgip string `json:"usgip"` + UniqueAlertid string `json:"unique_alertid"` + SrcipCountry string `json:"srcipCountry"` + DstipCountry FlexBool `json:"dstipCountry"` + UsgipCountry string `json:"usgipCountry"` + SrcipGeo struct { + ContinentCode string `json:"continent_code"` + CountryCode string `json:"country_code"` + CountryCode3 string `json:"country_code3"` + CountryName string `json:"country_name"` + Region string `json:"region"` + City string `json:"city"` + PostalCode string `json:"postal_code"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + DmaCode int64 `json:"dma_code"` + AreaCode int64 `json:"area_code"` + } `json:"srcipGeo"` + DstipGeo bool `json:"dstipGeo"` + UsgipGeo struct { + ContinentCode string `json:"continent_code"` + CountryCode string `json:"country_code"` + CountryCode3 string `json:"country_code3"` + CountryName string `json:"country_name"` + Region string `json:"region"` + City string `json:"city"` + PostalCode string `json:"postal_code"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + DmaCode int64 `json:"dma_code"` + AreaCode int64 `json:"area_code"` + } `json:"usgipGeo"` + SrcipASN string `json:"srcipASN"` + DstipASN string `json:"dstipASN"` + UsgipASN string `json:"usgipASN"` + Catname string `json:"catname"` + InnerAlertAction string `json:"inner_alert_action"` + InnerAlertGID int64 `json:"inner_alert_gid"` + InnerAlertSignatureID int64 `json:"inner_alert_signature_id"` + InnerAlertRev int64 `json:"inner_alert_rev"` + InnerAlertSignature string `json:"inner_alert_signature"` + InnerAlertCategory string `json:"inner_alert_category"` + InnerAlertSeverity int64 `json:"inner_alert_severity"` + Key string `json:"key"` + Subsystem string `json:"subsystem"` + SiteID string `json:"site_id"` + SiteName string `json:"-"` + Time int64 `json:"time"` + Datetime time.Time `json:"datetime"` + Msg string `json:"msg"` + IcmpType int64 `json:"icmp_type,omitempty"` + IcmpCode int64 `json:"icmp_code,omitempty"` +} + +// GetIDS returns Intrusion Detection Systems events. +// Returns all events that happened in site between from and to. +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) + if err != nil { + return data, err + } + + for i := range ids { + ids[i].SourceName = u.URL + } + + data = append(data, ids...) + } + + return data, nil +} + +// 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) { + var response struct { + Data []*IDS `json:"data"` + } + + URIpath := fmt.Sprintf(APIIPSEvents, site.Name) + + params := fmt.Sprintf(`{"start":"%v000","end":"%v000","_limit":50000}`, from.Unix(), to.Unix()) + + req, err := u.UniReq(URIpath, params) + if err != nil { + return nil, err + } + + resp, err := u.Do(req) + if err != nil { + return nil, err + } + + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("invalid status code from server %s", resp.Status) + } + + if err := json.Unmarshal(body, &response); err != nil { + return nil, err + } + + for i := range response.Data { + response.Data[i].SiteName = site.SiteName + } + + return response.Data, nil +} diff --git a/core/unifi/v4/site.go b/core/unifi/v4/site.go new file mode 100644 index 00000000..20018b03 --- /dev/null +++ b/core/unifi/v4/site.go @@ -0,0 +1,124 @@ +package unifi + +import ( + "fmt" + "strings" +) + +// GetSites returns a list of configured sites on the UniFi controller. +func (u *Unifi) GetSites() (Sites, error) { + var response struct { + Data []*Site `json:"data"` + } + + if err := u.GetData(APISiteList, &response); err != nil { + return nil, err + } + + sites := []string{} // used for debug log only + + for i, d := range response.Data { + // Add special SourceName value. + response.Data[i].SourceName = u.URL + // If the human name is missing (description), set it to the cryptic name. + response.Data[i].Desc = pick(d.Desc, d.Name) + // Add the custom site name to each site. used as a Grafana filter somewhere. + response.Data[i].SiteName = d.Desc + " (" + d.Name + ")" + sites = append(sites, d.Name) // used for debug log only + } + + u.DebugLog("Found %d site(s): %s", len(sites), strings.Join(sites, ",")) + + return response.Data, nil +} + +// GetSiteDPI garners dpi data for sites. +func (u *Unifi) GetSiteDPI(sites Sites) ([]*DPITable, error) { + data := []*DPITable{} + + for _, site := range sites { + u.DebugLog("Polling Controller, retreiving Site DPI data, site %s (%s) ", site.Name, site.Desc) + + var response struct { + Data []*DPITable `json:"data"` + } + + siteDPIpath := fmt.Sprintf(APISiteDPI, site.Name) + if err := u.GetData(siteDPIpath, &response, `{"type":"by_app"}`); err != nil { + return nil, err + } + + if l := len(response.Data); l > 1 { + return nil, fmt.Errorf("dpi data table contains more than 1 item; please open a bug report") + } else if l != 1 { + continue + } + + response.Data[0].SourceName = site.SourceName + response.Data[0].SiteName = site.SiteName + data = append(data, response.Data[0]) + } + + return data, nil +} + +// Sites is a struct to match Devices and Clients. +type Sites []*Site + +// Site represents a site's data. +type Site struct { + SourceName string `json:"-"` + ID string `json:"_id"` + Name string `json:"name"` + Desc string `json:"desc"` + SiteName string `json:"-"` + AttrHiddenID string `json:"attr_hidden_id"` + AttrNoDelete FlexBool `json:"attr_no_delete"` + Health []struct { + Subsystem string `json:"subsystem"` + NumUser FlexInt `json:"num_user,omitempty"` + NumGuest FlexInt `json:"num_guest,omitempty"` + NumIot FlexInt `json:"num_iot,omitempty"` + TxBytesR FlexInt `json:"tx_bytes-r,omitempty"` + RxBytesR FlexInt `json:"rx_bytes-r,omitempty"` + Status string `json:"status"` + NumAp FlexInt `json:"num_ap,omitempty"` + NumAdopted FlexInt `json:"num_adopted,omitempty"` + NumDisabled FlexInt `json:"num_disabled,omitempty"` + NumDisconnected FlexInt `json:"num_disconnected,omitempty"` + NumPending FlexInt `json:"num_pending,omitempty"` + NumGw FlexInt `json:"num_gw,omitempty"` + WanIP string `json:"wan_ip,omitempty"` + Gateways []string `json:"gateways,omitempty"` + Netmask string `json:"netmask,omitempty"` + Nameservers []string `json:"nameservers,omitempty"` + NumSta FlexInt `json:"num_sta,omitempty"` + GwMac string `json:"gw_mac,omitempty"` + GwName string `json:"gw_name,omitempty"` + GwSystemStats struct { + CPU FlexInt `json:"cpu"` + Mem FlexInt `json:"mem"` + Uptime FlexInt `json:"uptime"` + } `json:"gw_system-stats,omitempty"` + GwVersion string `json:"gw_version,omitempty"` + Latency FlexInt `json:"latency,omitempty"` + Uptime FlexInt `json:"uptime,omitempty"` + Drops FlexInt `json:"drops,omitempty"` + XputUp FlexInt `json:"xput_up,omitempty"` + XputDown FlexInt `json:"xput_down,omitempty"` + SpeedtestStatus string `json:"speedtest_status,omitempty"` + SpeedtestLastrun FlexInt `json:"speedtest_lastrun,omitempty"` + SpeedtestPing FlexInt `json:"speedtest_ping,omitempty"` + LanIP string `json:"lan_ip,omitempty"` + NumSw FlexInt `json:"num_sw,omitempty"` + RemoteUserEnabled FlexBool `json:"remote_user_enabled,omitempty"` + RemoteUserNumActive FlexInt `json:"remote_user_num_active,omitempty"` + RemoteUserNumInactive FlexInt `json:"remote_user_num_inactive,omitempty"` + RemoteUserRxBytes FlexInt `json:"remote_user_rx_bytes,omitempty"` + RemoteUserTxBytes FlexInt `json:"remote_user_tx_bytes,omitempty"` + RemoteUserRxPackets FlexInt `json:"remote_user_rx_packets,omitempty"` + RemoteUserTxPackets FlexInt `json:"remote_user_tx_packets,omitempty"` + SiteToSiteEnabled FlexBool `json:"site_to_site_enabled,omitempty"` + } `json:"health"` + NumNewAlarms FlexInt `json:"num_new_alarms"` +} diff --git a/core/unifi/v4/types.go b/core/unifi/v4/types.go new file mode 100644 index 00000000..ed298f40 --- /dev/null +++ b/core/unifi/v4/types.go @@ -0,0 +1,132 @@ +package unifi + +import ( + "encoding/json" + "fmt" + "net/http" + "strconv" + "strings" +) + +// This is a list of unifi API paths. +// The %s in each string must be replaced with a Site.Name. +const ( + // APIStatusPath shows Controller version. + APIStatusPath string = "/status" + // APISiteList is the path to the api site list. + APISiteList string = "/api/stat/sites" + // APISiteDPI is site DPI data. + APISiteDPI string = "/api/s/%s/stat/sitedpi" + // APISiteDPI is site DPI data. + APIClientDPI string = "/api/s/%s/stat/stadpi" + // APIClientPath is Unifi Clients API Path + APIClientPath string = "/api/s/%s/stat/sta" + // APIDevicePath is where we get data about Unifi devices. + APIDevicePath string = "/api/s/%s/stat/device" + // APINetworkPath contains network-configuration data. Not really graphable. + APINetworkPath string = "/api/s/%s/rest/networkconf" + // APIUserGroupPath contains usergroup configurations. + APIUserGroupPath string = "/api/s/%s/rest/usergroup" + // APILoginPath is Unifi Controller Login API Path + APILoginPath string = "/api/login" + // APIIPSEvents returns Intrusion Detection Systems Events + APIIPSEvents string = "/api/s/%s/stat/ips/event" +) + +// Logger is a base type to deal with changing log outputs. Create a logger +// that matches this interface to capture debug and error logs. +type Logger func(msg string, fmt ...interface{}) + +// discardLogs is the default debug logger. +func discardLogs(msg string, v ...interface{}) { + // do nothing. +} + +// 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 + UDMs []*UDM +} + +// Config is the data passed into our library. This configures things and allows +// us to connect to a controller and write log messages. +type Config struct { + User string + Pass string + URL string + VerifySSL bool + ErrorLog Logger + DebugLog Logger +} + +// Unifi is what you get in return for providing a password! Unifi represents +// a controller that you can make authenticated requests to. Use this to make +// additional requests for devices, clients or other custom data. Do not set +// the loggers to nil. Set them to DiscardLogs if you want no logs. +type Unifi struct { + *http.Client + *Config + *server +} + +// server is the /status endpoint from the Unifi controller. +type server struct { + Up FlexBool `json:"up"` + ServerVersion string `json:"server_version"` + UUID string `json:"uuid"` +} + +// FlexInt provides a container and unmarshalling for fields that may be +// numbers or strings in the Unifi API. +type FlexInt struct { + Val float64 + Txt string +} + +// UnmarshalJSON converts a string or number to an integer. +// Generally, do call this directly, it's used in the json interface. +func (f *FlexInt) UnmarshalJSON(b []byte) error { + var unk interface{} + + if err := json.Unmarshal(b, &unk); err != nil { + return err + } + + switch i := unk.(type) { + case float64: + f.Val = i + f.Txt = strconv.FormatFloat(i, 'f', -1, 64) + case string: + f.Txt = i + f.Val, _ = strconv.ParseFloat(i, 64) + case nil: + f.Txt = "0" + f.Val = 0 + default: + return fmt.Errorf("cannot unmarshal to FlexInt: %s", b) + } + + return nil +} + +// FlexBool provides a container and unmarshalling for fields that may be +// boolean or strings in the Unifi API. +type FlexBool struct { + Val bool + Txt string +} + +// UnmarshalJSON method converts armed/disarmed, yes/no, active/inactive or 0/1 to true/false. +// Really it converts ready, ok, up, t, armed, yes, active, enabled, 1, true to true. Anything else is false. +func (f *FlexBool) UnmarshalJSON(b []byte) error { + f.Txt = strings.Trim(string(b), `"`) + f.Val = f.Txt == "1" || strings.EqualFold(f.Txt, "true") || strings.EqualFold(f.Txt, "yes") || + strings.EqualFold(f.Txt, "t") || strings.EqualFold(f.Txt, "armed") || strings.EqualFold(f.Txt, "active") || + strings.EqualFold(f.Txt, "enabled") || strings.EqualFold(f.Txt, "ready") || strings.EqualFold(f.Txt, "up") || + strings.EqualFold(f.Txt, "ok") + + return nil +} diff --git a/core/unifi/v4/types_test.go b/core/unifi/v4/types_test.go new file mode 100644 index 00000000..a7eeef06 --- /dev/null +++ b/core/unifi/v4/types_test.go @@ -0,0 +1,41 @@ +package unifi + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFlexInt(t *testing.T) { + t.Parallel() + a := assert.New(t) + five, seven := 5, 7 + + var r struct { + Five FlexInt `json:"five"` + Seven FlexInt `json:"seven"` + Auto FlexInt `json:"auto"` + Channel FlexInt `json:"channel"` + Nil FlexInt `json:"nil"` + } + + // test unmarshalling the custom type three times with different values. + a.Nil(json.Unmarshal([]byte(`{"five": "5", "seven": 7, "auto": "auto", "nil": null}`), &r)) + // test number in string. + a.EqualValues(five, r.Five.Val) + a.EqualValues("5", r.Five.Txt) + // test number. + a.EqualValues(seven, r.Seven.Val) + a.EqualValues("7", r.Seven.Txt) + // test string. + a.EqualValues(0, r.Auto.Val) + a.EqualValues("auto", r.Auto.Txt) + // test (error) struct. + a.NotNil(json.Unmarshal([]byte(`{"channel": {}}`), &r), + "a non-string and non-number must produce an error.") + a.EqualValues(0, r.Channel.Val) + // test null. + a.EqualValues(0, r.Nil.Val) + a.EqualValues("0", r.Nil.Txt) +} diff --git a/core/unifi/v4/uap.go b/core/unifi/v4/uap.go new file mode 100644 index 00000000..172504b8 --- /dev/null +++ b/core/unifi/v4/uap.go @@ -0,0 +1,566 @@ +package unifi + +import ( + "encoding/json" + "time" +) + +// UAP represents all the data from the Ubiquiti Controller for a Unifi Access Point. +// This was auto generated then edited by hand to get all the data types right. +type UAP struct { + SourceName string `json:"-"` + ID string `json:"_id"` + Adopted FlexBool `json:"adopted"` + AntennaTable []struct { + Default FlexBool `json:"default"` + ID FlexInt `json:"id"` + Name string `json:"name"` + Wifi0Gain FlexInt `json:"wifi0_gain"` + Wifi1Gain FlexInt `json:"wifi1_gain"` + } `json:"antenna_table"` + BandsteeringMode string `json:"bandsteering_mode,omitempty"` + BoardRev int `json:"board_rev"` + Cfgversion string `json:"cfgversion"` + ConfigNetwork struct { + Type string `json:"type"` + IP string `json:"ip"` + } `json:"config_network"` + CountrycodeTable []int `json:"countrycode_table"` + EthernetTable []struct { + Mac string `json:"mac"` + NumPort FlexInt `json:"num_port"` + Name string `json:"name"` + } `json:"ethernet_table"` + FwCaps int `json:"fw_caps"` + HasEth1 FlexBool `json:"has_eth1"` + HasSpeaker FlexBool `json:"has_speaker"` + InformIP string `json:"inform_ip"` + InformURL string `json:"inform_url"` + IP string `json:"ip"` + LedOverride string `json:"led_override"` + Mac string `json:"mac"` + MeshStaVapEnabled FlexBool `json:"mesh_sta_vap_enabled"` + Model string `json:"model"` + Name string `json:"name"` + OutdoorModeOverride string `json:"outdoor_mode_override"` + PortTable []Port `json:"port_table"` + RadioTable RadioTable `json:"radio_table"` + ScanRadioTable []interface{} `json:"scan_radio_table"` + Serial string `json:"serial"` + SiteID string `json:"site_id"` + SiteName string `json:"-"` + Type string `json:"type"` + Version string `json:"version"` + VwireTable []interface{} `json:"vwire_table"` + WifiCaps int `json:"wifi_caps"` + WlangroupIDNa string `json:"wlangroup_id_na"` + WlangroupIDNg string `json:"wlangroup_id_ng"` + RequiredVersion string `json:"required_version"` + HwCaps int `json:"hw_caps"` + Unsupported FlexBool `json:"unsupported"` + UnsupportedReason FlexInt `json:"unsupported_reason"` + SysErrorCaps int `json:"sys_error_caps"` + HasFan FlexBool `json:"has_fan"` + HasTemperature FlexBool `json:"has_temperature"` + DeviceID string `json:"device_id"` + State int `json:"state"` + LastSeen FlexInt `json:"last_seen"` + Upgradable FlexBool `json:"upgradable"` + AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` + Rollupgrade FlexBool `json:"rollupgrade"` + KnownCfgversion string `json:"known_cfgversion"` + Uptime FlexInt `json:"uptime"` + UUptime FlexInt `json:"_uptime"` + Locating FlexBool `json:"locating"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + SysStats SysStats `json:"sys_stats"` + SystemStats SystemStats `json:"system-stats"` + SSHSessionTable []interface{} `json:"ssh_session_table"` + Scanning FlexBool `json:"scanning"` + SpectrumScanning FlexBool `json:"spectrum_scanning"` + GuestToken string `json:"guest_token"` + Meshv3PeerMac string `json:"meshv3_peer_mac"` + Satisfaction FlexInt `json:"satisfaction"` + Isolated FlexBool `json:"isolated"` + RadioTableStats RadioTableStats `json:"radio_table_stats"` + Uplink struct { + FullDuplex FlexBool `json:"full_duplex"` + IP string `json:"ip"` + Mac string `json:"mac"` + MaxVlan int `json:"max_vlan"` + Name string `json:"name"` + Netmask string `json:"netmask"` + NumPort int `json:"num_port"` + RxBytes FlexInt `json:"rx_bytes"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxMulticast FlexInt `json:"rx_multicast"` + RxPackets FlexInt `json:"rx_packets"` + Speed FlexInt `json:"speed"` + TxBytes FlexInt `json:"tx_bytes"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxPackets FlexInt `json:"tx_packets"` + Up FlexBool `json:"up"` + MaxSpeed FlexInt `json:"max_speed"` + Type string `json:"type"` + TxBytesR FlexInt `json:"tx_bytes-r"` + RxBytesR FlexInt `json:"rx_bytes-r"` + UplinkMac string `json:"uplink_mac"` + UplinkRemotePort int `json:"uplink_remote_port"` + } `json:"uplink"` + VapTable VapTable `json:"vap_table"` + DownlinkTable []struct { + PortIdx int `json:"port_idx"` + Speed int `json:"speed"` + FullDuplex bool `json:"full_duplex"` + Mac string `json:"mac"` + } `json:"downlink_table,omitempty"` + VwireVapTable []interface{} `json:"vwire_vap_table"` + BytesD FlexInt `json:"bytes-d"` + TxBytesD FlexInt `json:"tx_bytes-d"` + RxBytesD FlexInt `json:"rx_bytes-d"` + BytesR FlexInt `json:"bytes-r"` + LastUplink struct { + UplinkMac string `json:"uplink_mac"` + UplinkRemotePort int `json:"uplink_remote_port"` + } `json:"last_uplink"` + Stat UAPStat `json:"stat"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + VwireEnabled FlexBool `json:"vwireEnabled"` + UplinkTable []interface{} `json:"uplink_table"` + NumSta FlexInt `json:"num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` + TwoPhaseAdopt FlexBool `json:"two_phase_adopt,omitempty"` +} + +// UAPStat holds the "stat" data for an access point. +// This is split out because of a JSON data format change from 5.10 to 5.11. +type UAPStat struct { + *Ap +} + +// Ap is a subtype of UAPStat to make unmarshalling of different controller versions possible. +type Ap struct { + SiteID string `json:"site_id"` + O string `json:"o"` + Oid string `json:"oid"` + Ap string `json:"ap"` + Time FlexInt `json:"time"` + Datetime time.Time `json:"datetime"` + Bytes FlexInt `json:"bytes"` + Duration FlexInt `json:"duration"` + WifiTxDropped FlexInt `json:"wifi_tx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxDropped FlexInt `json:"rx_dropped"` + RxFrags FlexInt `json:"rx_frags"` + RxCrypts FlexInt `json:"rx_crypts"` + TxPackets FlexInt `json:"tx_packets"` + TxBytes FlexInt `json:"tx_bytes"` + TxErrors FlexInt `json:"tx_errors"` + TxDropped FlexInt `json:"tx_dropped"` + TxRetries FlexInt `json:"tx_retries"` + RxPackets FlexInt `json:"rx_packets"` + RxBytes FlexInt `json:"rx_bytes"` + UserRxDropped FlexInt `json:"user-rx_dropped"` + GuestRxDropped FlexInt `json:"guest-rx_dropped"` + UserRxErrors FlexInt `json:"user-rx_errors"` + GuestRxErrors FlexInt `json:"guest-rx_errors"` + UserRxPackets FlexInt `json:"user-rx_packets"` + GuestRxPackets FlexInt `json:"guest-rx_packets"` + UserRxBytes FlexInt `json:"user-rx_bytes"` + GuestRxBytes FlexInt `json:"guest-rx_bytes"` + UserRxCrypts FlexInt `json:"user-rx_crypts"` + GuestRxCrypts FlexInt `json:"guest-rx_crypts"` + UserRxFrags FlexInt `json:"user-rx_frags"` + GuestRxFrags FlexInt `json:"guest-rx_frags"` + UserTxPackets FlexInt `json:"user-tx_packets"` + GuestTxPackets FlexInt `json:"guest-tx_packets"` + UserTxBytes FlexInt `json:"user-tx_bytes"` + GuestTxBytes FlexInt `json:"guest-tx_bytes"` + UserTxErrors FlexInt `json:"user-tx_errors"` + GuestTxErrors FlexInt `json:"guest-tx_errors"` + UserTxDropped FlexInt `json:"user-tx_dropped"` + GuestTxDropped FlexInt `json:"guest-tx_dropped"` + UserTxRetries FlexInt `json:"user-tx_retries"` + GuestTxRetries FlexInt `json:"guest-tx_retries"` + MacFilterRejections FlexInt `json:"mac_filter_rejections"` + UserMacFilterRejections FlexInt `json:"user-mac_filter_rejections"` + GuestMacFilterRejections FlexInt `json:"guest-mac_filter_rejections"` + WifiTxAttempts FlexInt `json:"wifi_tx_attempts"` + UserWifiTxDropped FlexInt `json:"user-wifi_tx_dropped"` + GuestWifiTxDropped FlexInt `json:"guest-wifi_tx_dropped"` + UserWifiTxAttempts FlexInt `json:"user-wifi_tx_attempts"` + GuestWifiTxAttempts FlexInt `json:"guest-wifi_tx_attempts"` + + // UAP-AC-PRO names, others may differ. + /* These are all in VAP TABLE */ + /* + GuestWifi0RxPackets FlexInt `json:"guest-wifi0-rx_packets"` + GuestWifi1RxPackets FlexInt `json:"guest-wifi1-rx_packets"` + UserWifi1RxPackets FlexInt `json:"user-wifi1-rx_packets"` + UserWifi0RxPackets FlexInt `json:"user-wifi0-rx_packets"` + Wifi0RxPackets FlexInt `json:"wifi0-rx_packets"` + Wifi1RxPackets FlexInt `json:"wifi1-rx_packets"` + GuestWifi0RxBytes FlexInt `json:"guest-wifi0-rx_bytes"` + GuestWifi1RxBytes FlexInt `json:"guest-wifi1-rx_bytes"` + UserWifi1RxBytes FlexInt `json:"user-wifi1-rx_bytes"` + UserWifi0RxBytes FlexInt `json:"user-wifi0-rx_bytes"` + Wifi0RxBytes FlexInt `json:"wifi0-rx_bytes"` + Wifi1RxBytes FlexInt `json:"wifi1-rx_bytes"` + GuestWifi0RxErrors FlexInt `json:"guest-wifi0-rx_errors"` + GuestWifi1RxErrors FlexInt `json:"guest-wifi1-rx_errors"` + UserWifi1RxErrors FlexInt `json:"user-wifi1-rx_errors"` + UserWifi0RxErrors FlexInt `json:"user-wifi0-rx_errors"` + Wifi0RxErrors FlexInt `json:"wifi0-rx_errors"` + Wifi1RxErrors FlexInt `json:"wifi1-rx_errors"` + GuestWifi0RxDropped FlexInt `json:"guest-wifi0-rx_dropped"` + GuestWifi1RxDropped FlexInt `json:"guest-wifi1-rx_dropped"` + UserWifi1RxDropped FlexInt `json:"user-wifi1-rx_dropped"` + UserWifi0RxDropped FlexInt `json:"user-wifi0-rx_dropped"` + Wifi0RxDropped FlexInt `json:"wifi0-rx_dropped"` + Wifi1RxDropped FlexInt `json:"wifi1-rx_dropped"` + GuestWifi0RxCrypts FlexInt `json:"guest-wifi0-rx_crypts"` + GuestWifi1RxCrypts FlexInt `json:"guest-wifi1-rx_crypts"` + UserWifi1RxCrypts FlexInt `json:"user-wifi1-rx_crypts"` + UserWifi0RxCrypts FlexInt `json:"user-wifi0-rx_crypts"` + Wifi0RxCrypts FlexInt `json:"wifi0-rx_crypts"` + Wifi1RxCrypts FlexInt `json:"wifi1-rx_crypts"` + GuestWifi0RxFrags FlexInt `json:"guest-wifi0-rx_frags"` + GuestWifi1RxFrags FlexInt `json:"guest-wifi1-rx_frags"` + UserWifi1RxFrags FlexInt `json:"user-wifi1-rx_frags"` + UserWifi0RxFrags FlexInt `json:"user-wifi0-rx_frags"` + Wifi0RxFrags FlexInt `json:"wifi0-rx_frags"` + Wifi1RxFrags FlexInt `json:"wifi1-rx_frags"` + GuestWifi0TxPackets FlexInt `json:"guest-wifi0-tx_packets"` + GuestWifi1TxPackets FlexInt `json:"guest-wifi1-tx_packets"` + UserWifi1TxPackets FlexInt `json:"user-wifi1-tx_packets"` + UserWifi0TxPackets FlexInt `json:"user-wifi0-tx_packets"` + Wifi0TxPackets FlexInt `json:"wifi0-tx_packets"` + Wifi1TxPackets FlexInt `json:"wifi1-tx_packets"` + GuestWifi0TxBytes FlexInt `json:"guest-wifi0-tx_bytes"` + GuestWifi1TxBytes FlexInt `json:"guest-wifi1-tx_bytes"` + UserWifi1TxBytes FlexInt `json:"user-wifi1-tx_bytes"` + UserWifi0TxBytes FlexInt `json:"user-wifi0-tx_bytes"` + Wifi0TxBytes FlexInt `json:"wifi0-tx_bytes"` + Wifi1TxBytes FlexInt `json:"wifi1-tx_bytes"` + GuestWifi0TxErrors FlexInt `json:"guest-wifi0-tx_errors"` + GuestWifi1TxErrors FlexInt `json:"guest-wifi1-tx_errors"` + UserWifi1TxErrors FlexInt `json:"user-wifi1-tx_errors"` + UserWifi0TxErrors FlexInt `json:"user-wifi0-tx_errors"` + Wifi0TxErrors FlexInt `json:"wifi0-tx_errors"` + Wifi1TxErrors FlexInt `json:"wifi1-tx_errors"` + GuestWifi0TxDropped FlexInt `json:"guest-wifi0-tx_dropped"` + GuestWifi1TxDropped FlexInt `json:"guest-wifi1-tx_dropped"` + UserWifi1TxDropped FlexInt `json:"user-wifi1-tx_dropped"` + UserWifi0TxDropped FlexInt `json:"user-wifi0-tx_dropped"` + Wifi0TxDropped FlexInt `json:"wifi0-tx_dropped"` + Wifi1TxDropped FlexInt `json:"wifi1-tx_dropped"` + GuestWifi0TxRetries FlexInt `json:"guest-wifi0-tx_retries"` + GuestWifi1TxRetries FlexInt `json:"guest-wifi1-tx_retries"` + UserWifi1TxRetries FlexInt `json:"user-wifi1-tx_retries"` + UserWifi0TxRetries FlexInt `json:"user-wifi0-tx_retries"` + Wifi0TxRetries FlexInt `json:"wifi0-tx_retries"` + Wifi1TxRetries FlexInt `json:"wifi1-tx_retries"` + GuestWifi0MacFilterRejections FlexInt `json:"guest-wifi0-mac_filter_rejections"` + GuestWifi1MacFilterRejections FlexInt `json:"guest-wifi1-mac_filter_rejections"` + UserWifi1MacFilterRejections FlexInt `json:"user-wifi1-mac_filter_rejections"` + UserWifi0MacFilterRejections FlexInt `json:"user-wifi0-mac_filter_rejections"` + Wifi0MacFilterRejections FlexInt `json:"wifi0-mac_filter_rejections"` + Wifi1MacFilterRejections FlexInt `json:"wifi1-mac_filter_rejections"` + GuestWifi0WifiTxAttempts FlexInt `json:"guest-wifi0-wifi_tx_attempts"` + GuestWifi1WifiTxAttempts FlexInt `json:"guest-wifi1-wifi_tx_attempts"` + UserWifi1WifiTxAttempts FlexInt `json:"user-wifi1-wifi_tx_attempts"` + UserWifi0WifiTxAttempts FlexInt `json:"user-wifi0-wifi_tx_attempts"` + Wifi0WifiTxAttempts FlexInt `json:"wifi0-wifi_tx_attempts"` + Wifi1WifiTxAttempts FlexInt `json:"wifi1-wifi_tx_attempts"` + GuestWifi0WifiTxDropped FlexInt `json:"guest-wifi0-wifi_tx_dropped"` + GuestWifi1WifiTxDropped FlexInt `json:"guest-wifi1-wifi_tx_dropped"` + UserWifi1WifiTxDropped FlexInt `json:"user-wifi1-wifi_tx_dropped"` + UserWifi0WifiTxDropped FlexInt `json:"user-wifi0-wifi_tx_dropped"` + Wifi0WifiTxDropped FlexInt `json:"wifi0-wifi_tx_dropped"` + Wifi1WifiTxDropped FlexInt `json:"wifi1-wifi_tx_dropped"` + // UDM Names + GuestRa0RxPackets FlexInt `json:"guest-ra0-rx_packets"` + UserRa0RxPackets FlexInt `json:"user-ra0-rx_packets"` + Ra0RxPackets FlexInt `json:"ra0-rx_packets"` + GuestRa0RxBytes FlexInt `json:"guest-ra0-rx_bytes"` + UserRa0RxBytes FlexInt `json:"user-ra0-rx_bytes"` + Ra0RxBytes FlexInt `json:"ra0-rx_bytes"` + GuestRa0RxErrors FlexInt `json:"guest-ra0-rx_errors"` + UserRa0RxErrors FlexInt `json:"user-ra0-rx_errors"` + Ra0RxErrors FlexInt `json:"ra0-rx_errors"` + GuestRa0RxDropped FlexInt `json:"guest-ra0-rx_dropped"` + UserRa0RxDropped FlexInt `json:"user-ra0-rx_dropped"` + Ra0RxDropped FlexInt `json:"ra0-rx_dropped"` + GuestRa0RxCrypts FlexInt `json:"guest-ra0-rx_crypts"` + UserRa0RxCrypts FlexInt `json:"user-ra0-rx_crypts"` + Ra0RxCrypts FlexInt `json:"ra0-rx_crypts"` + GuestRa0RxFrags FlexInt `json:"guest-ra0-rx_frags"` + UserRa0RxFrags FlexInt `json:"user-ra0-rx_frags"` + Ra0RxFrags FlexInt `json:"ra0-rx_frags"` + GuestRa0TxPackets FlexInt `json:"guest-ra0-tx_packets"` + UserRa0TxPackets FlexInt `json:"user-ra0-tx_packets"` + Ra0TxPackets FlexInt `json:"ra0-tx_packets"` + GuestRa0TxBytes FlexInt `json:"guest-ra0-tx_bytes"` + UserRa0TxBytes FlexInt `json:"user-ra0-tx_bytes"` + Ra0TxBytes FlexInt `json:"ra0-tx_bytes"` + GuestRa0TxErrors FlexInt `json:"guest-ra0-tx_errors"` + UserRa0TxErrors FlexInt `json:"user-ra0-tx_errors"` + Ra0TxErrors FlexInt `json:"ra0-tx_errors"` + GuestRa0TxDropped FlexInt `json:"guest-ra0-tx_dropped"` + UserRa0TxDropped FlexInt `json:"user-ra0-tx_dropped"` + Ra0TxDropped FlexInt `json:"ra0-tx_dropped"` + GuestRa0TxRetries FlexInt `json:"guest-ra0-tx_retries"` + UserRa0TxRetries FlexInt `json:"user-ra0-tx_retries"` + Ra0TxRetries FlexInt `json:"ra0-tx_retries"` + GuestRa0MacFilterRejections FlexInt `json:"guest-ra0-mac_filter_rejections"` + UserRa0MacFilterRejections FlexInt `json:"user-ra0-mac_filter_rejections"` + Ra0MacFilterRejections FlexInt `json:"ra0-mac_filter_rejections"` + GuestRa0WifiTxAttempts FlexInt `json:"guest-ra0-wifi_tx_attempts"` + UserRa0WifiTxAttempts FlexInt `json:"user-ra0-wifi_tx_attempts"` + Ra0WifiTxAttempts FlexInt `json:"ra0-wifi_tx_attempts"` + GuestRa0WifiTxDropped FlexInt `json:"guest-ra0-wifi_tx_dropped"` + UserRa0WifiTxDropped FlexInt `json:"user-ra0-wifi_tx_dropped"` + Ra0WifiTxDropped FlexInt `json:"ra0-wifi_tx_dropped"` + GuestRai0RxPackets FlexInt `json:"guest-rai0-rx_packets"` + UserRai0RxPackets FlexInt `json:"user-rai0-rx_packets"` + Rai0RxPackets FlexInt `json:"rai0-rx_packets"` + GuestRai0RxBytes FlexInt `json:"guest-rai0-rx_bytes"` + UserRai0RxBytes FlexInt `json:"user-rai0-rx_bytes"` + Rai0RxBytes FlexInt `json:"rai0-rx_bytes"` + GuestRai0RxErrors FlexInt `json:"guest-rai0-rx_errors"` + UserRai0RxErrors FlexInt `json:"user-rai0-rx_errors"` + Rai0RxErrors FlexInt `json:"rai0-rx_errors"` + GuestRai0RxDropped FlexInt `json:"guest-rai0-rx_dropped"` + UserRai0RxDropped FlexInt `json:"user-rai0-rx_dropped"` + Rai0RxDropped FlexInt `json:"rai0-rx_dropped"` + GuestRai0RxCrypts FlexInt `json:"guest-rai0-rx_crypts"` + UserRai0RxCrypts FlexInt `json:"user-rai0-rx_crypts"` + Rai0RxCrypts FlexInt `json:"rai0-rx_crypts"` + GuestRai0RxFrags FlexInt `json:"guest-rai0-rx_frags"` + UserRai0RxFrags FlexInt `json:"user-rai0-rx_frags"` + Rai0RxFrags FlexInt `json:"rai0-rx_frags"` + GuestRai0TxPackets FlexInt `json:"guest-rai0-tx_packets"` + UserRai0TxPackets FlexInt `json:"user-rai0-tx_packets"` + Rai0TxPackets FlexInt `json:"rai0-tx_packets"` + GuestRai0TxBytes FlexInt `json:"guest-rai0-tx_bytes"` + UserRai0TxBytes FlexInt `json:"user-rai0-tx_bytes"` + Rai0TxBytes FlexInt `json:"rai0-tx_bytes"` + GuestRai0TxErrors FlexInt `json:"guest-rai0-tx_errors"` + UserRai0TxErrors FlexInt `json:"user-rai0-tx_errors"` + Rai0TxErrors FlexInt `json:"rai0-tx_errors"` + GuestRai0TxDropped FlexInt `json:"guest-rai0-tx_dropped"` + UserRai0TxDropped FlexInt `json:"user-rai0-tx_dropped"` + Rai0TxDropped FlexInt `json:"rai0-tx_dropped"` + GuestRai0TxRetries FlexInt `json:"guest-rai0-tx_retries"` + UserRai0TxRetries FlexInt `json:"user-rai0-tx_retries"` + Rai0TxRetries FlexInt `json:"rai0-tx_retries"` + GuestRai0MacFilterRejections FlexInt `json:"guest-rai0-mac_filter_rejections"` + UserRai0MacFilterRejections FlexInt `json:"user-rai0-mac_filter_rejections"` + Rai0MacFilterRejections FlexInt `json:"rai0-mac_filter_rejections"` + GuestRai0WifiTxAttempts FlexInt `json:"guest-rai0-wifi_tx_attempts"` + UserRai0WifiTxAttempts FlexInt `json:"user-rai0-wifi_tx_attempts"` + Rai0WifiTxAttempts FlexInt `json:"rai0-wifi_tx_attempts"` + GuestRai0WifiTxDropped FlexInt `json:"guest-rai0-wifi_tx_dropped"` + UserRai0WifiTxDropped FlexInt `json:"user-rai0-wifi_tx_dropped"` + Rai0WifiTxDropped FlexInt `json:"rai0-wifi_tx_dropped"` + */ +} + +// RadioTable is part of the data for UAPs and UDMs. +type RadioTable []struct { + AntennaGain FlexInt `json:"antenna_gain"` + BuiltinAntGain FlexInt `json:"builtin_ant_gain"` + BuiltinAntenna FlexBool `json:"builtin_antenna"` + Channel FlexInt `json:"channel"` + CurrentAntennaGain FlexInt `json:"current_antenna_gain"` + HasDfs FlexBool `json:"has_dfs"` + HasFccdfs FlexBool `json:"has_fccdfs"` + HasHt160 FlexBool `json:"has_ht160"` + Ht FlexInt `json:"ht"` + Is11Ac FlexBool `json:"is_11ac"` + MaxTxpower FlexInt `json:"max_txpower"` + MinRssi FlexInt `json:"min_rssi,omitempty"` + MinRssiEnabled FlexBool `json:"min_rssi_enabled"` + MinTxpower FlexInt `json:"min_txpower"` + Name string `json:"name"` + Nss FlexInt `json:"nss"` + Radio string `json:"radio"` + RadioCaps FlexInt `json:"radio_caps"` + SensLevelEnabled FlexBool `json:"sens_level_enabled"` + TxPower FlexInt `json:"tx_power"` + TxPowerMode string `json:"tx_power_mode"` + VwireEnabled FlexBool `json:"vwire_enabled"` + WlangroupID string `json:"wlangroup_id"` +} + +// RadioTableStats is part of the data shared between UAP and UDM +type RadioTableStats []struct { + Name string `json:"name"` + Channel FlexInt `json:"channel"` + Radio string `json:"radio"` + AstTxto interface{} `json:"ast_txto"` + AstCst interface{} `json:"ast_cst"` + AstBeXmit FlexInt `json:"ast_be_xmit"` + CuTotal FlexInt `json:"cu_total"` + CuSelfRx FlexInt `json:"cu_self_rx"` + CuSelfTx FlexInt `json:"cu_self_tx"` + Gain FlexInt `json:"gain"` + Satisfaction FlexInt `json:"satisfaction"` + State string `json:"state"` + Extchannel FlexInt `json:"extchannel"` + TxPower FlexInt `json:"tx_power"` + TxPackets FlexInt `json:"tx_packets"` + TxRetries FlexInt `json:"tx_retries"` + NumSta FlexInt `json:"num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` +} + +// VapTable holds much of the UAP wireless data. Shared by UDM. +type VapTable []struct { + AnomaliesBarChart struct { + HighDNSLatency FlexInt `json:"high_dns_latency"` + HighTCPLatency FlexInt `json:"high_tcp_latency"` + HighTCPPacketLoss FlexInt `json:"high_tcp_packet_loss"` + HighWifiLatency FlexInt `json:"high_wifi_latency"` + HighWifiRetries FlexInt `json:"high_wifi_retries"` + LowPhyRate FlexInt `json:"low_phy_rate"` + PoorStreamEff FlexInt `json:"poor_stream_eff"` + SleepyClient FlexInt `json:"sleepy_client"` + StaArpTimeout FlexInt `json:"sta_arp_timeout"` + StaDNSTimeout FlexInt `json:"sta_dns_timeout"` + StaIPTimeout FlexInt `json:"sta_ip_timeout"` + WeakSignal FlexInt `json:"weak_signal"` + } `json:"anomalies_bar_chart"` + AnomaliesBarChartNow struct { + HighDNSLatency FlexInt `json:"high_dns_latency"` + HighTCPLatency FlexInt `json:"high_tcp_latency"` + HighTCPPacketLoss FlexInt `json:"high_tcp_packet_loss"` + HighWifiLatency FlexInt `json:"high_wifi_latency"` + HighWifiRetries FlexInt `json:"high_wifi_retries"` + LowPhyRate FlexInt `json:"low_phy_rate"` + PoorStreamEff FlexInt `json:"poor_stream_eff"` + SleepyClient FlexInt `json:"sleepy_client"` + StaArpTimeout FlexInt `json:"sta_arp_timeout"` + StaDNSTimeout FlexInt `json:"sta_dns_timeout"` + StaIPTimeout FlexInt `json:"sta_ip_timeout"` + WeakSignal FlexInt `json:"weak_signal"` + } `json:"anomalies_bar_chart_now"` + ReasonsBarChart struct { + PhyRate FlexInt `json:"phy_rate"` + Signal FlexInt `json:"signal"` + SleepyClient FlexInt `json:"sleepy_client"` + StaArpTimeout FlexInt `json:"sta_arp_timeout"` + StaDNSLatency FlexInt `json:"sta_dns_latency"` + StaDNSTimeout FlexInt `json:"sta_dns_timeout"` + StaIPTimeout FlexInt `json:"sta_ip_timeout"` + StreamEff FlexInt `json:"stream_eff"` + TCPLatency FlexInt `json:"tcp_latency"` + TCPPacketLoss FlexInt `json:"tcp_packet_loss"` + WifiLatency FlexInt `json:"wifi_latency"` + WifiRetries FlexInt `json:"wifi_retries"` + } `json:"reasons_bar_chart"` + ReasonsBarChartNow struct { + PhyRate FlexInt `json:"phy_rate"` + Signal FlexInt `json:"signal"` + SleepyClient FlexInt `json:"sleepy_client"` + StaArpTimeout FlexInt `json:"sta_arp_timeout"` + StaDNSLatency FlexInt `json:"sta_dns_latency"` + StaDNSTimeout FlexInt `json:"sta_dns_timeout"` + StaIPTimeout FlexInt `json:"sta_ip_timeout"` + StreamEff FlexInt `json:"stream_eff"` + TCPLatency FlexInt `json:"tcp_latency"` + TCPPacketLoss FlexInt `json:"tcp_packet_loss"` + WifiLatency FlexInt `json:"wifi_latency"` + WifiRetries FlexInt `json:"wifi_retries"` + } `json:"reasons_bar_chart_now"` + RxTCPStats struct { + Goodbytes FlexInt `json:"goodbytes"` + LatAvg FlexInt `json:"lat_avg"` + LatMax FlexInt `json:"lat_max"` + LatMin FlexInt `json:"lat_min"` + Stalls FlexInt `json:"stalls"` + } `json:"rx_tcp_stats"` + TxTCPStats struct { + Goodbytes FlexInt `json:"goodbytes"` + LatAvg FlexInt `json:"lat_avg"` + LatMax FlexInt `json:"lat_max"` + LatMin FlexInt `json:"lat_min"` + Stalls FlexInt `json:"stalls"` + } `json:"tx_tcp_stats"` + WifiTxLatencyMov struct { + Avg FlexInt `json:"avg"` + Max FlexInt `json:"max"` + Min FlexInt `json:"min"` + Total FlexInt `json:"total"` + TotalCount FlexInt `json:"total_count"` + } `json:"wifi_tx_latency_mov"` + ApMac string `json:"ap_mac"` + AvgClientSignal FlexInt `json:"avg_client_signal"` + Bssid string `json:"bssid"` + Ccq int `json:"ccq"` + Channel FlexInt `json:"channel"` + DNSAvgLatency FlexInt `json:"dns_avg_latency"` + Essid string `json:"essid"` + Extchannel int `json:"extchannel"` + ID string `json:"id"` + IsGuest FlexBool `json:"is_guest"` + IsWep FlexBool `json:"is_wep"` + MacFilterRejections int `json:"mac_filter_rejections"` + MapID interface{} `json:"map_id"` + Name string `json:"name"` + NumSatisfactionSta FlexInt `json:"num_satisfaction_sta"` + NumSta int `json:"num_sta"` + Radio string `json:"radio"` + RadioName string `json:"radio_name"` + RxBytes FlexInt `json:"rx_bytes"` + RxCrypts FlexInt `json:"rx_crypts"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxFrags FlexInt `json:"rx_frags"` + RxNwids FlexInt `json:"rx_nwids"` + RxPackets FlexInt `json:"rx_packets"` + Satisfaction FlexInt `json:"satisfaction"` + SatisfactionNow FlexInt `json:"satisfaction_now"` + SiteID string `json:"site_id"` + State string `json:"state"` + T string `json:"t"` + TxBytes FlexInt `json:"tx_bytes"` + TxCombinedRetries FlexInt `json:"tx_combined_retries"` + TxDataMpduBytes FlexInt `json:"tx_data_mpdu_bytes"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxPackets FlexInt `json:"tx_packets"` + TxPower FlexInt `json:"tx_power"` + TxRetries FlexInt `json:"tx_retries"` + TxRtsRetries FlexInt `json:"tx_rts_retries"` + TxSuccess FlexInt `json:"tx_success"` + TxTotal FlexInt `json:"tx_total"` + Up FlexBool `json:"up"` + Usage string `json:"usage"` + WifiTxAttempts FlexInt `json:"wifi_tx_attempts"` + WifiTxDropped FlexInt `json:"wifi_tx_dropped"` + WlanconfID string `json:"wlanconf_id"` +} + +// UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Access Point Stat data. +func (v *UAPStat) UnmarshalJSON(data []byte) error { + var n struct { + Ap `json:"ap"` + } + + v.Ap = &n.Ap + + err := json.Unmarshal(data, v.Ap) // controller version 5.10. + if err != nil { + return json.Unmarshal(data, &n) // controller version 5.11. + } + + return nil +} diff --git a/core/unifi/v4/uap_test.go b/core/unifi/v4/uap_test.go new file mode 100644 index 00000000..155b3539 --- /dev/null +++ b/core/unifi/v4/uap_test.go @@ -0,0 +1,53 @@ +package unifi + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestUAPUnmarshalJSON(t *testing.T) { + testcontroller511 := `{ + "ap": { + "site_id": "mySite", + "o": "ap", + "oid": "00:00:00:00:00:00", + "ap": "00:00:00:00:00:00", + "time": 1577742600000, + "datetime": "2019-12-30T09:50:00Z", + "user-wifi1-rx_packets": 6596670, + "user-wifi0-rx_packets": 42659527, + "user-rx_packets": 49294197, + "guest-rx_packets": 0, + "wifi0-rx_packets": 42639527, + "wifi1-rx_packets": 6591670, + "rx_packets": 49299197}}` + + testcontroller510 := `{ + "site_id": "mySite", + "o": "ap", + "oid": "00:00:00:00:00:00", + "ap": "00:00:00:00:00:00", + "time": 1577742600000, + "datetime": "2019-12-30T09:50:00Z", + "user-wifi1-rx_packets": 6596670, + "user-wifi0-rx_packets": 42659527, + "user-rx_packets": 49294197, + "guest-rx_packets": 0, + "wifi0-rx_packets": 42639527, + "wifi1-rx_packets": 6591670, + "rx_packets": 49299197}` + + t.Parallel() + a := assert.New(t) + rxPakcets := 49299197 + u := &UAPStat{} + err := u.UnmarshalJSON([]byte(testcontroller510)) + a.Nil(err, "must be no error unmarshaling test strings") + a.Equal(float64(rxPakcets), u.RxPackets.Val, "data was not properly unmarshaled") + + u = &UAPStat{} // reset + err = u.UnmarshalJSON([]byte(testcontroller511)) + a.Nil(err, "must be no error unmarshaling test strings") + a.Equal(float64(rxPakcets), u.RxPackets.Val, "data was not properly unmarshaled") +} diff --git a/core/unifi/v4/udm.go b/core/unifi/v4/udm.go new file mode 100644 index 00000000..16842809 --- /dev/null +++ b/core/unifi/v4/udm.go @@ -0,0 +1,183 @@ +package unifi + +// UDM represents all the data from the Ubiquiti Controller for a Unifi Dream Machine. +// The UDM shares several structs/type-data with USW and USG. +type UDM struct { + SourceName string `json:"-"` + SiteID string `json:"site_id"` + SiteName string `json:"-"` + Mac string `json:"mac"` + Adopted FlexBool `json:"adopted"` + Serial string `json:"serial"` + IP string `json:"ip"` + Uptime FlexInt `json:"uptime"` + Model string `json:"model"` + Version string `json:"version"` + Name string `json:"name"` + Default FlexBool `json:"default"` + Locating FlexBool `json:"locating"` + Type string `json:"type"` + Unsupported FlexBool `json:"unsupported"` + UnsupportedReason FlexInt `json:"unsupported_reason"` + DiscoveredVia string `json:"discovered_via"` + AdoptIP string `json:"adopt_ip"` + AdoptURL string `json:"adopt_url"` + State FlexInt `json:"state"` + AdoptStatus FlexInt `json:"adopt_status"` + UpgradeState FlexInt `json:"upgrade_state"` + LastSeen FlexInt `json:"last_seen"` + AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` + Cfgversion string `json:"cfgversion"` + ConfigNetwork struct { + Type string `json:"type"` + IP string `json:"ip"` + } `json:"config_network"` + VwireTable []interface{} `json:"vwire_table"` + Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"` + JumboframeEnabled FlexBool `json:"jumboframe_enabled"` + FlowctrlEnabled FlexBool `json:"flowctrl_enabled"` + StpVersion string `json:"stp_version"` + StpPriority FlexInt `json:"stp_priority"` + PowerSourceCtrlEnabled FlexBool `json:"power_source_ctrl_enabled"` + LicenseState string `json:"license_state"` + ID string `json:"_id"` + DeviceID string `json:"device_id"` + AdoptState FlexInt `json:"adopt_state"` + AdoptTries FlexInt `json:"adopt_tries"` + AdoptManual FlexBool `json:"adopt_manual"` + InformURL string `json:"inform_url"` + InformIP string `json:"inform_ip"` + RequiredVersion string `json:"required_version"` + BoardRev FlexInt `json:"board_rev"` + EthernetTable []struct { + Mac string `json:"mac"` + NumPort FlexInt `json:"num_port"` + Name string `json:"name"` + } `json:"ethernet_table"` + PortTable []Port `json:"port_table"` + EthernetOverrides []struct { + Ifname string `json:"ifname"` + Networkgroup string `json:"networkgroup"` + } `json:"ethernet_overrides"` + UsgCaps FlexInt `json:"usg_caps"` + HasSpeaker FlexBool `json:"has_speaker"` + HasEth1 FlexBool `json:"has_eth1"` + FwCaps FlexInt `json:"fw_caps"` + HwCaps FlexInt `json:"hw_caps"` + WifiCaps FlexInt `json:"wifi_caps"` + SwitchCaps struct { + MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` + MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` + } `json:"switch_caps"` + HasFan FlexBool `json:"has_fan"` + HasTemperature FlexBool `json:"has_temperature"` + RulesetInterfaces interface{} `json:"ruleset_interfaces"` + /* struct { + Br0 string `json:"br0"` + Eth0 string `json:"eth0"` + Eth1 string `json:"eth1"` + Eth2 string `json:"eth2"` + Eth3 string `json:"eth3"` + Eth4 string `json:"eth4"` + Eth5 string `json:"eth5"` + Eth6 string `json:"eth6"` + Eth7 string `json:"eth7"` + Eth8 string `json:"eth8"` + } */ + KnownCfgversion string `json:"known_cfgversion"` + SysStats SysStats `json:"sys_stats"` + SystemStats SystemStats `json:"system-stats"` + GuestToken string `json:"guest_token"` + Overheating FlexBool `json:"overheating"` + SpeedtestStatus SpeedtestStatus `json:"speedtest-status"` + SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"` + Wan1 Wan `json:"wan1"` + Wan2 Wan `json:"wan2"` + Uplink Uplink `json:"uplink"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + DownlinkTable []interface{} `json:"downlink_table"` + WlangroupIDNa string `json:"wlangroup_id_na"` + WlangroupIDNg string `json:"wlangroup_id_ng"` + BandsteeringMode string `json:"bandsteering_mode"` + RadioTable *RadioTable `json:"radio_table,omitempty"` + RadioTableStats *RadioTableStats `json:"radio_table_stats,omitempty"` + VapTable *VapTable `json:"vap_table"` + XInformAuthkey string `json:"x_inform_authkey"` + NetworkTable NetworkTable `json:"network_table"` + PortOverrides []struct { + PortIdx FlexInt `json:"port_idx"` + PortconfID string `json:"portconf_id"` + } `json:"port_overrides"` + Stat UDMStat `json:"stat"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + BytesD FlexInt `json:"bytes-d"` + TxBytesD FlexInt `json:"tx_bytes-d"` + RxBytesD FlexInt `json:"rx_bytes-d"` + BytesR FlexInt `json:"bytes-r"` + NumSta FlexInt `json:"num_sta"` // USG + WlanNumSta FlexInt `json:"wlan-num_sta"` // UAP + LanNumSta FlexInt `json:"lan-num_sta"` // USW + UserWlanNumSta FlexInt `json:"user-wlan-num_sta"` // UAP + UserLanNumSta FlexInt `json:"user-lan-num_sta"` // USW + UserNumSta FlexInt `json:"user-num_sta"` // USG + GuestWlanNumSta FlexInt `json:"guest-wlan-num_sta"` // UAP + GuestLanNumSta FlexInt `json:"guest-lan-num_sta"` // USW + GuestNumSta FlexInt `json:"guest-num_sta"` // USG + NumDesktop FlexInt `json:"num_desktop"` // USG + NumMobile FlexInt `json:"num_mobile"` // USG + NumHandheld FlexInt `json:"num_handheld"` // USG +} + +// NetworkTable is the list of networks on a gateway. +type NetworkTable []struct { + ID string `json:"_id"` + AttrNoDelete FlexBool `json:"attr_no_delete"` + AttrHiddenID string `json:"attr_hidden_id"` + Name string `json:"name"` + SiteID string `json:"site_id"` + VlanEnabled FlexBool `json:"vlan_enabled"` + Purpose string `json:"purpose"` + IPSubnet string `json:"ip_subnet"` + Ipv6InterfaceType string `json:"ipv6_interface_type"` + DomainName string `json:"domain_name"` + IsNat FlexBool `json:"is_nat"` + DhcpdEnabled FlexBool `json:"dhcpd_enabled"` + DhcpdStart string `json:"dhcpd_start"` + DhcpdStop string `json:"dhcpd_stop"` + Dhcpdv6Enabled FlexBool `json:"dhcpdv6_enabled"` + Ipv6RaEnabled FlexBool `json:"ipv6_ra_enabled"` + LteLanEnabled FlexBool `json:"lte_lan_enabled"` + Networkgroup string `json:"networkgroup"` + DhcpdLeasetime FlexInt `json:"dhcpd_leasetime"` + DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"` + DhcpdGatewayEnabled FlexBool `json:"dhcpd_gateway_enabled"` + DhcpdTimeOffsetEnabled FlexBool `json:"dhcpd_time_offset_enabled"` + Ipv6PdStart string `json:"ipv6_pd_start"` + Ipv6PdStop string `json:"ipv6_pd_stop"` + DhcpdDNS1 string `json:"dhcpd_dns_1"` + DhcpdDNS2 string `json:"dhcpd_dns_2"` + DhcpdDNS3 string `json:"dhcpd_dns_3"` + DhcpdDNS4 string `json:"dhcpd_dns_4"` + Enabled FlexBool `json:"enabled"` + DhcpRelayEnabled FlexBool `json:"dhcp_relay_enabled"` + Mac string `json:"mac"` + IsGuest FlexBool `json:"is_guest"` + IP string `json:"ip"` + Up FlexBool `json:"up"` + NumSta FlexInt `json:"num_sta"` + RxBytes FlexInt `json:"rx_bytes"` + RxPackets FlexInt `json:"rx_packets"` + TxBytes FlexInt `json:"tx_bytes"` + TxPackets FlexInt `json:"tx_packets"` +} + +// UDMStat holds the "stat" data for a dream machine. +// A dream machine is a USG + USW + Controller +type UDMStat struct { + *Gw `json:"gw"` + *Sw `json:"sw"` + *Ap `json:"ap,omitempty"` +} diff --git a/core/unifi/v4/unifi.go b/core/unifi/v4/unifi.go new file mode 100644 index 00000000..2b3ba865 --- /dev/null +++ b/core/unifi/v4/unifi.go @@ -0,0 +1,160 @@ +// Package unifi provides a set of types to unload (unmarshal) Ubiquiti UniFi +// controller data. Also provided are methods to easily get data for devices - +// things like access points and switches, and for clients - the things +// connected to those access points and switches. As a bonus, each device and +// client type provided has an attached method to create InfluxDB datapoints. +package unifi + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/http/cookiejar" + "strings" + "time" +) + +// NewUnifi creates a http.Client with authenticated cookies. +// Used to make additional, authenticated requests to the APIs. +// Start here. +func NewUnifi(config *Config) (*Unifi, error) { + jar, err := cookiejar.New(nil) + if err != nil { + return nil, err + } + + config.URL = strings.TrimRight(config.URL, "/") + + if config.ErrorLog == nil { + config.ErrorLog = discardLogs + } + + if config.DebugLog == nil { + config.DebugLog = discardLogs + } + + u := &Unifi{Config: config, + Client: &http.Client{ + Jar: jar, + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: !config.VerifySSL}, + }, + }, + } + if err := u.Login(); err != nil { + return u, err + } + + if err := u.GetServerData(); err != nil { + return u, fmt.Errorf("unable to get server version: %v", err) + } + + return u, nil +} + +// Login is a helper method. It can be called to grab a new authentication cookie. +func (u *Unifi) Login() error { + start := time.Now() + + // magic login. + req, err := u.UniReq(APILoginPath, fmt.Sprintf(`{"username":"%s","password":"%s"}`, u.User, u.Pass)) + if err != nil { + return err + } + + resp, err := u.Do(req) + if err != nil { + return err + } + + defer resp.Body.Close() // we need no data here. + _, _ = io.Copy(ioutil.Discard, resp.Body) // avoid leaking. + u.DebugLog("Requested %s: elapsed %v, returned %d bytes", + APILoginPath, time.Since(start).Round(time.Millisecond), resp.ContentLength) + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("authentication failed (user: %s): %s (status: %s)", + u.User, u.URL+APILoginPath, resp.Status) + } + + return nil +} + +// GetServerData sets the controller's version and UUID. Only call this if you +// previously called Login and suspect the controller version has changed. +func (u *Unifi) GetServerData() error { + var response struct { + Data server `json:"meta"` + } + + u.server = &response.Data + + return u.GetData(APIStatusPath, &response) +} + +// GetData makes a unifi request and unmarshals the response into a provided pointer. +func (u *Unifi) GetData(apiPath string, v interface{}, params ...string) error { + start := time.Now() + + body, err := u.GetJSON(apiPath, params...) + if err != nil { + return err + } + + u.DebugLog("Requested %s: elapsed %v, returned %d bytes", + apiPath, time.Since(start).Round(time.Millisecond), len(body)) + + return json.Unmarshal(body, v) +} + +// UniReq is a small helper function that adds an Accept header. +// Use this if you're unmarshalling UniFi data into custom types. +// And if you're doing that... sumbut a pull request with your new struct. :) +// This is a helper method that is exposed for convenience. +func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err error) { + switch params { + case "": + req, err = http.NewRequest("GET", u.URL+apiPath, nil) + default: + req, err = http.NewRequest("POST", u.URL+apiPath, bytes.NewBufferString(params)) + } + + if err != nil { + return + } + + req.Header.Add("Accept", "application/json") + u.DebugLog("Requesting %s, with params: %v", apiPath, params != "") + + return +} + +// GetJSON returns the raw JSON from a path. This is useful for debugging. +func (u *Unifi) GetJSON(apiPath string, params ...string) ([]byte, error) { + req, err := u.UniReq(apiPath, strings.Join(params, " ")) + if err != nil { + return []byte{}, err + } + + resp, err := u.Do(req) + if err != nil { + return []byte{}, err + } + + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return body, err + } + + if resp.StatusCode != http.StatusOK { + err = fmt.Errorf("invalid status code from server %s", resp.Status) + } + + return body, err +} diff --git a/core/unifi/v4/unifi_test.go b/core/unifi/v4/unifi_test.go new file mode 100644 index 00000000..9c9015fb --- /dev/null +++ b/core/unifi/v4/unifi_test.go @@ -0,0 +1,62 @@ +package unifi + +import ( + "io/ioutil" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewUnifi(t *testing.T) { + t.Parallel() + a := assert.New(t) + u := "http://127.0.0.1:64431" + c := &Config{ + User: "user1", + Pass: "pass2", + URL: u, + VerifySSL: false, + DebugLog: discardLogs, + } + authReq, err := NewUnifi(c) + a.NotNil(err) + a.EqualValues(u, authReq.URL) + a.Contains(err.Error(), "connection refused", "an invalid destination should produce a connection error.") +} + +func TestUniReq(t *testing.T) { + t.Parallel() + a := assert.New(t) + p := "/test/path" + u := "http://some.url:8443" + // Test empty parameters. + authReq := &Unifi{Client: &http.Client{}, Config: &Config{URL: u, DebugLog: discardLogs}} + r, err := authReq.UniReq(p, "") + a.Nil(err, "newrequest must not produce an error") + a.EqualValues(p, r.URL.Path, + "the provided apiPath was not added to http request") + a.EqualValues(u, r.URL.Scheme+"://"+r.URL.Host, "URL improperly encoded") + a.EqualValues("GET", r.Method, "without parameters the method must be GET") + a.EqualValues("application/json", r.Header.Get("Accept"), "Accept header must be set to application/json") + + // Test with parameters + k := "key1=value9&key2=value7" + authReq = &Unifi{Client: &http.Client{}, Config: &Config{URL: "http://some.url:8443", DebugLog: discardLogs}} + r, err = authReq.UniReq(p, k) + a.Nil(err, "newrequest must not produce an error") + a.EqualValues(p, r.URL.Path, + "the provided apiPath was not added to http request") + a.EqualValues(u, r.URL.Scheme+"://"+r.URL.Host, "URL improperly encoded") + a.EqualValues("POST", r.Method, "with parameters the method must be POST") + a.EqualValues("application/json", r.Header.Get("Accept"), "Accept header must be set to application/json") + // Check the parameters. + d, err := ioutil.ReadAll(r.Body) + a.Nil(err, "problem reading request body, POST parameters may be malformed") + a.EqualValues(k, string(d), "POST parameters improperly encoded") +} + +/* NOT DONE: OPEN web server, check parameters posted, more. This test is incomplete. +a.EqualValues(`{"username": "user1","password": "pass2"}`, string(post_params), + "user/pass json parameters improperly encoded") +*/ diff --git a/core/unifi/v4/usg.go b/core/unifi/v4/usg.go new file mode 100644 index 00000000..d7aff5a1 --- /dev/null +++ b/core/unifi/v4/usg.go @@ -0,0 +1,252 @@ +package unifi + +import ( + "encoding/json" + "time" +) + +// USG represents all the data from the Ubiquiti Controller for a Unifi Security Gateway. +type USG struct { + SourceName string `json:"-"` + ID string `json:"_id"` + Adopted FlexBool `json:"adopted"` + Cfgversion string `json:"cfgversion"` + ConfigNetwork struct { + Type string `json:"type"` + IP string `json:"ip"` + } `json:"config_network"` + EthernetTable []struct { + Mac string `json:"mac"` + NumPort FlexInt `json:"num_port"` + Name string `json:"name"` + } `json:"ethernet_table"` + FwCaps FlexInt `json:"fw_caps"` + InformIP string `json:"inform_ip"` + InformURL string `json:"inform_url"` + IP string `json:"ip"` + LedOverride string `json:"led_override"` + LicenseState string `json:"license_state"` + Mac string `json:"mac"` + Model string `json:"model"` + Name string `json:"name"` + OutdoorModeOverride string `json:"outdoor_mode_override"` + Serial string `json:"serial"` + SiteID string `json:"site_id"` + SiteName string `json:"-"` + Type string `json:"type"` + UsgCaps FlexInt `json:"usg_caps"` + Version string `json:"version"` + RequiredVersion string `json:"required_version"` + EthernetOverrides []struct { + Ifname string `json:"ifname"` + Networkgroup string `json:"networkgroup"` + } `json:"ethernet_overrides"` + HwCaps FlexInt `json:"hw_caps"` + BoardRev FlexInt `json:"board_rev"` + Unsupported FlexBool `json:"unsupported"` + UnsupportedReason FlexInt `json:"unsupported_reason"` + DeviceID string `json:"device_id"` + State FlexInt `json:"state"` + LastSeen FlexInt `json:"last_seen"` + Upgradable FlexBool `json:"upgradable"` + AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` + Rollupgrade FlexBool `json:"rollupgrade"` + KnownCfgversion string `json:"known_cfgversion"` + Uptime FlexInt `json:"uptime"` + Locating FlexBool `json:"locating"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + SysStats SysStats `json:"sys_stats"` + SystemStats SystemStats `json:"system-stats"` + GuestToken string `json:"guest_token"` + SpeedtestStatus SpeedtestStatus `json:"speedtest-status"` + SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"` + Wan1 Wan `json:"wan1"` + Wan2 Wan `json:"wan2"` + PortTable []struct { + Name string `json:"name"` + Ifname string `json:"ifname"` + IP string `json:"ip"` + Netmask string `json:"netmask"` + Mac string `json:"mac"` + Up FlexBool `json:"up"` + Speed FlexInt `json:"speed"` + FullDuplex FlexBool `json:"full_duplex"` + RxBytes FlexInt `json:"rx_bytes"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxPackets FlexInt `json:"rx_packets"` + TxBytes FlexInt `json:"tx_bytes"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxPackets FlexInt `json:"tx_packets"` + RxMulticast FlexInt `json:"rx_multicast"` + Enable FlexBool `json:"enable"` + DNS []string `json:"dns,omitempty"` + Gateway string `json:"gateway,omitempty"` + } `json:"port_table"` + NetworkTable NetworkTable `json:"network_table"` + Uplink Uplink `json:"uplink"` + Stat USGStat `json:"stat"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + NumSta FlexInt `json:"num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` + NumDesktop FlexInt `json:"num_desktop"` + NumMobile FlexInt `json:"num_mobile"` + NumHandheld FlexInt `json:"num_handheld"` +} + +// Uplink is the Internet connection (or uplink) on a UniFi device. +type Uplink struct { + BytesR FlexInt `json:"bytes-r"` + Drops FlexInt `json:"drops"` + Enable FlexBool `json:"enable,omitempty"` + FullDuplex FlexBool `json:"full_duplex"` + Gateways []string `json:"gateways,omitempty"` + IP string `json:"ip"` + Latency FlexInt `json:"latency"` + Mac string `json:"mac,omitempty"` + MaxSpeed FlexInt `json:"max_speed"` + Name string `json:"name"` + Nameservers []string `json:"nameservers"` + Netmask string `json:"netmask"` + NumPort FlexInt `json:"num_port"` + RxBytes FlexInt `json:"rx_bytes"` + RxBytesR FlexInt `json:"rx_bytes-r"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxMulticast FlexInt `json:"rx_multicast"` + RxPackets FlexInt `json:"rx_packets"` + Speed FlexInt `json:"speed"` + SpeedtestLastrun FlexInt `json:"speedtest_lastrun,omitempty"` + SpeedtestPing FlexInt `json:"speedtest_ping,omitempty"` + SpeedtestStatus string `json:"speedtest_status,omitempty"` + TxBytes FlexInt `json:"tx_bytes"` + TxBytesR FlexInt `json:"tx_bytes-r"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxPackets FlexInt `json:"tx_packets"` + Type string `json:"type"` + Up FlexBool `json:"up"` + Uptime FlexInt `json:"uptime"` + XputDown FlexInt `json:"xput_down,omitempty"` + XputUp FlexInt `json:"xput_up,omitempty"` +} + +// Wan is a Wan interface on a USG or UDM. +type Wan struct { + Autoneg FlexBool `json:"autoneg"` + BytesR FlexInt `json:"bytes-r"` + DNS []string `json:"dns"` + Enable FlexBool `json:"enable"` + FlowctrlRx FlexBool `json:"flowctrl_rx"` + FlowctrlTx FlexBool `json:"flowctrl_tx"` + FullDuplex FlexBool `json:"full_duplex"` + Gateway string `json:"gateway"` // may be deprecated + IP string `json:"ip"` + Ifname string `json:"ifname"` + IsUplink FlexBool `json:"is_uplink"` + Mac string `json:"mac"` + MaxSpeed FlexInt `json:"max_speed"` + Media string `json:"media"` + Name string `json:"name"` + Netmask string `json:"netmask"` // may be deprecated + NumPort int `json:"num_port"` + PortIdx int `json:"port_idx"` + PortPoe FlexBool `json:"port_poe"` + RxBroadcast FlexInt `json:"rx_broadcast"` + RxBytes FlexInt `json:"rx_bytes"` + RxBytesR FlexInt `json:"rx_bytes-r"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxMulticast FlexInt `json:"rx_multicast"` + RxPackets FlexInt `json:"rx_packets"` + Speed FlexInt `json:"speed"` + TxBroadcast FlexInt `json:"tx_broadcast"` + TxBytes FlexInt `json:"tx_bytes"` + TxBytesR FlexInt `json:"tx_bytes-r"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxMulticast FlexInt `json:"tx_multicast"` + TxPackets FlexInt `json:"tx_packets"` + Type string `json:"type"` + Up FlexBool `json:"up"` +} + +// SpeedtestStatus is the speed test info on a USG or UDM. +type SpeedtestStatus struct { + Latency FlexInt `json:"latency"` + Rundate FlexInt `json:"rundate"` + Runtime FlexInt `json:"runtime"` + ServerDesc string `json:"server_desc,omitempty"` + StatusDownload FlexInt `json:"status_download"` + StatusPing FlexInt `json:"status_ping"` + StatusSummary FlexInt `json:"status_summary"` + StatusUpload FlexInt `json:"status_upload"` + XputDownload FlexInt `json:"xput_download"` + XputUpload FlexInt `json:"xput_upload"` +} + +// SystemStats is system info for a UDM, USG, USW. +type SystemStats struct { + CPU FlexInt `json:"cpu"` + Mem FlexInt `json:"mem"` + Uptime FlexInt `json:"uptime"` +} + +// SysStats is load info for a UDM, USG, USW. +type SysStats struct { + Loadavg1 FlexInt `json:"loadavg_1"` + Loadavg15 FlexInt `json:"loadavg_15"` + Loadavg5 FlexInt `json:"loadavg_5"` + MemBuffer FlexInt `json:"mem_buffer"` + MemTotal FlexInt `json:"mem_total"` + MemUsed FlexInt `json:"mem_used"` +} + +// USGStat holds the "stat" data for a gateway. +// This is split out because of a JSON data format change from 5.10 to 5.11. +type USGStat struct { + *Gw +} + +// Gw is a subtype of USGStat to make unmarshalling of different controller versions possible. +type Gw struct { + SiteID string `json:"site_id"` + O string `json:"o"` + Oid string `json:"oid"` + Gw string `json:"gw"` + Time FlexInt `json:"time"` + Datetime time.Time `json:"datetime"` + Duration FlexInt `json:"duration"` + WanRxPackets FlexInt `json:"wan-rx_packets"` + WanRxBytes FlexInt `json:"wan-rx_bytes"` + WanRxDropped FlexInt `json:"wan-rx_dropped"` + WanTxPackets FlexInt `json:"wan-tx_packets"` + WanTxBytes FlexInt `json:"wan-tx_bytes"` + LanRxPackets FlexInt `json:"lan-rx_packets"` + LanRxBytes FlexInt `json:"lan-rx_bytes"` + LanTxPackets FlexInt `json:"lan-tx_packets"` + LanTxBytes FlexInt `json:"lan-tx_bytes"` + LanRxDropped FlexInt `json:"lan-rx_dropped"` + WanRxErrors FlexInt `json:"wan-rx_errors,omitempty"` +} + +// UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Gateway Stat data. +func (v *USGStat) UnmarshalJSON(data []byte) error { + var n struct { + Gw `json:"gw"` + } + + v.Gw = &n.Gw + + err := json.Unmarshal(data, v.Gw) // controller version 5.10. + if err != nil { + return json.Unmarshal(data, &n) // controller version 5.11. + } + + return nil +} diff --git a/core/unifi/v4/usg_test.go b/core/unifi/v4/usg_test.go new file mode 100644 index 00000000..16bb6a18 --- /dev/null +++ b/core/unifi/v4/usg_test.go @@ -0,0 +1,60 @@ +package unifi + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestUSGUnmarshalJSON(t *testing.T) { + testcontroller511 := `{ + "gw": { + "site_id": "mySite", + "o": "gw", + "oid": "00:00:00:00:00:00", + "gw": "00:00:00:00:00:00", + "time": 1577742600000, + "datetime": "2019-12-30T09:50:00Z", + "bytes": 0, + "duration": 3590568000, + "wan-rx_packets": 299729434558, + "wan-rx_bytes": 299882768958208, + "wan-tx_packets": 249639259523, + "wan-tx_bytes": 169183252492369, + "lan-rx_packets": 78912349453, + "lan-rx_bytes": 37599596992669, + "lan-tx_packets": 12991234992, + "lan-tx_bytes": 11794664098210}}` + + testcontroller510 := `{ + "site_id": "mySite", + "o": "gw", + "oid": "00:00:00:00:00:00", + "gw": "00:00:00:00:00:00", + "time": 1577742600000, + "datetime": "2019-12-30T09:50:00Z", + "bytes": 0, + "duration": 3590568000, + "wan-rx_packets": 299729434558, + "wan-rx_bytes": 299882768958208, + "wan-tx_packets": 249639259523, + "wan-tx_bytes": 169183252492369, + "lan-rx_packets": 78912349453, + "lan-rx_bytes": 37599596992669, + "lan-tx_packets": 12991234992, + "lan-tx_bytes": 11794664098210}` + + t.Parallel() + a := assert.New(t) + + u := &USGStat{} + lanRx := 37599596992669 + err := u.UnmarshalJSON([]byte(testcontroller510)) + a.Nil(err, "must be no error unmarshaling test strings") + a.Equal(float64(lanRx), u.LanRxBytes.Val, "data was not properly unmarshaled") + + u = &USGStat{} // reset + err = u.UnmarshalJSON([]byte(testcontroller511)) + a.Nil(err, "must be no error unmarshaling test strings") + a.Equal(float64(lanRx), u.LanRxBytes.Val, "data was not properly unmarshaled") +} diff --git a/core/unifi/v4/usw.go b/core/unifi/v4/usw.go new file mode 100644 index 00000000..242b2053 --- /dev/null +++ b/core/unifi/v4/usw.go @@ -0,0 +1,377 @@ +package unifi + +import ( + "encoding/json" + "time" +) + +// USW represents all the data from the Ubiquiti Controller for a Unifi Switch. +type USW struct { + SourceName string `json:"-"` + SiteName string `json:"-"` + ID string `json:"_id"` + Adopted FlexBool `json:"adopted"` + BoardRev FlexInt `json:"board_rev"` + Cfgversion string `json:"cfgversion"` + ConfigNetwork struct { + Type string `json:"type"` + IP string `json:"ip"` + } `json:"config_network"` + Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"` + EthernetTable []struct { + Mac string `json:"mac"` + NumPort FlexInt `json:"num_port,omitempty"` + Name string `json:"name"` + } `json:"ethernet_table"` + FlowctrlEnabled FlexBool `json:"flowctrl_enabled"` + FwCaps FlexInt `json:"fw_caps"` + HasFan FlexBool `json:"has_fan"` + HasTemperature FlexBool `json:"has_temperature"` + InformIP string `json:"inform_ip"` + InformURL string `json:"inform_url"` + IP string `json:"ip"` + JumboframeEnabled FlexBool `json:"jumboframe_enabled"` + LedOverride string `json:"led_override"` + LicenseState string `json:"license_state"` + Mac string `json:"mac"` + Model string `json:"model"` + Name string `json:"name"` + OutdoorModeOverride string `json:"outdoor_mode_override"` + PortOverrides []struct { + Name string `json:"name,omitempty"` + PoeMode string `json:"poe_mode,omitempty"` + PortIdx FlexInt `json:"port_idx"` + PortconfID string `json:"portconf_id"` + } `json:"port_overrides"` + PortTable []Port `json:"port_table"` + Serial string `json:"serial"` + SiteID string `json:"site_id"` + StpPriority FlexInt `json:"stp_priority"` + StpVersion string `json:"stp_version"` + Type string `json:"type"` + Version string `json:"version"` + RequiredVersion string `json:"required_version"` + SwitchCaps struct { + FeatureCaps FlexInt `json:"feature_caps"` + MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` + MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` + } `json:"switch_caps"` + HwCaps FlexInt `json:"hw_caps"` + Unsupported FlexBool `json:"unsupported"` + UnsupportedReason FlexInt `json:"unsupported_reason"` + SysErrorCaps FlexInt `json:"sys_error_caps"` + DeviceID string `json:"device_id"` + State FlexInt `json:"state"` + LastSeen FlexInt `json:"last_seen"` + Upgradable FlexBool `json:"upgradable,omitempty"` + AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded,omitempty"` + Rollupgrade FlexBool `json:"rollupgrade,omitempty"` + KnownCfgversion string `json:"known_cfgversion"` + Uptime FlexInt `json:"uptime"` + Locating FlexBool `json:"locating"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + SysStats SysStats `json:"sys_stats"` + SystemStats SystemStats `json:"system-stats"` + FanLevel FlexInt `json:"fan_level"` + GeneralTemperature FlexInt `json:"general_temperature"` + Overheating FlexBool `json:"overheating"` + TotalMaxPower FlexInt `json:"total_max_power"` + DownlinkTable []struct { + PortIdx FlexInt `json:"port_idx"` + Speed FlexInt `json:"speed"` + FullDuplex FlexBool `json:"full_duplex"` + Mac string `json:"mac"` + } `json:"downlink_table"` + Uplink Uplink `json:"uplink"` + LastUplink struct { + UplinkMac string `json:"uplink_mac"` + } `json:"last_uplink"` + UplinkDepth FlexInt `json:"uplink_depth"` + Stat USWStat `json:"stat"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + NumSta FlexInt `json:"num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` +} + +// Port is a physical connection on a USW or UDM. +type Port struct { + AggregatedBy FlexBool `json:"aggregated_by"` + Autoneg FlexBool `json:"autoneg,omitempty"` + BytesR FlexInt `json:"bytes-r"` + DNS []string `json:"dns,omitempty"` + Dot1XMode string `json:"dot1x_mode"` + Dot1XStatus string `json:"dot1x_status"` + Enable FlexBool `json:"enable"` + FlowctrlRx FlexBool `json:"flowctrl_rx"` + FlowctrlTx FlexBool `json:"flowctrl_tx"` + FullDuplex FlexBool `json:"full_duplex"` + IP string `json:"ip,omitempty"` + Ifname string `json:"ifname,omitempty"` + IsUplink FlexBool `json:"is_uplink"` + Mac string `json:"mac,omitempty"` + Jumbo FlexBool `json:"jumbo,omitempty"` + Masked FlexBool `json:"masked"` + Media string `json:"media"` + Name string `json:"name"` + NetworkName string `json:"network_name,omitempty"` + NumPort int `json:"num_port,omitempty"` + OpMode string `json:"op_mode"` + PoeCaps FlexInt `json:"poe_caps"` + PoeClass string `json:"poe_class,omitempty"` + PoeCurrent FlexInt `json:"poe_current,omitempty"` + PoeEnable FlexBool `json:"poe_enable,omitempty"` + PoeGood FlexBool `json:"poe_good,omitempty"` + PoeMode string `json:"poe_mode,omitempty"` + PoePower FlexInt `json:"poe_power,omitempty"` + PoeVoltage FlexInt `json:"poe_voltage,omitempty"` + PortDelta struct { + TimeDelta int64 `json:"time_delta"` + } `json:"port_delta,omitempty"` + PortIdx FlexInt `json:"port_idx"` + PortPoe FlexBool `json:"port_poe"` + PortconfID string `json:"portconf_id"` + RxBroadcast FlexInt `json:"rx_broadcast"` + RxBytes FlexInt `json:"rx_bytes"` + RxBytesR FlexInt `json:"rx_bytes-r"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxMulticast FlexInt `json:"rx_multicast"` + RxPackets FlexInt `json:"rx_packets"` + Satisfaction FlexInt `json:"satisfaction,omitempty"` + SfpFound FlexBool `json:"sfp_found,omitempty"` + Speed FlexInt `json:"speed"` + SpeedCaps FlexInt `json:"speed_caps"` + StpPathcost FlexInt `json:"stp_pathcost"` + StpState string `json:"stp_state"` + TxBroadcast FlexInt `json:"tx_broadcast"` + TxBytes FlexInt `json:"tx_bytes"` + TxBytesR FlexInt `json:"tx_bytes-r"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxMulticast FlexInt `json:"tx_multicast"` + TxPackets FlexInt `json:"tx_packets"` + Type string `json:"type,omitempty"` + Up FlexBool `json:"up"` +} + +// USWStat holds the "stat" data for a switch. +// This is split out because of a JSON data format change from 5.10 to 5.11. +type USWStat struct { + *Sw +} + +// Sw is a subtype of USWStat to make unmarshalling of different controller versions possible. +type Sw struct { + SiteID string `json:"site_id"` + O string `json:"o"` + Oid string `json:"oid"` + Sw string `json:"sw"` + Time FlexInt `json:"time"` + Datetime time.Time `json:"datetime"` + RxPackets FlexInt `json:"rx_packets"` + RxBytes FlexInt `json:"rx_bytes"` + RxErrors FlexInt `json:"rx_errors"` + RxDropped FlexInt `json:"rx_dropped"` + RxCrypts FlexInt `json:"rx_crypts"` + RxFrags FlexInt `json:"rx_frags"` + TxPackets FlexInt `json:"tx_packets"` + TxBytes FlexInt `json:"tx_bytes"` + TxErrors FlexInt `json:"tx_errors"` + TxDropped FlexInt `json:"tx_dropped"` + TxRetries FlexInt `json:"tx_retries"` + RxMulticast FlexInt `json:"rx_multicast"` + RxBroadcast FlexInt `json:"rx_broadcast"` + TxMulticast FlexInt `json:"tx_multicast"` + TxBroadcast FlexInt `json:"tx_broadcast"` + Bytes FlexInt `json:"bytes"` + Duration FlexInt `json:"duration"` + /* These are all in port table */ + /* + Port1RxPackets FlexInt `json:"port_1-rx_packets,omitempty"` + Port1RxBytes FlexInt `json:"port_1-rx_bytes,omitempty"` + Port1TxPackets FlexInt `json:"port_1-tx_packets,omitempty"` + Port1TxBytes FlexInt `json:"port_1-tx_bytes,omitempty"` + Port1TxMulticast FlexInt `json:"port_1-tx_multicast"` + Port1TxBroadcast FlexInt `json:"port_1-tx_broadcast"` + Port3RxPackets FlexInt `json:"port_3-rx_packets,omitempty"` + Port3RxBytes FlexInt `json:"port_3-rx_bytes,omitempty"` + Port3TxPackets FlexInt `json:"port_3-tx_packets,omitempty"` + Port3TxBytes FlexInt `json:"port_3-tx_bytes,omitempty"` + Port3RxBroadcast FlexInt `json:"port_3-rx_broadcast"` + Port3TxMulticast FlexInt `json:"port_3-tx_multicast"` + Port3TxBroadcast FlexInt `json:"port_3-tx_broadcast"` + Port6RxPackets FlexInt `json:"port_6-rx_packets,omitempty"` + Port6RxBytes FlexInt `json:"port_6-rx_bytes,omitempty"` + Port6TxPackets FlexInt `json:"port_6-tx_packets,omitempty"` + Port6TxBytes FlexInt `json:"port_6-tx_bytes,omitempty"` + Port6RxMulticast FlexInt `json:"port_6-rx_multicast"` + Port6TxMulticast FlexInt `json:"port_6-tx_multicast"` + Port6TxBroadcast FlexInt `json:"port_6-tx_broadcast"` + Port7RxPackets FlexInt `json:"port_7-rx_packets,omitempty"` + Port7RxBytes FlexInt `json:"port_7-rx_bytes,omitempty"` + Port7TxPackets FlexInt `json:"port_7-tx_packets,omitempty"` + Port7TxBytes FlexInt `json:"port_7-tx_bytes,omitempty"` + Port7TxMulticast FlexInt `json:"port_7-tx_multicast"` + Port7TxBroadcast FlexInt `json:"port_7-tx_broadcast"` + Port9RxPackets FlexInt `json:"port_9-rx_packets,omitempty"` + Port9RxBytes FlexInt `json:"port_9-rx_bytes,omitempty"` + Port9TxPackets FlexInt `json:"port_9-tx_packets,omitempty"` + Port9TxBytes FlexInt `json:"port_9-tx_bytes,omitempty"` + Port9TxMulticast FlexInt `json:"port_9-tx_multicast"` + Port9TxBroadcast FlexInt `json:"port_9-tx_broadcast"` + Port10RxPackets FlexInt `json:"port_10-rx_packets,omitempty"` + Port10RxBytes FlexInt `json:"port_10-rx_bytes,omitempty"` + Port10TxPackets FlexInt `json:"port_10-tx_packets,omitempty"` + Port10TxBytes FlexInt `json:"port_10-tx_bytes,omitempty"` + Port10RxMulticast FlexInt `json:"port_10-rx_multicast"` + Port10TxMulticast FlexInt `json:"port_10-tx_multicast"` + Port10TxBroadcast FlexInt `json:"port_10-tx_broadcast"` + Port11RxPackets FlexInt `json:"port_11-rx_packets,omitempty"` + Port11RxBytes FlexInt `json:"port_11-rx_bytes,omitempty"` + Port11TxPackets FlexInt `json:"port_11-tx_packets,omitempty"` + Port11TxBytes FlexInt `json:"port_11-tx_bytes,omitempty"` + Port11TxMulticast FlexInt `json:"port_11-tx_multicast"` + Port11TxBroadcast FlexInt `json:"port_11-tx_broadcast"` + Port12RxPackets FlexInt `json:"port_12-rx_packets,omitempty"` + Port12RxBytes FlexInt `json:"port_12-rx_bytes,omitempty"` + Port12TxPackets FlexInt `json:"port_12-tx_packets,omitempty"` + Port12TxBytes FlexInt `json:"port_12-tx_bytes,omitempty"` + Port12TxMulticast FlexInt `json:"port_12-tx_multicast"` + Port12TxBroadcast FlexInt `json:"port_12-tx_broadcast"` + Port13RxPackets FlexInt `json:"port_13-rx_packets,omitempty"` + Port13RxBytes FlexInt `json:"port_13-rx_bytes,omitempty"` + Port13TxPackets FlexInt `json:"port_13-tx_packets,omitempty"` + Port13TxBytes FlexInt `json:"port_13-tx_bytes,omitempty"` + Port13RxMulticast FlexInt `json:"port_13-rx_multicast"` + Port13RxBroadcast FlexInt `json:"port_13-rx_broadcast"` + Port13TxMulticast FlexInt `json:"port_13-tx_multicast"` + Port13TxBroadcast FlexInt `json:"port_13-tx_broadcast"` + Port15RxPackets FlexInt `json:"port_15-rx_packets,omitempty"` + Port15RxBytes FlexInt `json:"port_15-rx_bytes,omitempty"` + Port15TxPackets FlexInt `json:"port_15-tx_packets,omitempty"` + Port15TxBytes FlexInt `json:"port_15-tx_bytes,omitempty"` + Port15RxBroadcast FlexInt `json:"port_15-rx_broadcast"` + Port15TxMulticast FlexInt `json:"port_15-tx_multicast"` + Port15TxBroadcast FlexInt `json:"port_15-tx_broadcast"` + Port16RxPackets FlexInt `json:"port_16-rx_packets,omitempty"` + Port16RxBytes FlexInt `json:"port_16-rx_bytes,omitempty"` + Port16TxPackets FlexInt `json:"port_16-tx_packets,omitempty"` + Port16TxBytes FlexInt `json:"port_16-tx_bytes,omitempty"` + Port16TxMulticast FlexInt `json:"port_16-tx_multicast"` + Port16TxBroadcast FlexInt `json:"port_16-tx_broadcast"` + Port17RxPackets FlexInt `json:"port_17-rx_packets,omitempty"` + Port17RxBytes FlexInt `json:"port_17-rx_bytes,omitempty"` + Port17TxPackets FlexInt `json:"port_17-tx_packets,omitempty"` + Port17TxBytes FlexInt `json:"port_17-tx_bytes,omitempty"` + Port17TxMulticast FlexInt `json:"port_17-tx_multicast"` + Port17TxBroadcast FlexInt `json:"port_17-tx_broadcast"` + Port18RxPackets FlexInt `json:"port_18-rx_packets,omitempty"` + Port18RxBytes FlexInt `json:"port_18-rx_bytes,omitempty"` + Port18TxPackets FlexInt `json:"port_18-tx_packets,omitempty"` + Port18TxBytes FlexInt `json:"port_18-tx_bytes,omitempty"` + Port18RxMulticast FlexInt `json:"port_18-rx_multicast"` + Port18TxMulticast FlexInt `json:"port_18-tx_multicast"` + Port18TxBroadcast FlexInt `json:"port_18-tx_broadcast"` + Port19RxPackets FlexInt `json:"port_19-rx_packets,omitempty"` + Port19RxBytes FlexInt `json:"port_19-rx_bytes,omitempty"` + Port19TxPackets FlexInt `json:"port_19-tx_packets,omitempty"` + Port19TxBytes FlexInt `json:"port_19-tx_bytes,omitempty"` + Port19TxMulticast FlexInt `json:"port_19-tx_multicast"` + Port19TxBroadcast FlexInt `json:"port_19-tx_broadcast"` + Port21RxPackets FlexInt `json:"port_21-rx_packets,omitempty"` + Port21RxBytes FlexInt `json:"port_21-rx_bytes,omitempty"` + Port21TxPackets FlexInt `json:"port_21-tx_packets,omitempty"` + Port21TxBytes FlexInt `json:"port_21-tx_bytes,omitempty"` + Port21RxBroadcast FlexInt `json:"port_21-rx_broadcast"` + Port21TxMulticast FlexInt `json:"port_21-tx_multicast"` + Port21TxBroadcast FlexInt `json:"port_21-tx_broadcast"` + Port22RxPackets FlexInt `json:"port_22-rx_packets,omitempty"` + Port22RxBytes FlexInt `json:"port_22-rx_bytes,omitempty"` + Port22TxPackets FlexInt `json:"port_22-tx_packets,omitempty"` + Port22TxBytes FlexInt `json:"port_22-tx_bytes,omitempty"` + Port22RxMulticast FlexInt `json:"port_22-rx_multicast"` + Port22TxMulticast FlexInt `json:"port_22-tx_multicast"` + Port22TxBroadcast FlexInt `json:"port_22-tx_broadcast"` + Port23RxPackets FlexInt `json:"port_23-rx_packets,omitempty"` + Port23RxBytes FlexInt `json:"port_23-rx_bytes,omitempty"` + Port23RxDropped FlexInt `json:"port_23-rx_dropped"` + Port23TxPackets FlexInt `json:"port_23-tx_packets,omitempty"` + Port23TxBytes FlexInt `json:"port_23-tx_bytes,omitempty"` + Port23RxMulticast FlexInt `json:"port_23-rx_multicast"` + Port23RxBroadcast FlexInt `json:"port_23-rx_broadcast"` + Port23TxMulticast FlexInt `json:"port_23-tx_multicast"` + Port23TxBroadcast FlexInt `json:"port_23-tx_broadcast"` + Port24RxPackets FlexInt `json:"port_24-rx_packets,omitempty"` + Port24RxBytes FlexInt `json:"port_24-rx_bytes,omitempty"` + Port24TxPackets FlexInt `json:"port_24-tx_packets,omitempty"` + Port24TxBytes FlexInt `json:"port_24-tx_bytes,omitempty"` + Port24RxMulticast FlexInt `json:"port_24-rx_multicast"` + Port24TxMulticast FlexInt `json:"port_24-tx_multicast"` + Port24TxBroadcast FlexInt `json:"port_24-tx_broadcast"` + Port1RxMulticast FlexInt `json:"port_1-rx_multicast"` + Port3RxDropped FlexInt `json:"port_3-rx_dropped"` + Port3RxMulticast FlexInt `json:"port_3-rx_multicast"` + Port6RxDropped FlexInt `json:"port_6-rx_dropped"` + Port7RxDropped FlexInt `json:"port_7-rx_dropped"` + Port7RxMulticast FlexInt `json:"port_7-rx_multicast"` + Port9RxDropped FlexInt `json:"port_9-rx_dropped"` + Port9RxMulticast FlexInt `json:"port_9-rx_multicast"` + Port9RxBroadcast FlexInt `json:"port_9-rx_broadcast"` + Port10RxBroadcast FlexInt `json:"port_10-rx_broadcast"` + Port12RxDropped FlexInt `json:"port_12-rx_dropped"` + Port12RxMulticast FlexInt `json:"port_12-rx_multicast"` + Port13RxDropped FlexInt `json:"port_13-rx_dropped"` + Port17RxDropped FlexInt `json:"port_17-rx_dropped"` + Port17RxMulticast FlexInt `json:"port_17-rx_multicast"` + Port17RxBroadcast FlexInt `json:"port_17-rx_broadcast"` + Port19RxDropped FlexInt `json:"port_19-rx_dropped"` + Port19RxMulticast FlexInt `json:"port_19-rx_multicast"` + Port19RxBroadcast FlexInt `json:"port_19-rx_broadcast"` + Port21RxDropped FlexInt `json:"port_21-rx_dropped"` + Port21RxMulticast FlexInt `json:"port_21-rx_multicast"` + Port7RxBroadcast FlexInt `json:"port_7-rx_broadcast"` + Port18RxBroadcast FlexInt `json:"port_18-rx_broadcast"` + Port16RxMulticast FlexInt `json:"port_16-rx_multicast"` + Port15RxDropped FlexInt `json:"port_15-rx_dropped"` + Port15RxMulticast FlexInt `json:"port_15-rx_multicast"` + Port16RxBroadcast FlexInt `json:"port_16-rx_broadcast"` + Port11RxBroadcast FlexInt `json:"port_11-rx_broadcast"` + Port12RxBroadcast FlexInt `json:"port_12-rx_broadcast"` + Port6RxBroadcast FlexInt `json:"port_6-rx_broadcast"` + Port24RxBroadcast FlexInt `json:"port_24-rx_broadcast"` + Port22RxBroadcast FlexInt `json:"port_22-rx_broadcast"` + Port10TxDropped FlexInt `json:"port_10-tx_dropped"` + Port16TxDropped FlexInt `json:"port_16-tx_dropped"` + Port1RxBroadcast FlexInt `json:"port_1-rx_broadcast"` + Port4RxPackets FlexInt `json:"port_4-rx_packets,omitempty"` + Port4RxBytes FlexInt `json:"port_4-rx_bytes,omitempty"` + Port4RxDropped FlexInt `json:"port_4-rx_dropped"` + Port4TxPackets FlexInt `json:"port_4-tx_packets,omitempty"` + Port4TxBytes FlexInt `json:"port_4-tx_bytes,omitempty"` + Port4TxDropped FlexInt `json:"port_4-tx_dropped"` + Port4RxMulticast FlexInt `json:"port_4-rx_multicast"` + Port4RxBroadcast FlexInt `json:"port_4-rx_broadcast"` + Port4TxMulticast FlexInt `json:"port_4-tx_multicast"` + Port4TxBroadcast FlexInt `json:"port_4-tx_broadcast"` + */ +} + +// UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Switch Stat data. +func (v *USWStat) UnmarshalJSON(data []byte) error { + var n struct { + Sw `json:"sw"` + } + + v.Sw = &n.Sw + + err := json.Unmarshal(data, v.Sw) // controller version 5.10. + if err != nil { + return json.Unmarshal(data, &n) // controller version 5.11. + } + + return nil +} diff --git a/core/unifi/v4/usw_test.go b/core/unifi/v4/usw_test.go new file mode 100644 index 00000000..66bfac63 --- /dev/null +++ b/core/unifi/v4/usw_test.go @@ -0,0 +1,75 @@ +package unifi + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func testGetControllerJSON() (string, string) { + return `{ + "sw": { + "site_id": "mySite", + "o": "sw", + "oid": "00:00:00:00:00:00", + "sw": "00:00:00:00:00:00", + "time": 1577742600000, + "datetime": "2019-12-30T09:40:00Z", + "rx_packets": 321, + "rx_bytes": 321, + "rx_errors": 123, + "rx_dropped": 123, + "rx_crypts": 123, + "rx_frags": 123, + "tx_packets": 123, + "tx_bytes": 123, + "tx_errors": 0, + "tx_dropped": 0, + "tx_retries": 0, + "rx_multicast": 123, + "rx_broadcast": 123, + "tx_multicast": 123, + "tx_broadcast": 123, + "bytes": 123, + "duration": 123}}`, + `{ + "site_id": "mySite", + "o": "sw", + "oid": "00:00:00:00:00:00", + "sw": "00:00:00:00:00:00", + "time": 1577742600000, + "datetime": "2019-12-30T09:40:00Z", + "rx_packets": 321, + "rx_bytes": 321, + "rx_errors": 123, + "rx_dropped": 123, + "rx_crypts": 123, + "rx_frags": 123, + "tx_packets": 123, + "tx_bytes": 123, + "tx_errors": 0, + "tx_dropped": 0, + "tx_retries": 0, + "rx_multicast": 123, + "rx_broadcast": 123, + "tx_multicast": 123, + "tx_broadcast": 123, + "bytes": 123, + "duration": 123}` +} + +func TestUSWUnmarshalJSON(t *testing.T) { + t.Parallel() + a := assert.New(t) + testcontroller511, testcontroller510 := testGetControllerJSON() + rxMulticast := 123 + u := &USWStat{} + err := u.UnmarshalJSON([]byte(testcontroller510)) + a.Nil(err, "must be no error unmarshaling test strings") + a.Equal(float64(rxMulticast), u.RxMulticast.Val, "data was not properly unmarshaled") + + u = &USWStat{} // reset + err = u.UnmarshalJSON([]byte(testcontroller511)) + a.Nil(err, "must be no error unmarshaling test strings") + a.Equal(float64(rxMulticast), u.RxMulticast.Val, "data was not properly unmarshaled") +} From cf23e224fb8b0bb3601a32bf552d411e1522dfb5 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Fri, 27 Dec 2019 21:04:23 -0800 Subject: [PATCH 122/194] remove mod from here --- core/unifi/go.mod | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 core/unifi/go.mod diff --git a/core/unifi/go.mod b/core/unifi/go.mod deleted file mode 100644 index 80ac2e5c..00000000 --- a/core/unifi/go.mod +++ /dev/null @@ -1,9 +0,0 @@ -module golift.io/unifi - -go 1.13 - -require ( - github.com/davecgh/go-spew v1.1.1 - github.com/pmezard/go-difflib v1.0.0 - github.com/stretchr/testify v1.4.0 -) From 6c9ce4da800e5d1ee7f4eb4db1fde82f17c683d8 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Fri, 27 Dec 2019 21:05:49 -0800 Subject: [PATCH 123/194] Delete go.sum --- core/unifi/go.sum | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 core/unifi/go.sum diff --git a/core/unifi/go.sum b/core/unifi/go.sum deleted file mode 100644 index 1041afa2..00000000 --- a/core/unifi/go.sum +++ /dev/null @@ -1,11 +0,0 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From abd0c32dbd8494ad19d597c454b73ce125d81830 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Fri, 27 Dec 2019 21:09:14 -0800 Subject: [PATCH 124/194] Update go.mod --- core/unifi/v4/go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/v4/go.mod b/core/unifi/v4/go.mod index 80ac2e5c..9757df3f 100644 --- a/core/unifi/v4/go.mod +++ b/core/unifi/v4/go.mod @@ -1,4 +1,4 @@ -module golift.io/unifi +module golift.io/unifi/v4 go 1.13 From 7ac8c958c69be0458b27ab38534ce218a423c7a9 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Fri, 27 Dec 2019 21:16:13 -0800 Subject: [PATCH 125/194] add module here? --- core/unifi/go.mod | 9 +++++++++ core/unifi/go.sum | 11 +++++++++++ 2 files changed, 20 insertions(+) create mode 100644 core/unifi/go.mod create mode 100644 core/unifi/go.sum diff --git a/core/unifi/go.mod b/core/unifi/go.mod new file mode 100644 index 00000000..80ac2e5c --- /dev/null +++ b/core/unifi/go.mod @@ -0,0 +1,9 @@ +module golift.io/unifi + +go 1.13 + +require ( + github.com/davecgh/go-spew v1.1.1 + github.com/pmezard/go-difflib v1.0.0 + github.com/stretchr/testify v1.4.0 +) diff --git a/core/unifi/go.sum b/core/unifi/go.sum new file mode 100644 index 00000000..1041afa2 --- /dev/null +++ b/core/unifi/go.sum @@ -0,0 +1,11 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From bb61340800154211a93c1d5fe919061553980521 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Fri, 27 Dec 2019 21:23:01 -0800 Subject: [PATCH 126/194] delete this --- core/unifi/v4/LICENSE | 23 - core/unifi/v4/README.md | 64 - core/unifi/v4/clients.go | 156 -- core/unifi/v4/devices.go | 107 -- core/unifi/v4/dpi.go | 2366 ----------------------------- core/unifi/v4/examples/convert.sh | 26 - core/unifi/v4/examples/ids.json | 66 - core/unifi/v4/examples/uap.json | 738 --------- core/unifi/v4/examples/ugw.json | 371 ----- core/unifi/v4/examples/usw.json | 1720 --------------------- core/unifi/v4/go.mod | 9 - core/unifi/v4/go.sum | 11 - core/unifi/v4/ids.go | 150 -- core/unifi/v4/site.go | 124 -- core/unifi/v4/types.go | 132 -- core/unifi/v4/types_test.go | 41 - core/unifi/v4/uap.go | 566 ------- core/unifi/v4/uap_test.go | 53 - core/unifi/v4/udm.go | 183 --- core/unifi/v4/unifi.go | 160 -- core/unifi/v4/unifi_test.go | 62 - core/unifi/v4/usg.go | 252 --- core/unifi/v4/usg_test.go | 60 - core/unifi/v4/usw.go | 377 ----- core/unifi/v4/usw_test.go | 75 - 25 files changed, 7892 deletions(-) delete mode 100644 core/unifi/v4/LICENSE delete mode 100644 core/unifi/v4/README.md delete mode 100644 core/unifi/v4/clients.go delete mode 100644 core/unifi/v4/devices.go delete mode 100644 core/unifi/v4/dpi.go delete mode 100755 core/unifi/v4/examples/convert.sh delete mode 100644 core/unifi/v4/examples/ids.json delete mode 100644 core/unifi/v4/examples/uap.json delete mode 100644 core/unifi/v4/examples/ugw.json delete mode 100644 core/unifi/v4/examples/usw.json delete mode 100644 core/unifi/v4/go.mod delete mode 100644 core/unifi/v4/go.sum delete mode 100644 core/unifi/v4/ids.go delete mode 100644 core/unifi/v4/site.go delete mode 100644 core/unifi/v4/types.go delete mode 100644 core/unifi/v4/types_test.go delete mode 100644 core/unifi/v4/uap.go delete mode 100644 core/unifi/v4/uap_test.go delete mode 100644 core/unifi/v4/udm.go delete mode 100644 core/unifi/v4/unifi.go delete mode 100644 core/unifi/v4/unifi_test.go delete mode 100644 core/unifi/v4/usg.go delete mode 100644 core/unifi/v4/usg_test.go delete mode 100644 core/unifi/v4/usw.go delete mode 100644 core/unifi/v4/usw_test.go diff --git a/core/unifi/v4/LICENSE b/core/unifi/v4/LICENSE deleted file mode 100644 index 9187a167..00000000 --- a/core/unifi/v4/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -MIT License - -Copyright (c) 2019 Go Lift - Building Strong Go Tools -Copyright (c) 2018 David Newhall II -Copyright (c) 2016 Garrett Bjerkhoel - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/core/unifi/v4/README.md b/core/unifi/v4/README.md deleted file mode 100644 index 87f58e06..00000000 --- a/core/unifi/v4/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# Go Library: `unifi` - -It connects to a Unifi Controller, given a url, username and password. Returns -an authenticated http Client you may use to query the device for data. Also -contains some built-in methods for de-serializing common client and device -data. The data is provided in a large struct you can consume in your application. - -This library is designed to PULL data FROM the controller. It has no methods that -update settings or change things on the controller. -[Someone expressed interest](https://github.com/golift/unifi/issues/31) in -adding methods to update data, and I'm okay with that. I'll even help add them. -[Tell me what you want to do](https://github.com/golift/unifi/issues/new), and we'll make it happen. - -Pull requests, feature requests, code reviews and feedback are welcomed! - -Here's a working example: -```golang -package main - -import "log" -import "golift.io/unifi" - -func main() { - c := *unifi.Config{ - User: "admin", - Pass: "superSecret1234", - URL: "https://127.0.0.1:8443/", - // Log with log.Printf or make your own interface that accepts (msg, fmt) - ErrorLog: log.Printf, - DebugLog: log.Printf, - } - uni, err := unifi.NewUnifi(c) - if err != nil { - log.Fatalln("Error:", err) - } - - sites, err := uni.GetSites() - if err != nil { - log.Fatalln("Error:", err) - } - clients, err := uni.GetClients(sites) - if err != nil { - log.Fatalln("Error:", err) - } - devices, err := uni.GetDevices(sites) - if err != nil { - log.Fatalln("Error:", err) - } - - log.Println(len(sites), "Unifi Sites Found: ", sites) - log.Println(len(clients), "Clients connected:") - for i, client := range clients { - log.Println(i+1, client.ID, client.Hostname, client.IP, client.Name, client.LastSeen) - } - - log.Println(len(devices.USWs), "Unifi Switches Found") - log.Println(len(devices.USGs), "Unifi Gateways Found") - - log.Println(len(devices.UAPs), "Unifi Wireless APs Found:") - for i, uap := range devices.UAPs { - log.Println(i+1, uap.Name, uap.IP) - } -} -``` diff --git a/core/unifi/v4/clients.go b/core/unifi/v4/clients.go deleted file mode 100644 index ca4ea34d..00000000 --- a/core/unifi/v4/clients.go +++ /dev/null @@ -1,156 +0,0 @@ -package unifi - -import ( - "fmt" -) - -// GetClients returns a response full of clients' data from the UniFi Controller. -func (u *Unifi) GetClients(sites Sites) (Clients, error) { - data := make([]*Client, 0) - - for _, site := range sites { - var response struct { - Data []*Client `json:"data"` - } - - u.DebugLog("Polling Controller, retreiving UniFi Clients, site %s (%s) ", site.Name, site.Desc) - - clientPath := fmt.Sprintf(APIClientPath, site.Name) - if err := u.GetData(clientPath, &response); err != nil { - return nil, err - } - - for i, d := range response.Data { - // Add special SourceName value. - response.Data[i].SourceName = u.URL - // Add the special "Site Name" to each client. This becomes a Grafana filter somewhere. - response.Data[i].SiteName = site.Desc + " (" + site.Name + ")" - // Fix name and hostname fields. Sometimes one or the other is blank. - response.Data[i].Hostname = pick(d.Hostname, d.Name, d.Mac) - response.Data[i].Name = pick(d.Name, d.Hostname) - } - - data = append(data, response.Data...) - } - - return data, nil -} - -// GetClientsDPI garners dpi data for clients. -func (u *Unifi) GetClientsDPI(sites Sites) ([]*DPITable, error) { - var data []*DPITable - - for _, site := range sites { - u.DebugLog("Polling Controller, retreiving Client DPI data, site %s (%s) ", site.Name, site.Desc) - - var response struct { - Data []*DPITable `json:"data"` - } - - clientDPIpath := fmt.Sprintf(APIClientDPI, site.Name) - if err := u.GetData(clientDPIpath, &response, `{"type":"by_app"}`); err != nil { - return nil, err - } - - for _, d := range response.Data { - d.SourceName = site.SourceName - d.SiteName = site.SiteName - data = append(data, d) - } - } - - return data, nil -} - -// Clients contains a list that contains all of the unifi clients from a controller. -type Clients []*Client - -// Client defines all the data a connected-network client contains. -type Client struct { - SourceName string `json:"-"` - Anomalies int64 `json:"anomalies,omitempty"` - ApMac string `json:"ap_mac"` - ApName string `json:"-"` - AssocTime int64 `json:"assoc_time"` - Blocked bool `json:"blocked,omitempty"` - Bssid string `json:"bssid"` - BytesR int64 `json:"bytes-r"` - Ccq int64 `json:"ccq"` - Channel FlexInt `json:"channel"` - DevCat FlexInt `json:"dev_cat"` - DevFamily FlexInt `json:"dev_family"` - DevID FlexInt `json:"dev_id"` - DevVendor FlexInt `json:"dev_vendor,omitempty"` - DhcpendTime int `json:"dhcpend_time,omitempty"` - Satisfaction FlexInt `json:"satisfaction,omitempty"` - Essid string `json:"essid"` - FirstSeen int64 `json:"first_seen"` - FixedIP string `json:"fixed_ip"` - GwMac string `json:"gw_mac"` - GwName string `json:"-"` - Hostname string `json:"hostname"` - ID string `json:"_id"` - IP string `json:"ip"` - IdleTime int64 `json:"idle_time"` - Is11R FlexBool `json:"is_11r"` - IsGuest FlexBool `json:"is_guest"` - IsGuestByUAP FlexBool `json:"_is_guest_by_uap"` - IsGuestByUGW FlexBool `json:"_is_guest_by_ugw"` - IsGuestByUSW FlexBool `json:"_is_guest_by_usw"` - IsWired FlexBool `json:"is_wired"` - LastSeen int64 `json:"last_seen"` - LastSeenByUAP int64 `json:"_last_seen_by_uap"` - LastSeenByUGW int64 `json:"_last_seen_by_ugw"` - LastSeenByUSW int64 `json:"_last_seen_by_usw"` - LatestAssocTime int64 `json:"latest_assoc_time"` - Mac string `json:"mac"` - Name string `json:"name"` - Network string `json:"network"` - NetworkID string `json:"network_id"` - Noise int64 `json:"noise"` - Note string `json:"note"` - Noted FlexBool `json:"noted"` - OsClass FlexInt `json:"os_class"` - OsName FlexInt `json:"os_name"` - Oui string `json:"oui"` - PowersaveEnabled FlexBool `json:"powersave_enabled"` - QosPolicyApplied FlexBool `json:"qos_policy_applied"` - Radio string `json:"radio"` - RadioName string `json:"radio_name"` - RadioProto string `json:"radio_proto"` - RadioDescription string `json:"-"` - RoamCount int64 `json:"roam_count"` - Rssi int64 `json:"rssi"` - RxBytes int64 `json:"rx_bytes"` - RxBytesR int64 `json:"rx_bytes-r"` - RxPackets int64 `json:"rx_packets"` - RxRate int64 `json:"rx_rate"` - Signal int64 `json:"signal"` - SiteID string `json:"site_id"` - SiteName string `json:"-"` - SwDepth int `json:"sw_depth"` - SwMac string `json:"sw_mac"` - SwName string `json:"-"` - SwPort FlexInt `json:"sw_port"` - TxBytes int64 `json:"tx_bytes"` - TxBytesR int64 `json:"tx_bytes-r"` - TxPackets int64 `json:"tx_packets"` - TxRetries int64 `json:"tx_retries"` - TxPower int64 `json:"tx_power"` - TxRate int64 `json:"tx_rate"` - Uptime int64 `json:"uptime"` - UptimeByUAP int64 `json:"_uptime_by_uap"` - UptimeByUGW int64 `json:"_uptime_by_ugw"` - UptimeByUSW int64 `json:"_uptime_by_usw"` - UseFixedIP FlexBool `json:"use_fixedip"` - UserGroupID string `json:"usergroup_id"` - UserID string `json:"user_id"` - Vlan FlexInt `json:"vlan"` - WifiTxAttempts int64 `json:"wifi_tx_attempts"` - WiredRxBytes int64 `json:"wired-rx_bytes"` - WiredRxBytesR int64 `json:"wired-rx_bytes-r"` - WiredRxPackets int64 `json:"wired-rx_packets"` - WiredTxBytes int64 `json:"wired-tx_bytes"` - WiredTxBytesR int64 `json:"wired-tx_bytes-r"` - WiredTxPackets int64 `json:"wired-tx_packets"` -} diff --git a/core/unifi/v4/devices.go b/core/unifi/v4/devices.go deleted file mode 100644 index d877d9c4..00000000 --- a/core/unifi/v4/devices.go +++ /dev/null @@ -1,107 +0,0 @@ -package unifi - -import ( - "encoding/json" - "fmt" -) - -// GetDevices returns a response full of devices' data from the UniFi Controller. -func (u *Unifi) GetDevices(sites Sites) (*Devices, error) { - devices := new(Devices) - - for _, site := range sites { - var response struct { - Data []json.RawMessage `json:"data"` - } - - devicePath := fmt.Sprintf(APIDevicePath, site.Name) - if err := u.GetData(devicePath, &response); err != nil { - return nil, err - } - - loopDevices := u.parseDevices(response.Data, site.SiteName) - devices.UAPs = append(devices.UAPs, loopDevices.UAPs...) - devices.USGs = append(devices.USGs, loopDevices.USGs...) - devices.USWs = append(devices.USWs, loopDevices.USWs...) - devices.UDMs = append(devices.UDMs, loopDevices.UDMs...) - } - - return devices, nil -} - -// parseDevices parses the raw JSON from the Unifi Controller into device structures. -func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { - devices := new(Devices) - - for _, r := range data { - // Loop each item in the raw JSON message, detect its type and unmarshal it. - assetType := "" - - if o := make(map[string]interface{}); u.unmarshalDevice("map", r, &o) != nil { - continue - } else if t, ok := o["type"].(string); ok { - assetType = t - } - - u.DebugLog("Unmarshalling Device Type: %v, site %s ", assetType, siteName) - // 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, SourceName: u.URL} - 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, SourceName: u.URL} - 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, SourceName: u.URL} - if u.unmarshalDevice(assetType, r, dev) == nil { - dev.Name = pick(dev.Name, dev.Mac) - devices.USWs = append(devices.USWs, dev) - } - case "udm": - dev := &UDM{SiteName: siteName, SourceName: u.URL} - if u.unmarshalDevice(assetType, r, dev) == nil { - dev.Name = pick(dev.Name, dev.Mac) - devices.UDMs = append(devices.UDMs, dev) - } - default: - u.ErrorLog("unknown asset type - %v - skipping", assetType) - } - } - - return devices -} - -// unmarshalDevice handles logging for the unmarshal operations in parseDevices(). -func (u *Unifi) unmarshalDevice(dev string, data json.RawMessage, v interface{}) (err error) { - if err = json.Unmarshal(data, v); err != nil { - u.ErrorLog("json.Unmarshal(%v): %v", dev, err) - u.ErrorLog("Enable Debug Logging to output the failed payload.") - - json, err := data.MarshalJSON() - u.DebugLog("Failed Payload: %s (marshal err: %v)", json, err) - u.DebugLog("The above payload can prove useful during torubleshooting when you open an Issue:") - u.DebugLog("==- https://github.com/golift/unifi/issues/new -==") - } - - return err -} - -// pick returns the first non empty string in a list. -// used in a few places around this library. -func pick(strings ...string) string { - for _, s := range strings { - if s != "" { - return s - } - } - - return "" -} diff --git a/core/unifi/v4/dpi.go b/core/unifi/v4/dpi.go deleted file mode 100644 index 86170d03..00000000 --- a/core/unifi/v4/dpi.go +++ /dev/null @@ -1,2366 +0,0 @@ -package unifi - -import "strconv" - -// DPITable contains DPI data for clients or sites, or .. things. -type DPITable struct { - SourceName string `json:"-"` - SiteName string `json:"-"` - Name string `json:"-"` - MAC string `json:"mac"` - ByCat []DPIData `json:"by_cat"` - ByApp []DPIData `json:"by_app"` - LastUpdated int64 `json:"last_updated"` -} - -// DPIData is the DPI data in the DPI table. -type DPIData struct { - Cat int `json:"cat"` - App int `json:"app"` - RxBytes int64 `json:"rx_bytes"` - TxBytes int64 `json:"tx_bytes"` - RxPackets int64 `json:"rx_packets"` - TxPackets int64 `json:"tx_packets"` -} - -// DPIMap allows binding methods to the DPICat and DPIApps variables. -type DPIMap map[int]string - -// Get returns a value, or an unknown placeholder. -func (d DPIMap) Get(cat int) string { - if v, ok := d[cat]; ok { - return v - } - - return "Unknown_" + strconv.Itoa(cat) -} - -// GetApp returns an app value, or an unknown placeholder. -func (d DPIMap) GetApp(cat, app int) string { - if v, ok := d[cat<<16+app]; ok { - return v - } - - return "Unknown_" + strconv.Itoa(cat<<16+app) -} - -// Keys returns the map keys in a slice. -func (d DPIMap) Keys() []string { - out := []string{} - for k := range d { - out = append(out, strconv.Itoa(k)) - } - - return out -} - -// DPICats maps the categories to descriptions. -// From: https://fw-download.ubnt.com/data/usg-dpi/1628-debian-v1.442.0-05f5a57eaef344358bd5a8e84a184c18.tar -var DPICats = DPIMap{ - 0: "Instant Messengers", - 1: "Peer-to-Peer Networks", - 3: "File Sharing", - 4: "Media Streaming", - 5: "Email Messaging", - 6: "VoIP Services", - 7: "Database Tools", - 8: "Online Games", - 9: "Management Protocols", - 10: "Remote Access", - 11: "Tunneling and Proxy", - 12: "Investment Platforms", - 13: "Web Services", - 14: "Security Updates", - 15: "Web IM", - 17: "Business Tools", - 18: "Network Protocols_18", - 19: "Network Protocols_19", - 20: "Network Protocols_20", - 23: "Private Protocols", - 24: "Social Networks", - 255: "Unknown_255", -} - -// DPIApps maps the applications to names. -// From: https://fw-download.ubnt.com/data/usg-dpi/1628-debian-v1.442.0-05f5a57eaef344358bd5a8e84a184c18.tar -var DPIApps = DPIMap{ - 1: "MSN", - 2: "Yahoo Messenger", - 3: "AIM/ICQ/iIM", - 4: "QQ/TM", - 5: "DingTalk/Laiwang", - 6: "IRC", - 7: "Yoics", - 8: "Rediff BOL", - 9: "Google Talk", - 10: "Gadu-Gadu", - 11: "Yixin", - 12: "POPO", - 13: "Tlen", - 14: "Wlt", - 15: "RenRen", - 16: "Omegle", - 17: "IPMSG", - 18: "Aliww", - 19: "Mail.ru IM", - 20: "Kubao", - 21: "Lava-Lava", - 22: "PaltalkScene", - 23: "UcTalk", - 24: "WinpopupX", - 25: "BeeTalk", - 26: "Squiggle", - 27: "Apple iMessage", - 28: "Pidgin", - 29: "ISPQ", - 30: "Momo", - 31: "ChatON", - 32: "Caihong", - 33: "KC", - 34: "IMVU", - 35: "Instan-t", - 36: "PiIM", - 37: "Xfire", - 38: "Raidcall", - 39: "Slack", - 41: "WhatsApp", - 42: "Userplane", - 43: "24im", - 44: "Camfrog", - 45: "Snow", - 46: "Digsby", - 49: "Message Send Protocol", - 52: "SOMA", - 53: "Hike", - 54: "Fetion", - 55: "Heyyo", - 56: "Alicall", - 57: "Qeshow", - 58: "MissLee", - 59: "Jctrans", - 61: "BaiduHi", - 62: "TELTEL", - 64: "9158", - 65: "Kltx", - 66: "IM+", - 67: "Imi", - 68: "Netcall", - 69: "ECP", - 72: "Etnano", - 77: "ProvideSupport", - 78: "Dudu IM", - 80: "Weibo IM", - 81: "WO", - 82: "Guagua", - 83: "Hangouts", - 84: "ClubCooee", - 85: "Palringo", - 86: "KikMessenger", - 87: "Doshow", - 88: "Mibbit", - 89: "YY", - 90: "Ispeak", - 91: "VzoChat", - 92: "Trillian", - 93: "HipChat", - 94: "IntraMessenger", - 95: "BitWise", - 96: "Barablu", - 97: "Whoshere", - 98: "LiiHo", - 99: "Appme", - 100: "Verychat", - 101: "Voxer", - 102: "TextMe", - 103: "Bump", - 104: "CoolMessenger", - 105: "NateOn", - 106: "WeChat", - 107: "Snapchat", - 108: "Wangxin", - 65538: "BitTorrent Series", - 65540: "DirectConnect", - 65542: "eDonkey Series", - 65543: "FastTrack", - 65544: "Gnutella", - 65545: "WinMX", - 65546: "Foxy", - 65547: "Winny", - 65548: "POCO", - 65549: "iMesh/Lphant", - 65550: "ClubBox", - 65551: "Vagaa", - 65553: "Thunder", - 65554: "myMusic", - 65555: "QQDownload", - 65556: "WebTorrent", - 65557: "easyMule", - 65559: "Fileguri", - 65563: "Soulseek", - 65565: "GNUnet", - 65566: "XNap", - 65567: "Avicora", - 65568: "Kceasy", - 65569: "Aria2", - 65570: "Arctic", - 65572: "Bitflu", - 65573: "BTG", - 65574: "Pando", - 65577: "Deepnet Explorer", - 65578: "aMule", - 65580: "Ares", - 65581: "Azureus", - 65582: "BCDC++", - 65583: "BitBuddy", - 65584: "BitComet", - 65585: "BitTornado", - 65587: "ApexDC++", - 65588: "Bearshare", - 65590: "BitLord", - 65591: "BitSpirit", - 65594: "Shareaza", - 65598: "eMule", - 65600: "eMule Plus", - 65604: "FileScope", - 65609: "GoGoBox", - 65612: "Hydranode", - 65617: "Kazaa Lite Tools K++", - 65620: "BitRocket", - 65621: "MlDonkey", - 65622: "MooPolice", - 65630: "Phex", - 65633: "RevConnect", - 65634: "Rufus", - 65635: "SababaDC", - 65636: "Shareaza Plus", - 65640: "BTSlave", - 65642: "TorrentStorm", - 65648: "uTorrent", - 65652: "ZipTorrent", - 65655: "BitPump", - 65665: "Tuotu", - 65685: "Vuze", - 65686: "Enhanced CTorrent", - 65688: "Bittorrent X", - 65689: "DelugeTorrent", - 65690: "CTorrent", - 65691: "Propagate Data Client", - 65692: "EBit", - 65693: "Electric Sheep", - 65695: "FoxTorrent", - 65696: "GSTorrent", - 65698: "Halite", - 65700: "KGet", - 65701: "KTorrent", - 65703: "LH-ABC", - 65704: "libTorrent", - 65705: "LimeWire", - 65707: "MonoTorrent", - 65708: "MoonlightTorrent", - 65709: "Net Transport", - 65714: "qBittorrent", - 65715: "Qt 4 Torrent example", - 65716: "Retriever", - 65718: "Swiftbit", - 65720: "SwarmScope", - 65721: "SymTorrent", - 65722: "Sharktorrent", - 65724: "TorrentDotNET", - 65725: "Transmission", - 65726: "uLeecher", - 65727: "BitLet", - 65728: "FireTorrent", - 65730: "XanTorrent", - 65731: "Xtorrent", - 65732: "Pruna", - 65733: "Soribada", - 65734: "Gample", - 65735: "DIYHARD", - 65736: "LottoFile", - 65737: "ShareBox", - 65738: "Bondisk", - 65739: "Filei", - 65740: "KDISK", - 65741: "Ondisk", - 65742: "FILEJO", - 65743: "FILEDOK", - 65744: "Tomatopang/Santa25", - 65745: "Webhard", - 65746: "TPLE", - 65747: "DiskPump", - 65748: "NETFOLDER", - 65749: "QFILE", - 65750: "DISKMAN", - 65751: "DBGO", - 65752: "Congaltan", - 65753: "Diskpot", - 65754: "Ipopclub", - 65755: "Yesfile", - 65756: "Nedisk", - 65757: "Me2disk", - 65758: "Odisk", - 65759: "Tomfile", - 65760: "Adrive.co.kr", - 65761: "ZIOfile", - 65762: "APPLEFILE", - 65763: "SUPERDOWN", - 65764: "Hidisk", - 65765: "Downs", - 65766: "DownDay", - 65767: "BOMULBOX", - 65768: "FILEHAM", - 65769: "Tdisk", - 65770: "Filehon", - 65771: "Jjangfile", - 65772: "Onehard.com", - 65773: "Pdpop", - 65774: "AirFile", - 65775: "FILEZZIM", - 65776: "Atomfile.co.kr", - 65777: "QDOWN.com", - 65778: "Alfile.net", - 65779: "Bigfile.co.kr", - 65780: "Hardmoa.com", - 65781: "Redfile.co.kr", - 65782: "FILETV.co.kr", - 65783: "Now.co.kr", - 65784: "JustBeamIt", - 65785: "reep.io", - 65786: "GnucDNA/Gimme", - 65787: "MyNapster", - 196609: "FTP Applications", - 196610: "GetRight", - 196611: "FlashGet", - 196612: "AsianDVDClub", - 196613: "Web File Transfer", - 196614: "FileZilla", - 196615: "Kuaipan", - 196616: "DBank", - 196617: "115.com", - 196618: "Weiyun", - 196619: "Rayfile", - 196620: "0zz0", - 196621: "Herosh", - 196622: "2Shared", - 196624: "BIZHARD", - 196626: "UPlusBox", - 196627: "Filebox.ro", - 196628: "Qnext", - 196629: "OneDrive", - 196630: "YunFile", - 196631: "Filehosting", - 196632: "Dev-Host", - 196633: "Solidfiles", - 196634: "IBackup", - 196635: "FileSwap", - 196637: "Temp-Share", - 196638: "WikiUpload", - 196640: "MEGA", - 196641: "Copy.com", - 196642: "4Shared", - 196643: "HiCloud", - 196644: "Depositfiles", - 196645: "Docstoc", - 196646: "360 Cloud", - 196647: "Symantec Nomdb", - 196648: "Baidu Cloud", - 196649: "GitHub", - 196650: "FileDropper", - 196651: "CrashPlan", - 196652: "Net2FTP", - 196653: "Mediafire", - 196655: "Carbonite", - 196656: "Mozy", - 196657: "SOS Online Backup", - 196670: "NFS", - 196672: "WD My Cloud", - 196676: "Box", - 196678: "Scribd", - 196680: "Rapidshare", - 196681: "Sendspace", - 196683: "Hightail", - 196684: "Diino", - 196686: "Fluxiom", - 196689: "Nomadesk", - 196692: "Dropbox", - 196693: "Filesend.to", - 196694: "Firestorage", - 196695: "Naver Cloud", - 196696: "Filesend.net", - 196697: "Crocko", - 196700: "Fileserve", - 196701: "Netload", - 196702: "Megashares", - 196703: "TransferBigFiles", - 196705: "Filemail", - 196706: "Zamzar", - 196708: "Divshare", - 196709: "DL Free", - 196711: "Nakido", - 196713: "Gigaup", - 196714: "Filestube", - 196716: "Filer.cx", - 196717: "Cx.com", - 196718: "Elephantdrive", - 196722: "Zshare", - 196723: "Freakshare", - 196724: "Uploading", - 196725: "Bitshare", - 196726: "Letitbit.net", - 196727: "Extabit", - 196728: "Filefactory", - 196729: "Furk", - 196731: "GoldFile", - 196732: "GigaSize", - 196733: "Turbobit", - 196735: "Hitfile", - 196737: "Zippyshare", - 196738: "SoundCloud", - 196739: "SpeedyShare", - 196741: "WinSCP", - 196742: "FilePost.net", - 196743: "GlumboUploads", - 196744: "RapidGator.net", - 196745: "GoZilla", - 196746: "Clip2net", - 196747: "Datei.to", - 196748: "Totodisk", - 196749: "LeapFile", - 196750: "BigUpload", - 196751: "OnlineFileFolder", - 196752: "ASUSWebStorage", - 196753: "File-Upload.net", - 196754: "File-Works", - 196755: "Zumodrive", - 196756: "PutLocker", - 196757: "Wetransfer", - 196758: "iCloud", - 196759: "CloudMe", - 196760: "Beanywhere", - 196761: "Sugarsync", - 196762: "DriveHQ", - 196763: "Yandex.Disk", - 196764: "Backblaze", - 196765: "AirSet", - 196766: "SpiderOak", - 196767: "1337X", - 196768: "MailBigFile", - 196769: "GoldCoupon.co.kr", - 196770: "Egnyte", - 196771: "SmugMug", - 196772: "SlideShare.net", - 196773: "4Sync", - 196774: "IDrive", - 196775: "Mendeley", - 196777: "Daum-cloud", - 196778: "TeamBeam", - 262145: "Windows Media Player", - 262146: "RealPlayer", - 262147: "Winamp", - 262148: "QuickTime", - 262149: "Weather Channel", - 262150: "PPTV (PPLive)", - 262151: "QQLive", - 262152: "LOVEFiLM", - 262153: "ITV", - 262154: "iTunes", - 262155: "Adobe Flash", - 262156: "Channel 5", - 262157: "iQIYI/PPS", - 262158: "Headweb", - 262159: "Viaplay", - 262160: "KKBox", - 262161: "WATCHEVER", - 262162: "Maxdome", - 262163: "Twitch.tv", - 262164: "TED", - 262165: "RTP", - 262166: "SBS", - 262167: "UUSee", - 262168: "SopCast", - 262169: "KeyHoleTV", - 262170: "Sina Video", - 262171: "Metacafe", - 262172: "Wuaki.tv", - 262173: "SHOUTcast", - 262174: "BBC-iplayer", - 262175: "Live365", - 262176: "Dailymotion", - 262177: "Filmin", - 262178: "Flixster", - 262179: "Hulu", - 262180: "GuaGua", - 262181: "NUBEOX", - 262182: "Kugou", - 262183: "MoveNetworks", - 262184: "Babelgum", - 262185: "Livestation", - 262186: "Apple Music", - 262187: "Miro", - 262188: "Smithsonian Channel", - 262189: "NHL", - 262190: "NicoNico", - 262191: "Ooyala", - 262192: "Photobucket", - 262193: "MLSsoccer", - 262194: "Channel 4", - 262195: "VideoDetective", - 262196: "Ustream.tv", - 262197: "Veetle", - 262198: "VeohTV", - 262199: "iTunes Festival", - 262200: "SiriusXM", - 262201: "Break.com", - 262202: "CinemaNow/FilmOn", - 262203: "Letv", - 262204: "RTSP", - 262205: "Funshion", - 262206: "17", - 262207: "MTV.com", - 262208: "Sohu TV", - 262209: "MP4", - 262210: "MMS/WMSP", - 262211: "FLV", - 262212: "PIPI", - 262213: "Hulkshare", - 262214: "Tudou", - 262215: "Ifeng Video ", - 262216: "WSJ Live", - 262217: "Cradio", - 262218: "Roku", - 262219: "Amazon Prime Music", - 262220: "Crackle", - 262221: "Blip.tv", - 262223: "Audible", - 262224: "Web Streaming", - 262225: "DIRECTV", - 262226: "Vyclone", - 262227: "China Streaming Video", - 262228: "Crunchyroll", - 262229: "EmpFlix", - 262230: "Porn.com", - 262231: "EskimoTube", - 262232: "NewBigTube", - 262233: "Madbitties", - 262234: "RTMP", - 262235: "Hustlertube", - 262236: "TnaFlix", - 262237: "Xtube", - 262238: "Yobt.tv", - 262239: "Youjizz", - 262240: "v.163.com", - 262241: "Yahoo Video", - 262245: "Pandora", - 262246: "Deezer", - 262247: "VLC", - 262250: "Livesearch.tv/CoolStreaming", - 262251: "Qello", - 262252: "CNTV", - 262254: "Thunderkankan", - 262256: "Youtube", - 262258: "56.com", - 262259: "RMVB", - 262260: "Youku.com", - 262261: "SWF", - 262262: "AVI", - 262263: "MP3", - 262264: "WMA", - 262265: "MOV", - 262266: "WMV", - 262267: "ASF", - 262268: "Vudu", - 262270: "PBS Video", - 262271: "Freecast", - 262272: "Ku6", - 262274: "Spotify", - 262275: "LastFM", - 262276: "Netflix", - 262277: "Uitzendinggemist", - 262278: "RTL.nl", - 262279: "TudouVa", - 262280: "GYAO", - 262281: "BARKS", - 262283: "Baofeng", - 262284: "Qvod/Bobohu", - 262285: "Grooveshark", - 262286: "Microsoft Silverlight", - 262287: "6.cn", - 262288: "Rhapsody", - 262289: "Kideos", - 262290: "Imgo TV", - 262291: "Joy.cn", - 262292: "Yinyuetai", - 262293: "Hichannel", - 262294: "ADNstream", - 262295: "Livestream", - 262296: "YoukuVa ", - 262297: "Kodi", - 262298: "Voddler", - 262299: "National Geographic Kids", - 262301: "Flixwagon", - 262302: "M4V", - 262303: "Podcast", - 262305: "Shazam", - 262306: "TuneIn", - 262307: "PBS Kids", - 262308: "BaiduMusic", - 262310: "DoubanFM", - 262311: "IMDb.com", - 262312: "XVideos.com", - 262313: "xHamster.com", - 262314: "PornHub.com", - 262315: "LiveJasmin.com", - 262316: "XNXX.com", - 262317: "YouPorn.com", - 262318: "MajorLeagueGaming", - 262319: "Wowtv.co.kr", - 262320: "iMBC", - 262321: "AfreecaTV", - 262322: "Arirang", - 262323: "KCTVjeju", - 262324: "CJB.co.kr", - 262325: "MBN", - 262326: "MYSolive", - 262327: "KBS", - 262328: "Mwave", - 262329: "YTN", - 262330: "Musicsoda", - 262331: "FreeOnes.com", - 262332: "Streamate.com", - 262333: "Airplay", - 262334: "DAAP", - 262335: "M1905", - 262336: "VEVO", - 262337: "Amazon Instant Video", - 262338: "MixBit", - 262339: "Baomihua", - 262340: "FORA.tv", - 262341: "Vimeo", - 262342: "Vube", - 262343: "RedTube.com", - 262344: "Tube8", - 262345: "Mgoon", - 262346: "Trailers", - 262347: "HBOGO", - 262348: "MLB.com", - 262349: "Kaltura.com", - 262350: "Plex.tv", - 262351: "DouyuTV", - 262358: "Kids.gov", - 262367: "Periscope", - 262373: "HBO NOW", - 262374: "MiaoPai", - 262389: "UniFi Video Camera", - 327681: "SMTP", - 327682: "POP3", - 327683: "IMAP4", - 327684: "NNTP", - 327685: "Twig", - 327686: "GroupWise", - 327687: "au one net", - 327688: "Virtru", - 327689: "PChome", - 327690: "DTI MyMail", - 327691: "Ymail", - 327692: "IIJ MailViewer", - 327693: "Telenet Mail", - 327694: "Open Mail", - 327695: "InfoSphere Webmail", - 327696: "Goo Mail", - 327697: "Nifty", - 327698: "QQ Mail", - 327699: "Roundcubemail", - 327700: "Zenno", - 327701: "Itm-asp", - 327702: "Biglobe", - 327703: "SquirrelMail", - 327704: "Zoho Mail", - 327705: "Inter7", - 327706: "TOK2", - 327707: "Smoug", - 327708: "1und1", - 327709: "Plala", - 327710: "WAKWAK", - 327711: "Eyejot", - 327712: "AsahiNet", - 327713: "Aikq", - 327714: "Yandex.Mail", - 327715: "Arcor", - 327716: "Bluewin", - 327717: "Directbox", - 327718: "Freenet", - 327720: "Smart Mail", - 327722: "WEB.DE", - 327723: "MS Exchange Server", - 327732: "Webmail.de", - 327742: "NETEASE Mail", - 327743: "Gmx Mail", - 327744: "Excite", - 327745: "InfoSeek Mail", - 327746: "Livedoor", - 327747: "Nate Mail", - 327749: "Optimum", - 327751: "Secureserver", - 327753: "Sina Mail", - 327755: "Rambler", - 327760: "Daum Mail", - 327761: "Mail.com", - 327762: "OCN", - 327763: "MailChimp", - 327764: "Rediff Mail", - 327770: "Korea Mail", - 327772: "MyEmail", - 327773: "JumboMail", - 327775: "Gmail", - 327776: "AOL Mail", - 327777: "hiBox", - 327778: "COX", - 327779: "Hushmail", - 327780: "Mail.ru", - 327781: "HiNet Mail", - 327782: "Horde", - 327783: "Fastmail", - 327784: "Comcast", - 327785: "Laposte", - 327786: "Yahoo Mail", - 327787: "Usermin Mail", - 327788: "Tistory", - 327789: "Orange", - 327790: "012mail", - 327791: "T-Online", - 327792: "Jubii Mail", - 327793: "Whalemail", - 327794: "Lavabit", - 327795: "Tiscali", - 393217: "Skype", - 393218: "H.323", - 393220: "Facetime", - 393221: "Juiker", - 393222: "Sqwiggle", - 393223: "ooVoo", - 393225: "TeamSpeak", - 393226: "Ventrilo", - 393228: "SIP", - 393229: "NetMeeting", - 393230: "Inter-Asterisk", - 393231: "Net2Phone", - 393232: "MSRP", - 393234: "LINE", - 393235: "Fring", - 393236: "Goober", - 393238: "Viber", - 393239: "Kakao", - 393240: "iCall", - 393242: "Nimbuzz", - 393243: "Bobsled", - 393244: "indoona", - 393245: "Wi-Fi Calling", - 393246: "Tango", - 393247: "Ooma", - 458753: "MSSQL", - 458754: "MySQL", - 458755: "Oracle", - 458756: "PostgreSQL", - 458757: "SAP", - 458760: "Etelos", - 458761: "Centriccrm", - 458766: "MongoDB", - 458767: "Salesforce", - 458768: "MariaDB", - 524289: "QQ Game", - 524290: "Our Game", - 524291: "Cga.com", - 524292: "FIFA", - 524293: "PopKart", - 524294: "Archlord", - 524295: "AddictingGames.com", - 524296: "Realgame", - 524297: "Audition", - 524298: "Koramgame", - 524299: "BnB Game", - 524300: "Chinagame", - 524301: "CS Game", - 524302: "Diablo", - 524303: "Legend", - 524304: "Lineage", - 524306: "Quake Game", - 524307: "Diablo3", - 524308: "Sina Web Game", - 524310: "WOW Game", - 524311: "Ispeakgame", - 524312: "Torchlight2", - 524313: "MapleStory", - 524314: "TowerOfSaviors", - 524315: "Wolfenstein", - 524316: "Second Life", - 524317: "Kimi", - 524318: "Pokemon Go", - 524319: "PartyPoker", - 524320: "Pogo", - 524321: "PokerStars", - 524322: "Zango", - 524323: "Little Fighter 2", - 524324: "BomberClone", - 524325: "Doom", - 524326: "FSJOY", - 524327: "175pt", - 524328: "Zhuxian", - 524329: "GameTea/GameABC", - 524330: "Talesrunner", - 524331: "PK Game", - 524332: "Concerto Gate", - 524333: "TLBB", - 524334: "YBOnline", - 524335: "Xunyou", - 524336: "Mwo", - 524337: "Mobile Strike", - 524338: "WuLin", - 524339: "DNF Game", - 524340: "Bo Game", - 524341: "Gran Turismo", - 524343: "Electronic Arts", - 524344: "ZhengTu", - 524345: "SGOL", - 524346: "XY2Online", - 524347: "Asherons Call", - 524348: "Kali", - 524349: "EverQuest", - 524350: "XBOX", - 524351: "BrettspielWelt", - 524352: "Bet-at-Home", - 524353: "City of Heroes", - 524354: "ClubPenguin", - 524355: "StepMania", - 524356: "Battle.net", - 524358: "Apprentice", - 524359: "Monster Hunter Frontier Z", - 524360: "FreeLotto Game", - 524361: "Halo", - 524362: "iSketch", - 524363: "RuneScape", - 524364: "FUNMILY", - 524365: "Yeapgame", - 524366: "Grand Theft Auto", - 524367: "Lineage2", - 524368: "GM99 Game", - 524369: "RayCity", - 524370: "Rockstar Games", - 524371: "Aleph One", - 524372: "Wayi", - 524373: "CMWEBGAME", - 524374: "Call of Duty", - 524375: "CAPTAN", - 524376: "Supercell", - 524377: "Need for Speed", - 524379: "Madden NFL", - 524380: "Half-Life", - 524381: "Team Fortress", - 524383: "Final Fantasy", - 524384: "Mythic", - 524385: "NetPanzer", - 524386: "Sdo.com", - 524388: "Pokemon Netbattle", - 524389: "RunUO-Ultima", - 524390: "Soldat Dedicated", - 524391: "Blizzard Entertainment", - 524392: "RIFT", - 524393: "TetriNET", - 524394: "Tibia", - 524395: "PlanetSide", - 524396: "TripleA", - 524398: "Unreal", - 524399: "Valve Steam", - 524400: "WesNOth", - 524401: "Xpilot", - 524402: "Swtor", - 524403: "EVEOnline", - 524404: "Hearthstone", - 524405: "Guild Wars", - 524406: "Zhong Hua Hero", - 524407: "Wizard101", - 524408: "SD Gundam", - 524409: "Prius", - 524410: "Age of Conan", - 524411: "RF Returns", - 524412: "AION", - 524413: "POPO Game", - 524414: "War-Rock", - 524415: "TEN Game", - 524416: "LUNA2", - 524417: "Karos", - 524418: "SPOnline", - 524419: "RO Game", - 524420: "StarCraft2", - 524421: "Itaiwanmj", - 524422: "CMWEBGAME Game", - 524423: "Beanfun Game", - 524424: "JXW", - 524425: "Nobol", - 524426: "DragonNest", - 524427: "BBonline", - 524428: "Hangame", - 524429: "Homygame", - 524430: "Sony PlayStation", - 524431: "Garena", - 524432: "91555", - 524433: "JJ Game", - 524434: "YHgame", - 524435: "Mdm365", - 524436: "7fgame", - 524437: "Dokee", - 524438: "VSA", - 524439: "Funtown", - 524440: "SF Game", - 524441: "173kh", - 524442: "Boyaapoker", - 524443: "GameCenter", - 524444: "Minecraft", - 524445: "Dark Souls", - 524446: "The Secret World", - 524447: "World2", - 524448: "CrossFire", - 524449: "XYQ", - 524450: "Nexon", - 524451: "Vindictus", - 524452: "DotA", - 524453: "PAYDAY", - 524454: "Wayi Game", - 524455: "War Thunder", - 524456: "Warframe", - 524457: "TT-Play Game", - 524458: "TT-Play", - 524459: "Robocraft", - 524460: "World of Tanks", - 524461: "Divinity", - 524462: "Left 4 Dead 2", - 524463: "DayZ", - 524464: "Heroes of the Storm", - 524466: "TXWY Game", - 524476: "Smite", - 524478: "FreeStyle 2 Street Basketball", - 524479: "Yeapgame Game", - 524483: "BlackShot", - 524486: "Combat Arms", - 524490: "Blade and Soul", - 524491: "FUNMILY Game", - 524500: "Elsword", - 524501: "Echo of Soul", - 524502: "Aura Kingdom", - 524503: "Aeria Games", - 524504: "9-yin", - 524505: "Tera", - 524506: "PSO2", - 524507: "Mabinogi", - 524510: "Ubisoft", - 524512: "Sony Entertainment Network", - 524513: "WSOP", - 524514: "TexasHoldemPoker", - 524515: "DarkSummoner", - 524516: "AjaxPlay", - 524517: "AirlineMogul", - 524518: "Evony", - 524519: "BasketBallZone", - 524520: "Y8 Game", - 524521: "Y8-Y8", - 524522: "KIZI-GAMES", - 524523: "Ibibo", - 524524: "Hattrick Game", - 524525: "Godgame", - 524526: "Aswordtw", - 524527: "Qme RO", - 524529: "THE WORLD", - 524530: "Qme JH", - 524531: "Qme COS", - 524532: "Qme SG", - 524533: "Origin", - 524534: "LoL", - 524535: "THISISGAME", - 524536: "Miniclip Game", - 524537: "888games", - 524538: "WilliamHill", - 524539: "Betfair Game", - 524540: "Kongregate Game", - 524541: "Roblox Game", - 524542: "King Game", - 524543: "Chess Game", - 524593: "Overwatch", - 524632: "Battlefield", - 524633: "Star Wars Battlefront", - 524639: "Rainbow Six Siege", - 524640: "ARK Survival Evolved", - 524641: "The Division", - 524648: "Super Mario Run", - 524649: "Nintendo", - 524651: "Clash of Clans", - 524652: "Clash Royale", - 524736: "Grand Theft Auto: San Andreas", - 524782: "Destiny 2", - 524790: "NBA 2K18", - 524794: "Uncharted: The Lost Legacy", - 524795: "NHL 18", - 524796: "NBA Live 18", - 524801: "Wargaming.net", - 589828: "IGMP", - 589829: "SNMP", - 589885: "DNS", - 589888: "Multicast DNS", - 589890: "Finger protocol", - 589916: "DCE-RPC", - 589933: "SSDP", - 589934: "SMB", - 589936: "SMB2", - 589942: "ICMP", - 589951: "UPnP", - 655361: "pcAnywhere", - 655362: "VNC", - 655363: "TeamViewer", - 655364: "MS Remote Desktop Protocol (RDP)", - 655365: "Chrome Remote Desktop", - 655366: "NTRglobal", - 655367: "RemoteCall", - 655368: "LiveCare", - 655369: "GoToMyPC", - 655370: "Pulseway", - 655371: "Radmin", - 655372: "Beinsync", - 655373: "Fastviewer", - 655374: "CrossTec Remote Control", - 655375: "GoToMeeting", - 655376: "ShowMyPC", - 655377: "Join.me", - 655378: "Telnet", - 655379: "Techinline", - 655380: "ISL Online", - 655381: "Secure Shell (SSH)", - 655385: "IBM Remote monitoring and Control", - 655395: "Netviewer", - 655396: "VT100", - 655397: "AnyDesk", - 655398: "X11", - 655399: "Alpemix", - 655402: "Instanthousecall", - 655403: "Ammyy", - 655404: "Anyplace Control", - 655405: "BeamYourScreen", - 655406: "Laplink Everywhere", - 655407: "GoToAssist", - 655408: "MSP Anywhere", - 720898: "VNN", - 720899: "Spotflux", - 720900: "SoftEther/PacketiX", - 720901: "TinyVPN", - 720902: "HTTP-Tunnel", - 720903: "Tor", - 720904: "Ping Tunnel", - 720905: "Wujie/UltraSurf", - 720906: "Freegate", - 720907: "Hidemyass", - 720909: "Vedivi", - 720910: "ZenMate", - 720911: "Hamachi", - 720912: "Disconnect.me", - 720914: "Asproxy", - 720915: "OpenDoor", - 720916: "NSTX DNS Tunnel", - 720917: "Coralcdn", - 720918: "Glype", - 720919: "GPass", - 720920: "Kproxy", - 720921: "Megaproxy", - 720922: "FreeSafeIP", - 720924: "GreenVPN", - 720925: "Surrogafier", - 720926: "Vtunnel", - 720927: "GomVPN", - 720928: "BypassThat", - 720929: "GetPrivate", - 720930: "JAP/JonDo", - 720933: "SofaWare", - 720934: "FlyProxy", - 720936: "Kerberos", - 720939: "EasyHideIP", - 720942: "CPROXY", - 720943: "AnonyMouse", - 720945: "Avoidr", - 720946: "Hidedoor", - 720948: "CGIProxy", - 720949: "ProxyTopSite", - 720950: "Phproxy", - 720951: "OpenVPN", - 720952: "CCProxy", - 720953: "Proxy Rental", - 720954: "PD-Proxy", - 720955: "Proxy4Free", - 720957: "Hideman", - 720959: "Rtmpt", - 720960: "LogMeIn", - 720961: "HotspotShield", - 720962: "ExpressVPN", - 720963: "GogoNET", - 720964: "HTTP Proxy Server", - 720965: "Hola", - 720966: "Texasproxy", - 720967: "Ourproxy", - 720968: "Proxify", - 720969: "Fast Proxy", - 720970: "Zalmos", - 720971: "Easy Proxy", - 720972: "Proxy Era", - 720973: "DotVPN", - 720974: "BrowSec", - 720976: "Unblock Proxy", - 720977: "Air-Proxy", - 720978: "Suresome", - 720979: "Defilter", - 720980: "SSLunblock", - 720983: "K12History", - 720984: "SurfEasy", - 720985: "Frozenway", - 720986: "CyberGhostVPN", - 720987: "SecurityKISS", - 720988: "WebWarper", - 720989: "Guardster", - 720990: "ProxFree", - 720991: "TunnelBear", - 720992: "AstrillVPN", - 720993: "Hide ALL IP", - 720994: "ZfreeZ", - 720995: "IPVanish", - 720996: "PrivateTunnel", - 720997: "SaferSurf", - 720998: "SecureLine VPN", - 720999: "Steganos VPN", - 721000: "StrongVPN", - 721001: "ZeroTier", - 721002: "Ngrok", - 721003: "Pagekite", - 721004: "Goproxing", - 721005: "VPN.HT", - 721006: "Betternet", - 721007: "Hide My IP", - 721008: "Stay Invisible", - 721009: "Zapyo", - 721010: "NordVPN", - 721011: "Avast SecureLine", - 721013: "Tunnello", - 721014: "Opera VPN", - 786434: "DZH", - 786435: "10JQKA", - 786437: "Qianlong", - 786438: "Compass.cn", - 786439: "Huaan", - 786440: "StockStar ", - 786441: "TDX", - 786443: "Hexun", - 786444: "Hypwise", - 786449: "Kiwoom", - 786450: "Windin", - 786451: "SamsungPoP", - 786453: "StockTrace", - 786454: "JRJ", - 786455: "TradeFields", - 786456: "Bloomberg", - 786457: "Netdania", - 786458: "TradeInterceptor", - 851969: "WhiteHat Aviator", - 851970: "HTC Widget", - 851971: "Doodle", - 851972: "Level3", - 851973: "FuzeMeeting", - 851974: "Mobile01", - 851975: "Speedtest.net", - 851976: "Google Chrome", - 851977: "Babelfish", - 851978: "Google Translate", - 851980: "Mozilla Firefox", - 851981: "Apple Safari", - 851982: "Opera browser", - 851984: "Google Books", - 851985: "eBay", - 851986: "hao123", - 851987: "WebSocket", - 851988: "Tmall", - 851989: "PayPal.com", - 851990: "Ask.com", - 851991: "BBC", - 851992: "Alibaba.com", - 851993: "CNN.com", - 851995: "Sogou.com", - 851996: "Evernote", - 851997: "About.com", - 851998: "Alipay.com", - 851999: "Imgur", - 852000: "Adcash", - 852001: "Huffington Post", - 852002: "360buy", - 852003: "ESPN", - 852004: "Books", - 852005: "Craigslist.org", - 852006: "Google Analytics", - 852007: "Bing Maps", - 852008: "ETtoday ", - 852009: "104 Job Bank", - 852010: "NOWnews", - 852011: "518 Job Bank", - 852012: "Chinatimes.com", - 852013: "GOHAPPY", - 852014: "591", - 852015: "8591", - 852016: "Chinatrust", - 852017: "Donga.com", - 852018: "Gmarket", - 852019: "Chosun.com", - 852020: "Cafe24.com", - 852021: "11st", - 852022: "MK.co.kr", - 852023: "Auction", - 852024: "Hankyung", - 852025: "Ppomppu", - 852026: "MT.co.kr", - 852027: "Zum.com", - 852028: "Hankooki", - 852029: "JOBKOREA", - 852031: "Khan.co.kr", - 852032: "Incruit", - 852033: "YES24", - 852034: "Amazon CloudFront", - 852035: "Pcstore", - 852036: "Myfreshnet.com", - 852037: "Microsoft.com", - 852038: "Life.com.tw", - 852039: "Libertytimes", - 852040: "Lativ", - 852041: "Inven", - 852042: "cnYES", - 852043: "Babyhome", - 852044: "8comic.com", - 852045: "Ck101.com", - 852046: "Taiwanlottery", - 852047: "Momoshop", - 852048: "Eyny.com", - 852049: "Yam.com", - 852050: "PChome.com", - 852051: "Gamme", - 852052: "Apple.com", - 852053: "Hinet.net", - 852054: "Google Earth", - 852055: "Saramin", - 852056: "KoreaHerald", - 852057: "Plus28.com", - 852058: "ChunghwaPost ", - 852059: "Gomaji ", - 852060: "NewSen", - 852061: "Etnews.com", - 852062: "Seoul.co.kr", - 852063: "YONHAPNEWS", - 852064: "Etoday.co.kr", - 852065: "Yesky.com", - 852066: "1111 Job Bank", - 852067: "Emart", - 852068: "KBstar", - 852069: "HERALDCORP", - 852070: "ActiveX", - 852071: "MSN.com", - 852072: "Edaily", - 852073: "Segye", - 852074: "Bobaedream", - 852075: "Nocutnews", - 852076: "MONETA.co.kr", - 852077: "Kukinews", - 852078: "Java Applet", - 852079: "Todayhumor", - 852080: "Inews24", - 852081: "KoreaTimes", - 852082: "OhmyNews", - 852083: "Aladin.co.kr", - 852084: "SK Encar", - 852085: "eTorrent", - 852086: "TVREPORT", - 852087: "Mydaily", - 852088: "Microsoft Live.com", - 852089: "News1.kr", - 852090: "Munhwa", - 852091: "Dreamwiz", - 852092: "Dailian.co.kr", - 852093: "Rediff.com", - 852094: "Akamai.net", - 852096: "Microsoft Edge", - 852097: "Yugma", - 852098: "TPB PirateBrowser", - 852099: "Android browser", - 852100: "Wikispaces", - 852101: "Wikidot", - 852102: "Google Play", - 852103: "Wetpaint", - 852104: "Windows Store", - 852105: "Webshots", - 852106: "Kindle Cloud Reader", - 852107: "Nice264", - 852108: "Symbian browser", - 852109: "Vyew", - 852110: "TikiWiki", - 852111: "Castfire", - 852112: "Mercari", - 852113: "SugarCRM", - 852115: "Stumbleupon", - 852116: "Yahoo Shopping", - 852117: "Clothes Aoyama", - 852118: "Rakuten Shopping", - 852119: "Spark", - 852120: "Socialtext", - 852121: "CacaoWeb", - 852122: "PBworks", - 852123: "Fool", - 852124: "Showbie", - 852125: "MorningStar", - 852126: "Screaming Frog SEO Spider", - 852127: "MoinMoin", - 852128: "AppStore", - 852129: "Ragingbull", - 852130: "Daum", - 852131: "Google Docs", - 852133: "Naver", - 852134: "Editgrid", - 852135: "Jaspersoft", - 852136: "Clarizen", - 852139: "Interpark", - 852140: "Hyundaihmall", - 852141: "Groupon", - 852142: "Gsshop", - 852143: "Wemakeprice", - 852144: "Lotte.com", - 852145: "Coupang", - 852147: "Google Alerts", - 852149: "Dnshop.com", - 852150: "ZoomSpider crawler", - 852151: "Win Web Crawler", - 852152: "HTTrack crawler", - 852153: "Abot crawler", - 852154: "Googlebot crawler", - 852155: "Microsoft bingbot crawler", - 852156: "Yahoo Slurp crawler", - 852157: "Beanfun", - 852158: "QUIC", - 852159: "ifeng.com", - 852160: "Conduit Mobile", - 852161: "Rakuten Point", - 852162: "Gamebase", - 852163: "Kingstone", - 852164: "Udn.com", - 852165: "Fril", - 852166: "Sportsseoul", - 852167: "Babylon ", - 852168: "Yahoo Finance", - 852170: "Creative Cloud", - 852171: "Jira", - 852172: "PHPwiki", - 852173: "Rakuten Edy", - 852174: "WebCT", - 852175: "Youseemore", - 852176: "Zwiki-editing", - 852177: "Adobe.com", - 852178: "Backpackit/Campfire", - 852180: "ERoom-net", - 852182: "DiDiTaxi", - 852184: "Glide", - 852186: "Mediawiki", - 852187: "fitbit", - 852188: "LastPass", - 852189: "National Geographic", - 852190: "HTTP", - 852191: "AOL Toolbar", - 852192: "Yandex.Browser", - 852193: "Uber", - 852194: "Web-crawler", - 852195: "RSS", - 852196: "WeatherBug", - 852197: "Yahoo Toolbar", - 852198: "Alexa Toolbar", - 852199: "Internet Archive", - 852200: "Wikipedia", - 852201: "Wiktionary", - 852202: "Amazon", - 852203: "Google Toolbar", - 852205: "Zoho", - 852206: "Microsoft Internet Explorer", - 852207: "Localmind", - 852208: "LinkedIn Pulse", - 852209: "BookU", - 852210: "Zappos", - 852211: "Expedia", - 852212: "AdF.ly", - 852213: "Baidu", - 852214: "Yahoo", - 852215: "Taobao", - 852216: "163.com", - 852217: "Sina.com", - 852218: "Bing.com", - 852219: "Ruten", - 852220: "Shop.com", - 852221: "Appledaily", - 852222: "CWB", - 852223: "CNA", - 852224: "Harvey Norman", - 852225: "Hackpad", - 852226: "JB Hi-Fi", - 852227: "MyDeal.com.au", - 852228: "AUSHOP", - 852229: "CrazySales", - 852230: "Giphy", - 852231: "Riffsy", - 852232: "Gumtree", - 852233: "Priceline", - 852234: "Carousell", - 852235: "Wish", - 852236: "Shein Shopping", - 852237: "Romwe", - 852238: "The Iconic", - 852239: "Boohoo", - 852240: "Aliexpress", - 852241: "ASOS", - 852242: "Catch of the Day", - 852273: "Amazon AppStream", - 917505: "TrendMicro Titanium-6-ICRC", - 917506: "TrendMicro Titanium-7-ICRC", - 917507: "TrendMicro Titanium-8-ICRC", - 917508: "BitDefender", - 917509: "360Safe", - 917510: "Rising", - 917511: "TortoiseSVN", - 917513: "Microsoft Windows Update", - 917514: "Norton", - 917515: "Sophos", - 917516: "Yum", - 917517: "MIUI", - 917518: "Adobe", - 917519: "InstallAnyWhere", - 917520: "Kaspersky", - 917521: "McAfee", - 917522: "TrendMicro", - 917523: "F-Secure", - 917524: "NOD32", - 917525: "Avast", - 917526: "Jiangmin", - 917527: "Avira", - 917528: "Emsisoft", - 917529: "Panda", - 917530: "AVG", - 917531: "PCTools", - 917532: "TrendMicro Titanium-10-ICRC", - 917533: "Outpost", - 917534: "Spybot", - 917535: "Duba", - 917536: "Apple", - 917538: "Google Update", - 917539: "TrendMicro Titanium-6-WTP", - 917540: "JAVA Update", - 917541: "SONY PC/Xperia Companion", - 917542: "SketchUp", - 917543: "Webroot", - 917544: "TrendMicro Titanium-7-WTP", - 917545: "TrendMicro Titanium-8-WTP", - 917546: "TrendMicro Titanium-10-WTP", - 917547: "TrendMicro Titanium-11-ICRC", - 917548: "TrendMicro Titanium-11-WTP", - 917549: "TrendMicro Titanium-12-ICRC", - 917550: "TrendMicro Titanium-12-WTP", - 983043: "eBuddy.com", - 983044: "iLoveIM.com", - 983047: "imo.im", - 983048: "Chikka", - 983050: "QQ Web Messenger", - 983051: "AOL Web Messenger", - 983054: "ICQ Web Messenger", - 983057: "AirAim", - 983058: "Instan-t Web Messenger", - 983065: "TaoBao AliWW", - 983069: "Gadu-Gadu Web Messenger", - 983070: "Karoo Lark", - 983072: "Web IM+", - 1114113: "WatchGuard WSM Management", - 1114114: "WatchGuard Web Management UI", - 1114115: "WatchGuard Authentication Access", - 1114117: "WatchGuard external Webblocker database fetch", - 1114118: "Livelink", - 1114119: "Altiris", - 1114120: "AMS", - 1114121: "Apache Synapse", - 1114122: "WatchGuard CLI ", - 1114124: "Webex", - 1114125: "Webex-WebOffice", - 1114128: "Avamar", - 1114129: "Avaya", - 1114130: "BackupExec", - 1114131: "Bitcoin Core", - 1114133: "Microsoft OS license", - 1114134: "Microsoft Office 2013 license", - 1114138: "BZFlag", - 1114140: "CAJO", - 1114141: "Cisco HSRP", - 1114142: "SkyDesk", - 1114144: "Microsoft Office", - 1114150: "openQRM", - 1114151: "Citrix", - 1114152: "CodeMeter", - 1114155: "Corba", - 1114158: "Cups", - 1114160: "Cvsup", - 1114161: "DameWare", - 1114167: "Db2", - 1114168: "Docker", - 1114169: "Dclink", - 1114170: "Urchin Web Analytics", - 1114172: "Applications Manager", - 1114174: "Zoom", - 1114176: "EForward-document transport system", - 1114177: "EMWIN", - 1114179: "Adobe Connect", - 1114182: "Big Brother", - 1114185: "Fuze Meeting", - 1114187: "FritzBox", - 1114188: "Skype for Business", - 1114191: "Websense", - 1114195: "Whisker", - 1114201: "HP-JetDirect", - 1114203: "VMWare", - 1114205: "IBM HTTP", - 1114206: "IBM SmartCloud", - 1114212: "IMS", - 1114213: "Informix", - 1114222: "Limelight", - 1114229: "Lawson-m3", - 1114238: "Meeting-maker", - 1114239: "Zendesk", - 1114246: "Microsoft DTC", - 1114248: "Microsoft Netlogon", - 1114250: "Microsoft Remote Web Workplace", - 1114251: "Office Sway", - 1114252: "Sharepoint-wiki", - 1114253: "Microsoft SSDP", - 1114255: "GatherPlace", - 1114269: "Xgrid", - 1114272: "Backweb", - 1114273: "Bugzilla", - 1114274: "NCube", - 1114275: "WinboxRouterOS", - 1114277: "WSO2", - 1114279: "NetFlow", - 1114289: "concur", - 1114290: "NetSupport", - 1114308: "DirectAdmin", - 1114309: "EasyBits", - 1114310: "Eiq-sec-analyzer", - 1114311: "Netbotz", - 1114312: "Aspera FASP", - 1114318: "Perforce", - 1114320: "TiVoConnect", - 1114321: "Polycom", - 1114322: "WebSphere", - 1114330: "Radacct RADIUS", - 1114334: "Securemeeting", - 1114337: "SANE", - 1114339: "WebHost", - 1114340: "CPanel", - 1114342: "Sibelius", - 1114343: "Siebel-crm", - 1114347: "SMS", - 1114350: "Spirent", - 1114351: "SPSS", - 1114352: "Subversion", - 1114355: "Tripwire", - 1114359: "WatchGuard Webblocker database transfer", - 1114361: "WatchGuard Security Event Processor logging", - 1114363: "Genesys Meeting Center", - 1114365: "Nagios", - 1114366: "Microsoft Office 365", - 1114396: "ChatWork", - 1179649: "TCP Port Service Multiplexer", - 1179650: "Management Utility", - 1179651: "Compression Process", - 1179652: "Zeroconf", - 1179653: "Echo", - 1179654: "Discard", - 1179655: "Active Users", - 1179656: "L2TP", - 1179657: "puparp", - 1179658: "vsinet", - 1179659: "maitrd", - 1179660: "Character Generator", - 1179663: "applix", - 1179664: "Net Assistant", - 1179665: "any private mail system", - 1179666: "BackOrifice", - 1179667: "AltaVista Firewall97", - 1179668: "NSW User System FE", - 1179669: "MSG ICP", - 1179670: "MSG Authentication", - 1179671: "Display Support Protocol", - 1179672: "any private printer server", - 1179673: "Time", - 1179674: "Route Access Protocol", - 1179675: "Resource Location Protocol", - 1179676: "graphics", - 1179677: "Host Name Server", - 1179678: "NIC Name", - 1179679: "MPM FLAGS Protocol", - 1179680: "Message Processing Module [recv]", - 1179681: "MPM [default send]", - 1179682: "NI FTP", - 1179683: "Digital Audit Daemon", - 1179684: "Login Host Protocol (TACACS)", - 1179685: "Remote Mail Checking Protocol", - 1179686: "IMP Logical Address Maintenance", - 1179687: "XNS Time Protocol", - 1179688: "Domain Name Server", - 1179689: "XNS Clearinghouse", - 1179690: "ISI Graphics Language", - 1179691: "XNS Authentication", - 1179692: "Mail Transfer Protocol (MTP)", - 1179693: "XNS Mail", - 1179694: "any private file service", - 1179695: "NI MAIL", - 1179696: "ACA Services", - 1179697: "VIA Systems - FTP whois++", - 1179698: "Communications Integrator (CI)", - 1179699: "TACACS-Database Service", - 1179700: "Oracle SQL-NET", - 1179701: "Bootstrap Protocol Server", - 1179702: "Bootstrap Protocol Client", - 1179703: "profile", - 1179704: "Gopher", - 1179705: "Remote Job Service", - 1179706: "any private dial out service", - 1179707: "Distributed External Object Store", - 1179708: "any private RJE service netrjs", - 1179709: "Vet TCP", - 1179710: "Finger", - 1179711: "World Wide Web HTTP", - 1179712: "Torpark", - 1179713: "XFER Utility", - 1179714: "MIT ML Device", - 1179715: "Common Trace Facility", - 1179716: "Micro Focus Cobol", - 1179717: "any private terminal link ttylink", - 1179718: "Kerberos", - 1179719: "SU MIT Telnet Gateway", - 1179720: "DNSIX Securit Attribute Token Map", - 1179721: "MIT Dover Spooler", - 1179722: "Network Printing Protocol", - 1179723: "Device Control Protocol", - 1179724: "Tivoli Object Dispatcher", - 1179725: "BSD supdupd(8)", - 1179726: "DIXIE Protocol Specification", - 1179727: "Swift Remote Virtural File Protocol", - 1179728: "linuxconf", - 1179729: "Metagram Relay", - 1179731: "NIC Host Name Server", - 1179732: "ISO-TSAP Class 0", - 1179733: "Genesis Point-to-Point Trans Net", - 1179734: "ACR-NEMA Digital Imag. & Comm. 300", - 1179735: "Mailbox Name Nameserver", - 1179736: "msantipiracy", - 1179737: "Eudora compatible PW changer", - 1179739: "SNA Gateway Access Server", - 1179740: "PostOffice V.2", - 1179742: "Portmapper RPC Bind", - 1179743: "McIDAS Data Transmission Protocol", - 1179744: "Ident Tap Authentication Service", - 1179745: "Audio News Multicast", - 1179746: "Simple File Transfer Protocol", - 1179747: "ANSA REX Notify", - 1179748: "UUCP Path Service", - 1179749: "SQL Services", - 1179751: "blackjack", - 1179752: "Encore Expedited Remote Pro.Call", - 1179753: "Smakynet", - 1179754: "Network Time Protocol", - 1179755: "ANSA REX Trader", - 1179756: "Locus PC-Interface Net Map Ser", - 1179757: "Unisys Unitary Login", - 1179758: "Locus PC-Interface Conn Server", - 1179759: "GSS X License Verification", - 1179760: "Password Generator Protocol", - 1179761: "Cisco FNATIVE", - 1179762: "Cisco TNATIVE", - 1179763: "Cisco SYSMAINT", - 1179764: "Statistics Service", - 1179765: "INGRES-NET Service", - 1179766: "NCS local location broker", - 1179767: "PROFILE Naming System", - 1179768: "NetBIOS Name Service", - 1179769: "NetBIOS Datagram Service", - 1179770: "NetBIOS Session Service", - 1179771: "EMFIS Data Service", - 1179772: "EMFIS Control Service", - 1179773: "Britton-Lee IDM", - 1179774: "Internet Message Access Protocol", - 1179775: "Universal Management Architecture", - 1179776: "UAAC Protocol", - 1179777: "iso-ip0", - 1179778: "iso-ip", - 1179779: "Jargon", - 1179780: "AED 512 Emulation Service", - 1179781: "SQL-net", - 1179782: "HEMS", - 1179783: "Background File Transfer Program (BFTP)", - 1179784: "SGMP", - 1179785: "NetSC-prod", - 1179786: "NetSC-dev", - 1179787: "SQL Service", - 1179788: "KNET VM Command Message Protocol", - 1179789: "PCMail Server", - 1179790: "NSS-Routing", - 1179791: "SGMP-traps", - 1179793: "SNMPTRAP", - 1179794: "CMIP TCP Manager", - 1179795: "CMIP TCP Agent", - 1179796: "Xerox", - 1179797: "Sirius Systems", - 1179798: "namp", - 1179799: "rsvd", - 1179800: "send", - 1179801: "Network PostScript", - 1179802: "Network Innovations Multiplex", - 1179803: "Network Innovations CL 1", - 1179804: "xyplex-mux", - 1179805: "mailq", - 1179806: "vmnet", - 1179807: "genrad-mux", - 1179808: "X Display Manager Control Protocol", - 1179809: "NextStep Window Server", - 1179810: "Border Gateway Protocol", - 1179811: "Intergraph", - 1179812: "unify", - 1179813: "Unisys Audit SITP", - 1179814: "ocbinder", - 1179815: "ocserver", - 1179816: "remote-kis", - 1179817: "KIS Protocol", - 1179818: "Application Communication Interface", - 1179819: "Plus Fives MUMPS", - 1179820: "Queued File Transport", - 1179821: "Gateway Access Control Protocol", - 1179822: "Prospero Directory Service", - 1179823: "OSU Network Monitoring System", - 1179824: "Spider Remote Monitoring Protocol", - 1179825: "Internet Relay Chat", - 1179826: "DNSIX Network Level Module Audit", - 1179827: "DNSIX Session Mgt Module Audit Redir", - 1179828: "Directory Location Service", - 1179829: "Directory Location Service Monitor", - 1179830: "SMUX", - 1179831: "IBM System Resource Controller", - 1179832: "AppleTalk Routing Maintenance", - 1179833: "AppleTalk Name Binding", - 1179834: "AppleTalk Unused", - 1179835: "AppleTalk Echo", - 1179836: "AppleTalk Zone Information", - 1179838: "Trivial Authenticated Mail Protocol", - 1179839: "ANSI Z39.50", - 1179840: "Texas Instruments", - 1179841: "ATEXSSTR", - 1179842: "IPX", - 1179843: "vmpwscs", - 1179844: "Insignia Solutions", - 1179845: "Computer Associates Intl License Server", - 1179846: "dBASE Unix", - 1179847: "Netix Message Posting Protocol", - 1179848: "Unisys ARPs", - 1179849: "Interactive Mail Access Protocol v3", - 1179850: "Berkeley rlogind with SPX auth", - 1179851: "Berkeley rshd with SPX auth", - 1179852: "Certificate Distribution Center", - 1179853: "masqdialer", - 1179854: "direct", - 1179855: "Survey Measurement", - 1179856: "inbusiness", - 1179857: "link", - 1179858: "Display Systems Protocol", - 1179859: "VAT", - 1179860: "bhfhs", - 1179862: "RAP (Route Access Protocol)", - 1179863: "Checkpoint Firewall-1", - 1179864: "Efficient Short Remote Operations", - 1179865: "openport", - 1179866: "Checkpoint Firewall-1 Management", - 1179867: "arcisdms", - 1179868: "hdap", - 1179869: "Border Gateway Multicast Protocol (BGMP)", - 1179870: "X-Bone CTL", - 1179871: "SCSI on ST", - 1179872: "Tobit David Service Layer", - 1179873: "Tobit David Replica", - 1179874: "http-mgmt", - 1179875: "personal-link", - 1179876: "Cable Port A X", - 1179877: "rescap", - 1179878: "corerjd", - 1179879: "FXP-1", - 1179880: "K-BLOCK", - 1179881: "Novastor Backup", - 1179882: "entrusttime", - 1179883: "bhmds", - 1179884: "AppleShare IP WebAdmin", - 1179885: "VSLMP", - 1179886: "magenta-logic", - 1179887: "opalis-robot", - 1179888: "DPSI", - 1179889: "decAuth", - 1179890: "zannet", - 1179891: "PKIX TimeStamp", - 1179892: "PTP Event", - 1179893: "PTP General", - 1179894: "Programmable Interconnect Point (PIP)", - 1179895: "RTSPS", - 1179896: "Texar Security Port", - 1179897: "Prospero Data Access Protocol", - 1179898: "Perf Analysis Workbench", - 1179899: "Zebra server", - 1179900: "Fatmen Server", - 1179901: "Cabletron Management Protocol", - 1179902: "mftp", - 1179903: "MATIP Type A", - 1245185: "PPTP", - 1245186: "BakBone NetVault", - 1245187: "DTAG or bhoedap4", - 1245188: "ndsauth", - 1245189: "bh611", - 1245190: "datex-asn", - 1245191: "Cloanto Net 1", - 1245192: "bhevent", - 1245193: "shrinkwrap", - 1245194: "Windows RPC", - 1245195: "Tenebris Network Trace Service", - 1245196: "scoi2odialog", - 1245197: "semantix", - 1245198: "SRS Send", - 1245200: "aurora-cmgr", - 1245201: "DTK", - 1245202: "odmr", - 1245203: "mortgageware", - 1245204: "qbikgdp", - 1245205: "rpc2portmap", - 1245206: "Coda authentication server (codaauth2)", - 1245207: "ClearCase", - 1245208: "ListProcessor", - 1245209: "Legent Corporation", - 1245210: "hassle", - 1245211: "Amiga Envoy Network Inquiry Proto", - 1245212: "NEC Corporation", - 1245213: "TIA EIA IS-99 modem client", - 1245214: "TIA EIA IS-99 modem server", - 1245215: "HP Performance data collector", - 1245216: "HP Performance data managed node", - 1245217: "HP Performance data alarm manager", - 1245218: "A Remote Network Server System", - 1245219: "IBM Application", - 1245220: "ASA Message Router Object Def.", - 1245221: "Appletalk Update-Based Routing Pro.", - 1245222: "Unidata LDM", - 1245223: "Lightweight Directory Access Protocol", - 1245224: "uis", - 1245225: "SynOptics SNMP Relay Port", - 1245226: "SynOptics Port Broker Port", - 1245228: "Meta5", - 1245229: "EMBL Nucleic Data Transfer", - 1245230: "NETscout Control Protocol", - 1245231: "Novell Netware over IP", - 1245232: "Multi Protocol Trans. Net.", - 1245233: "kryptolan", - 1245234: "ISO Transport Class 2 Non-Control over TCP", - 1245235: "Workstation Solutions", - 1245236: "Uninterruptible Power Supply", - 1245237: "Genie Protocol", - 1245238: "decap", - 1245239: "nced", - 1245240: "ncld", - 1245241: "Interactive Mail Support Protocol", - 1245242: "timbuktu", - 1245243: "Prospero Resource Manager Sys. Man.", - 1245244: "Prospero Resource Manager Node Man.", - 1245245: "DECLadebug Remote Debug Protocol", - 1245246: "Remote MT Protocol", - 1245247: "Trap Convention Port", - 1245248: "smsp", - 1245249: "infoseek", - 1245250: "bnet", - 1245251: "silverplatter", - 1245252: "onmux", - 1245253: "hyper-g", - 1245254: "ariel1", - 1245255: "smpte", - 1245256: "ariel2", - 1245257: "ariel3", - 1245258: "IBM Operations Planning and Control Start", - 1245259: "IBM Operations Planning and Control Track", - 1245260: "icad-el", - 1245261: "smartsdp", - 1245262: "Server Location", - 1245263: "ocs_cmu", - 1245264: "ocs_amu", - 1245265: "utmpsd", - 1245266: "utmpcd", - 1245267: "iasd", - 1245268: "Usenet Network News Transfer", - 1245269: "mobileip-agent", - 1245270: "mobilip-mn", - 1245271: "dna-cml", - 1245272: "comscm", - 1245273: "dsfgw", - 1245274: "dasp", - 1245275: "sgcp", - 1245276: "decvms-sysmgt", - 1245277: "cvc_hostd", - 1245278: "HTTP Protocol over TLS SSL", - 1245279: "Simple Network Paging Protocol", - 1245280: "Win2k+ Server Message Block", - 1245281: "ddm-rdb", - 1245282: "ddm-dfm", - 1245283: "DDM-SSL", - 1245284: "AS Server Mapper", - 1245285: "tserver", - 1245286: "Cray Network Semaphore server", - 1245287: "Cray SFS config server", - 1245288: "creativeserver", - 1245289: "contentserver", - 1245290: "creativepartnr", - 1245291: "macon-tcp", - 1245292: "scohelp", - 1245294: "ampr-rcmd", - 1245295: "skronk", - 1245296: "datasurfsrv", - 1245297: "datasurfsrvsec", - 1245298: "Alpes", - 1245299: "kpasswd", - 1245300: "SMTP Protocol over TLS SSL (was SSMTP)", - 1245301: "digital-vrc", - 1245302: "mylex-mapd", - 1245303: "Photuris Key Management", - 1245304: "Radio Control Protocol", - 1245305: "scx-proxy", - 1245306: "mondex", - 1245307: "ljk-login", - 1245308: "hybrid-pop", - 1245309: "tn-tl-w1", - 1245310: "Tcpnethaspsrv Protocol", - 1245311: "tn-tl-fd1", - 1245312: "ss7ns", - 1245313: "spsc", - 1245314: "iafserver", - 1245315: "WCCP", - 1245316: "loadsrv", - 1245317: "serialnumberd", - 1245318: "dvs", - 1245319: "bgs-nsi", - 1245320: "ulpnet", - 1245321: "Integra Software Management Environment", - 1245322: "Air Soft Power Burst", - 1245324: "sstats", - 1245325: "saft Simple Asynchronous File Transfer", - 1245326: "gss-http", - 1245327: "nest-protocol", - 1245328: "micom-pfs", - 1245329: "go-login", - 1245330: "Transport Independent Convergence for FNA", - 1245331: "pov-ray", - 1245332: "intecourier", - 1245333: "pim-rp-disc", - 1245334: "dantz", - 1245335: "siam", - 1245336: "ISO ILL Protocol", - 1245337: "VPN Key Exchange", - 1245338: "Simple Transportation Management Framework (STMF)", - 1245339: "asa-appl-proto", - 1245340: "intrinsa", - 1245341: "Citadel", - 1245342: "mailbox-lm", - 1245343: "ohimsrv", - 1245344: "crs", - 1245345: "xvttp", - 1245346: "snare", - 1245347: "FirstClass Protocol", - 1245348: "passgo", - 1245349: "BSD rexecd(8)", - 1245350: "BSD rlogind(8)", - 1245351: "BSD rshd(8)", - 1245352: "spooler", - 1245353: "videotex", - 1245354: "like tenex link but across", - 1245355: "ntalk", - 1245356: "unixtime", - 1245357: "Routing Information Protocol (RIP)", - 1245358: "ripng", - 1245359: "ulp", - 1245360: "ibm-db2", - 1245361: "NetWare Core Protocol (NCP)", - 1245362: "Timeserver", - 1245363: "newdate", - 1245364: "Stock IXChange", - 1245365: "Customer IXChange", - 1245366: "irc-serv", - 1245370: "readnews", - 1245371: "netwall for emergency broadcasts", - 1245372: "MegaMedia Admin", - 1245373: "iiop", - 1245374: "opalis-rdv", - 1245375: "Networked Media Streaming Protocol", - 1245376: "gdomap", - 1245377: "Apertus Technologies Load Determination", - 1245378: "uucpd", - 1245379: "uucp-rlogin", - 1245380: "Commerce", - 1245381: "klogin", - 1245382: "krcmd", - 1245383: "Kerberos encrypted remote shell", - 1245384: "DHCPv6 Client", - 1245385: "DHCPv6 Server", - 1245386: "AFP over TCP", - 1245387: "idfp", - 1245388: "new-who", - 1245389: "cybercash", - 1245390: "deviceshare", - 1245391: "pirp", - 1245392: "Real Time Stream Control Protocol", - 1245393: "dsf", - 1245394: "Remote File System (RFS)", - 1245395: "openvms-sysipc", - 1245396: "sdnskmp", - 1245397: "teedtap", - 1245398: "rmonitord", - 1245399: "monitor", - 1245400: "chcmd", - 1245402: "snews", - 1245403: "plan 9 file service", - 1245404: "whoami", - 1245405: "streettalk", - 1245406: "banyan-rpc", - 1245407: "Microsoft shuttle", - 1245408: "Microsoft rome", - 1245409: "demon", - 1245410: "udemon", - 1245411: "sonar", - 1245412: "banyan-vip", - 1245413: "FTP Software Agent System", - 1245414: "vemmi", - 1245415: "ipcd", - 1245416: "vnas", - 1245417: "ipdd", - 1245418: "decbsrv", - 1245419: "sntp-heartbeat", - 1245420: "Bundle Discovery Protocol", - 1245421: "scc-security", - 1245422: "Philips Video-Conferencing", - 1245423: "keyserver", - 1245424: "IMAP4+SSL", - 1245425: "password-chg", - 1245426: "submission", - 1245427: "cal", - 1245428: "eyelink", - 1245429: "tns-cml", - 1245430: "FileMaker Pro", - 1245431: "eudora-set", - 1245432: "HTTP RPC Ep Map", - 1245433: "tpip", - 1245434: "cab-protocol", - 1245435: "smsd", - 1245436: "PTC Name Service", - 1245437: "SCO Web Server Manager 3", - 1245438: "Aeolon Core Protocol", - 1245439: "Sun IPC server", - 1310721: "nqs", - 1310722: "Sender-Initiated Unsolicited File Transfer", - 1310723: "npmp-trap", - 1310724: "npmp-local", - 1310725: "npmp-gui", - 1310726: "HMMP Indication", - 1310727: "HMMP Operation", - 1310728: "SSLshell", - 1310729: "Internet Configuration Manager", - 1310730: "SCO System Administration Server", - 1310731: "SCO Desktop Administration Server", - 1310732: "DEI-ICDA", - 1310733: "Digital EVM", - 1310734: "SCO WebServer Manager", - 1310735: "ESCP", - 1310736: "Collaborator", - 1310737: "Aux Bus Shunt", - 1310738: "Crypto Admin", - 1310739: "DEC DLM", - 1310740: "ASIA", - 1310741: "PassGo Tivoli", - 1310742: "QMQP (qmail)", - 1310743: "3Com AMP3", - 1310744: "RDA", - 1310745: "IPP (Internet Printing Protocol)", - 1310746: "bmpp", - 1310747: "Service Status update (Sterling Software)", - 1310748: "ginad", - 1310749: "RLZ DBase", - 1310750: "LDAP Protocol over TLS SSL (was SLDAP)", - 1310751: "lanserver", - 1310752: "mcns-sec", - 1310753: "Multicast Source Discovery Protocol (MSDP)", - 1310754: "entrust-sps", - 1310755: "repcmd", - 1310756: "ESRO-EMSDP V1.3", - 1310757: "SANity", - 1310758: "dwr", - 1310759: "PSSC", - 1310760: "Label Distribution Protocol (LDP)", - 1310761: "DHCP Failover", - 1310762: "Registry Registrar Protocol (RRP)", - 1310763: "Aminet", - 1310764: "OBEX", - 1310765: "IEEE MMS", - 1310766: "HELLO_PORT", - 1310767: "AODV", - 1310768: "TINC", - 1310769: "SPMP", - 1310770: "RMC", - 1310771: "TenFold", - 1310772: "URL Rendezvous", - 1310773: "MacOS Server Admin", - 1310774: "HAP", - 1310775: "PFTP", - 1310776: "PureNoise", - 1310777: "Secure Aux Bus", - 1310778: "Sun DR", - 1310779: "doom Id Software", - 1310780: "campaign contribution disclosures - SDR Technologies", - 1310781: "MeComm", - 1310782: "MeRegister", - 1310783: "VACDSM-SWS", - 1310784: "VACDSM-APP", - 1310785: "VPPS-QUA", - 1310786: "CIMPLEX", - 1310787: "ACAP", - 1310788: "DCTP", - 1310789: "VPPS Via", - 1310790: "Virtual Presence Protocol", - 1310791: "GNU Gereration Foundation NCP", - 1310792: "MRM", - 1310793: "entrust-aaas", - 1310794: "entrust-aams", - 1310795: "XFR", - 1310796: "CORBA IIOP", - 1310797: "CORBA IIOP SSL", - 1310798: "MDC Port Mapper", - 1310799: "Hardware Control Protocol Wismar", - 1310800: "asipregistry", - 1310801: "REALM-RUSD", - 1310802: "NMAP", - 1310803: "VATP", - 1310804: "MS Exchange Routing", - 1310805: "Hyperwave-ISP", - 1310806: "connendp", - 1310807: "Linux-HA (High-Availability Linux)", - 1310808: "IEEE-MMS-SSL", - 1310809: "RUSHD", - 1310810: "UUIDGEN", - 1310811: "OLSR", - 1310812: "Access Network", - 1310813: "errlog copy server daemon", - 1310814: "AgentX", - 1310815: "Secure Internet Live Conferencing (SILC)", - 1310816: "Borland DSJ", - 1310817: "Entrust Key Management Service Handler", - 1310818: "Entrust Administration Service Handler", - 1310819: "Cisco TDP", - 1310820: "IBM NetView DM 6000 Server Client", - 1310821: "IBM NetView DM 6000 send tcp", - 1310822: "IBM NetView DM 6000 receive tcp", - 1310823: "netGW", - 1310824: "Network based Rev. Cont. Sys.", - 1310825: "Flexible License Manager", - 1310826: "Fujitsu Device Control", - 1310827: "Russell Info Sci Calendar Manager", - 1310828: "Kerberos 5 admin changepw", - 1310830: "rfile", - 1310832: "pump", - 1310833: "qrh", - 1310834: "rrh", - 1310835: "kerberos v5 server propagation", - 1310836: "nlogin", - 1310837: "con", - 1310839: "ns", - 1310840: "kpwd Kerberos (v4) passwd", - 1310841: "quotad", - 1310842: "cycleserv", - 1310843: "omserv", - 1310844: "webster", - 1310845: "phone", - 1310846: "vid", - 1310847: "cadlock", - 1310848: "rtip", - 1310849: "cycleserv2", - 1310850: "submit", - 1310851: "rpasswd", - 1310852: "entomb", - 1310853: "wpages", - 1310854: "Hummingbird Exceed jconfig", - 1310855: "wpgs", - 1310856: "concert", - 1310857: "QSC", - 1310858: "controlit", - 1310859: "mdbs_daemon", - 1310860: "Device", - 1310861: "FCP", - 1310862: "itm-mcell-s", - 1310863: "PKIX-3 CA RA", - 1310864: "DHCP Failover 2", - 1310865: "SUP server", - 1310866: "rsync", - 1310867: "ICL coNETion locate server", - 1310868: "ICL coNETion server info", - 1310869: "AccessBuilder", - 1310870: "OMG Initial Refs", - 1310871: "Samba SWAT Tool", - 1310872: "IDEAFARM-CHAT", - 1310873: "IDEAFARM-CATCH", - 1310874: "xact-backup", - 1310875: "SecureNet Pro sensor", - 1310878: "Netnews Administration System", - 1310879: "Telnet Protocol over TLS SSL", - 1310880: "IMAP4 Protocol over TLS SSL", - 1310881: "ICP Protocol over TLS SSL", - 1310882: "POP3 Protocol over TLS SSL", - 1310883: "bhoetty", - 1310884: "Cray Unified Resource Manager", - 1310887: "Microsoft Authentication via SSL", - 1310888: "Google(SSL)", - 1310889: "Yahoo Authentication via SSL", - 1310890: "AOL Authentication via SSL", - 1310891: "FIX", - 1310892: "STUN", - 1310893: "Dynamic Host Configuration Protocol (DHCP)", - 1310894: "Megaco", - 1310895: "Rstatd", - 1310896: "RSVP", - 1310897: "SOAP", - 1310898: "Ess Apple Authentication via SSL", - 1310899: "TFTP", - 1310900: "Daytime", - 1310902: "MicrosoftOnline Authentication via SSL", - 1310903: "Microsoft WINS", - 1310904: "Remote Procedure Call (RPC)", - 1310905: "SSL/TLS", - 1310906: "Google APIs(SSL)", - 1310907: "Sina Authentication via SSL", - 1310908: "Google App Engine(SSL)", - 1310909: "Google User Content(SSL)", - 1310910: "Blackberry Authentication via SSL", - 1310912: "Adobe Authentication via SSL", - 1310914: "Lets Encrypt", - 1507329: "QQ Private Protocol", - 1507330: "Thunder Private Protocol", - 1507333: "Jabber Private Protocol", - 1572865: "Classmates", - 1572866: "Yik Yak", - 1572867: "Facebook", - 1572868: "Flickr", - 1572870: "Friendfeed", - 1572871: "Hi5", - 1572872: "LinkedIn", - 1572873: "Livejournal", - 1572874: "Twitter", - 1572875: "Plurk", - 1572876: "MySpace", - 1572880: "Khan Academy", - 1572881: "Pinterest", - 1572882: "Tumblr", - 1572883: "MeetMe", - 1572884: "VKontakte", - 1572885: "Odnoklassniki", - 1572886: "Niwota", - 1572887: "Tagged", - 1572889: "PerfSpot", - 1572890: "Me2day", - 1572891: "Mekusharim", - 1572892: "Draugiem", - 1572893: "Badoo", - 1572894: "Meetup", - 1572895: "Foursquare", - 1572896: "Ning", - 1572897: "i-Part/iPair", - 1572898: "Wretch", - 1572899: "Dudu", - 1572900: "Mig33", - 1572901: "Hatena", - 1572902: "eHarmony", - 1572903: "Fotolog ", - 1572905: "Tencent QQ", - 1572906: "Pixnet", - 1572907: "Nk.Pl", - 1572909: "Twoo", - 1572910: "Plaxo", - 1572911: "Cyworld", - 1572912: "Jivesoftware", - 1572913: "WordPress", - 1572914: "FMyLife", - 1572915: "Dcinside", - 1572916: "Class Chinaren", - 1572917: "Bai Sohu", - 1572918: "Yammer", - 1572919: "Douban", - 1572920: "Gamer", - 1572921: "Xuite", - 1572922: "ChatMe", - 1572923: "Clien.net", - 1572927: "AdultFriendFinder", - 1572928: "Fling.com", - 1572929: "Delicious", - 1572930: "Mei.fm", - 1572931: "Streetlife", - 1572967: "Daum-blog", - 1572968: "Naver-blog", - 1572970: "Panoramio", - 1572974: "Blogger", - 1572975: "FC2", - 1572976: "Yahoo Blog", - 1572977: "Friendster", - 1572978: "Ameba", - 1572980: "Bebo social network", - 1572981: "Kaixin", - 1572983: "Orkut", - 1572985: "Aol-Answers", - 1572987: "CoolTalk social network", - 1572988: "RenRen.com", - 1572989: "TweetDeck", - 1572990: "Hootsuite", - 1572998: "Xing", - 1572999: "Lokalisten", - 1573000: "meinVZ/studiVZ", - 1573004: "Viadeo", - 1573005: "Tuenti", - 1573006: "Hyves", - 1573007: "Mixi.jp", - 1573008: "Yahoo-mbga.jp", - 1573009: "GREE", - 1573010: "Netlog", - 1573011: "2ch", - 1573013: "Reddit", - 1573014: "LoveTheseCurves", - 1573015: "Weibo", - 1573016: "Google+", - 1573017: "Skyrock", - 1573018: "51.com", - 1573019: "Jackd", - 1573020: "Touch", - 1573021: "Skout", - 1573022: "Instagram", - 1573023: "Jiayuan", - 1573024: "Zoosk", - 1573025: "DatingDNA", - 1573026: "500px", - 1573028: "iAround", - 1573029: "pairs", - 1573030: "Path", - 1573031: "WeHeartIt", - 1573032: "Fancy", - 1573033: "Vine", - 1573034: "SnappyTV", - 1573035: "Miliao", - 1573036: "After School", - 1573074: "Weico", - 16777215: "Unknown_Other", -} diff --git a/core/unifi/v4/examples/convert.sh b/core/unifi/v4/examples/convert.sh deleted file mode 100755 index de5b2975..00000000 --- a/core/unifi/v4/examples/convert.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -# Usage: -# ./convert.sh [prefix] -# should contain a go struct, like uap_type.go -# It converts the go struct to an influx thing, like you see in uap_influx.go. -# [prefix] is optional. I used it to do all the stat_ uap metrics. -# Very crude, just helps skip a lot of copy/paste. -# -path=$1 -pre=$2 - -# Reads in the file one line at a time. -while IFS='' read -r line; do - # Split each piece of the file out. - name=$(echo "${line}" | awk '{print $1}') - type=$(echo "${line}" | awk '{print $2}') - json=$(echo "${line}" | awk '{print $3}') - json=$(echo "${json}" | cut -d\" -f2) - - # Don't print junk lines. (it still prints some junk lines) - if [ "$json" != "" ]; then - # Add a .Val suffix if this is a FlexInt or FlexBool. - [[ "$type" = Flex* ]] && suf=.Val - echo "\"${pre}${json}\": u.Stat.${name}${suf}," - fi -done < ${path} diff --git a/core/unifi/v4/examples/ids.json b/core/unifi/v4/examples/ids.json deleted file mode 100644 index 5dbb0fe2..00000000 --- a/core/unifi/v4/examples/ids.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "_id": "5d2416c78f0385ccf1c6df44", - "archived": false, - "timestamp": 1562646211, - "flow_id": 1591464006222389, - "in_iface": "eth1", - "event_type": "alert", - "src_ip": "196.196.244.84", - "src_mac": "f0:9f:c2:c4:bb:f1", - "src_port": 51413, - "dest_ip": "192.168.3.2", - "dst_mac": "40:a8:f0:68:c3:58", - "dest_port": 36881, - "proto": "UDP", - "app_proto": "failed", - "host": "f0:22:22:22:22:22", - "usgip": "11.22.33.44", - "unique_alertid": "1341902566-2019-07-08T21:23:31.229941-0700", - "srcipCountry": "SE", - "dstipCountry": false, - "usgipCountry": "US", - "srcipGeo": { - "continent_code": "EU", - "country_code": "SE", - "country_code3": "SWE", - "country_name": "Sweden", - "region": "26", - "city": "Stockholm", - "postal_code": "168 65", - "latitude": 59.349998474121094, - "longitude": 17.91670036315918, - "dma_code": 0, - "area_code": 0 - }, - "dstipGeo": false, - "usgipGeo": { - "continent_code": "NA", - "country_code": "US", - "country_code3": "USA", - "country_name": "United States", - "region": "CA", - "city": "Other", - "postal_code": "99999", - "latitude": 99.139400482177734, - "longitude": -99.39669799804688, - "dma_code": 862, - "area_code": 999 - }, - "srcipASN": "AS42607 Internet Carrier Limited", - "dstipASN": "", - "usgipASN": "AS7922 Comcast Cable Communications, LLC", - "catname": "spamhaus", - "inner_alert_action": "allowed", - "inner_alert_gid": 1, - "inner_alert_signature_id": 2400022, - "inner_alert_rev": 2673, - "inner_alert_signature": "ET DROP Spamhaus DROP Listed Traffic Inbound group 23", - "inner_alert_category": "Misc Attack", - "inner_alert_severity": 2, - "key": "EVT_IPS_IpsAlert", - "subsystem": "www", - "site_id": "574e86994566ffb914a2683c", - "time": 1562646211000, - "datetime": "2019-07-09T04:23:31Z", - "msg": "IPS Alert 2: Misc Attack. Signature ET DROP Spamhaus DROP Listed Traffic Inbound group 23. From: 196.196.244.84:51413, to: 192.168.3.2:36881, protocol: UDP" -}, diff --git a/core/unifi/v4/examples/uap.json b/core/unifi/v4/examples/uap.json deleted file mode 100644 index dbc6c4ae..00000000 --- a/core/unifi/v4/examples/uap.json +++ /dev/null @@ -1,738 +0,0 @@ -{ - "_id": "574e8bde4566ffb914a26853", - "adopted": true, - "antenna_table": [ - { - "default": true, - "id": 4, - "name": "Combined", - "wifi0_gain": 3, - "wifi1_gain": 3 - } - ], - "bandsteering_mode": "prefer_5g", - "board_rev": 18, - "cfgversion": "08cd8d6b71ebe82f", - "config_network": { - "type": "dhcp", - "ip": "10.1.10.67" - }, - "countrycode_table": [ - 840, - 124, - 630 - ], - "ethernet_table": [ - { - "mac": "80:22:a8:22:ae:22", - "num_port": 2, - "name": "eth0" - } - ], - "fw_caps": 4128063, - "has_eth1": false, - "has_speaker": false, - "inform_ip": "192.168.3.1", - "inform_url": "http://unifi:8080/inform", - "ip": "192.168.1.8", - "led_override": "default", - "mac": "80:22:22:22:22:22", - "mesh_sta_vap_enabled": true, - "model": "U7PG2", - "name": "wap-lower", - "outdoor_mode_override": "default", - "port_table": [ - { - "port_idx": 1, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26845", - "attr_no_edit": true, - "media": "GE", - "name": "Main", - "poe_caps": 0, - "port_poe": false, - "tx_bytes-r": 0, - "rx_bytes-r": 0, - "bytes-r": 0, - "port_delta": { - "time_delta": 21 - }, - "enable": true, - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 2, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26845", - "media": "GE", - "name": "Secondary", - "poe_caps": 0, - "port_poe": false, - "tx_bytes-r": 0, - "rx_bytes-r": 0, - "bytes-r": 0, - "port_delta": { - "time_delta": 21 - }, - "enable": true, - "masked": false, - "aggregated_by": false - } - ], - "radio_table": [ - { - "radio": "ng", - "name": "wifi0", - "channel": "auto", - "ht": "40", - "tx_power_mode": "auto", - "tx_power": "0", - "max_txpower": 22, - "min_txpower": 6, - "nss": 3, - "min_rssi_enabled": false, - "builtin_antenna": true, - "builtin_ant_gain": 3, - "current_antenna_gain": 0, - "radio_caps": 16420, - "wlangroup_id": "574e869d4566ffb914a26843" - }, - { - "radio": "na", - "name": "wifi1", - "channel": "auto", - "ht": "80", - "tx_power_mode": "high", - "tx_power": "0", - "max_txpower": 22, - "min_txpower": 6, - "nss": 3, - "min_rssi_enabled": false, - "is_11ac": true, - "has_dfs": true, - "has_fccdfs": true, - "builtin_antenna": true, - "builtin_ant_gain": 3, - "current_antenna_gain": 0, - "radio_caps": 50479140, - "wlangroup_id": "574e869d4566ffb914a26843" - } - ], - "scan_radio_table": [], - "serial": "xxxyyyzzz", - "site_id": "574e86994566ffb914a2683c", - "type": "uap", - "version": "4.0.42.10433", - "vwire_table": [], - "wifi_caps": 49141, - "wlangroup_id_na": "574e869d4566ffb914a26843", - "wlangroup_id_ng": "574e869d4566ffb914a26843", - "required_version": "3.4.1", - "hw_caps": 0, - "unsupported": false, - "unsupported_reason": 0, - "sys_error_caps": 0, - "has_fan": false, - "has_temperature": false, - "device_id": "574e8bde4566ffb914a26853", - "state": 1, - "last_seen": 1562225381, - "upgradable": false, - "adoptable_when_upgraded": false, - "rollupgrade": false, - "known_cfgversion": "08cd8d6b71ebe82f", - "uptime": 3105845, - "_uptime": 3105845, - "locating": false, - "connect_request_ip": "192.168.1.8", - "connect_request_port": "43913", - "sys_stats": { - "loadavg_1": "0.04", - "loadavg_15": "0.14", - "loadavg_5": "0.10", - "mem_buffer": 0, - "mem_total": 128622592, - "mem_used": 67178496 - }, - "system-stats": { - "cpu": "24.7", - "mem": "52.2", - "uptime": "3105845" - }, - "ssh_session_table": [], - "scanning": false, - "spectrum_scanning": false, - "guest_token": "4D630D2A1AF84771FCBB8EEB4C47E030", - "meshv3_peer_mac": "", - "satisfaction": 95, - "isolated": false, - "radio_table_stats": [ - { - "name": "wifi0", - "channel": 6, - "radio": "ng", - "ast_txto": null, - "ast_cst": null, - "ast_be_xmit": 398, - "cu_total": 20, - "cu_self_rx": 14, - "cu_self_tx": 4, - "gain": 3, - "state": "RUN", - "extchannel": 1, - "tx_power": 22, - "tx_packets": 183, - "tx_retries": 108, - "num_sta": 2, - "guest-num_sta": 0, - "user-num_sta": 2 - }, - { - "name": "wifi1", - "channel": 36, - "radio": "na", - "ast_txto": null, - "ast_cst": null, - "ast_be_xmit": 398, - "cu_total": 12, - "cu_self_rx": 10, - "cu_self_tx": 2, - "gain": 3, - "state": "RUN", - "extchannel": 1, - "tx_power": 22, - "tx_packets": 22466, - "tx_retries": 858, - "num_sta": 4, - "guest-num_sta": 0, - "user-num_sta": 4 - } - ], - "uplink": { - "full_duplex": true, - "ip": "0.0.0.0", - "mac": "80:22:22:22:22:22", - "max_vlan": 96, - "name": "eth0", - "netmask": "0.0.0.0", - "num_port": 2, - "rx_bytes": 3752803309, - "rx_dropped": 102338, - "rx_errors": 0, - "rx_multicast": 0, - "rx_packets": 245302304, - "speed": 1000, - "tx_bytes": 1604707458, - "tx_dropped": 341, - "tx_errors": 0, - "tx_packets": 194278357, - "up": true, - "max_speed": 1000, - "type": "wire", - "tx_bytes-r": 9693222, - "rx_bytes-r": 92418, - "uplink_mac": "f0:22:22:22:22:22", - "uplink_remote_port": 15 - }, - "vap_table": [ - { - "avg_client_signal": 0, - "bssid": "82:22:22:22:22:22", - "ccq": 0, - "channel": 36, - "essid": "Extra Free", - "extchannel": 1, - "id": "574e96834566ffb914a26875", - "mac_filter_rejections": 0, - "name": "ath3", - "num_satisfaction_sta": 0, - "num_sta": 0, - "radio": "na", - "radio_name": "wifi1", - "rx_bytes": 61253, - "rx_crypts": 0, - "rx_dropped": 0, - "rx_errors": 0, - "rx_frags": 0, - "rx_nwids": 47658, - "rx_packets": 576, - "rx_tcp_stats": { - "goodbytes": 0, - "lat_avg": 0, - "lat_max": 0, - "lat_min": 4294967295, - "stalls": 0 - }, - "satisfaction": -1, - "satisfaction_now": -1, - "state": "RUN", - "tx_bytes": 922841, - "tx_combined_retries": 0, - "tx_data_mpdu_bytes": 0, - "tx_dropped": 18128, - "tx_errors": 7, - "tx_packets": 736, - "tx_power": 22, - "tx_retries": 0, - "tx_rts_retries": 0, - "tx_success": 0, - "tx_tcp_stats": { - "goodbytes": 0, - "lat_avg": 0, - "lat_max": 0, - "lat_min": 4294967295, - "stalls": 0 - }, - "tx_total": 0, - "up": true, - "usage": "guest", - "wifi_tx_attempts": 0, - "wifi_tx_dropped": 0, - "wifi_tx_latency_mov": { - "avg": 0, - "max": 0, - "min": 4294967295, - "total": 0, - "total_count": 0 - }, - "t": "vap", - "wlanconf_id": "574e96834566ffb914a26875", - "is_guest": true, - "is_wep": false, - "ap_mac": "80:22:a8:22:22:22", - "map_id": null, - "site_id": "574e86994566ffb914a2683c" - }, - { - "avg_client_signal": -65, - "bssid": "80:22:a8:22:22:22", - "ccq": 333, - "channel": 36, - "essid": "Extra Fast", - "extchannel": 1, - "id": "574e96614566ffb914a26874", - "mac_filter_rejections": 0, - "name": "ath2", - "num_satisfaction_sta": 4, - "num_sta": 4, - "radio": "na", - "radio_name": "wifi1", - "rx_bytes": 3358763522, - "rx_crypts": 161639, - "rx_dropped": 161639, - "rx_errors": 161639, - "rx_frags": 0, - "rx_nwids": 37605, - "rx_packets": 99128603, - "rx_tcp_stats": { - "goodbytes": 16243150352, - "lat_avg": 7, - "lat_max": 100, - "lat_min": 10, - "stalls": 0 - }, - "satisfaction": 96, - "satisfaction_now": 97, - "state": "RUN", - "tx_bytes": 834859686, - "tx_combined_retries": 9067488, - "tx_data_mpdu_bytes": 48117828355, - "tx_dropped": 109, - "tx_errors": 4076905, - "tx_packets": 111980588, - "tx_power": 22, - "tx_retries": 9067488, - "tx_rts_retries": 0, - "tx_success": 62855481, - "tx_tcp_stats": { - "goodbytes": 2154118473, - "lat_avg": 18, - "lat_max": 120, - "lat_min": 10, - "stalls": 0 - }, - "tx_total": 62855552, - "up": true, - "usage": "user", - "wifi_tx_attempts": 71923040, - "wifi_tx_dropped": 71, - "wifi_tx_latency_mov": { - "avg": 565, - "max": 31757, - "min": 98, - "total": 10183098, - "total_count": 18019 - }, - "t": "vap", - "wlanconf_id": "574e96614566ffb914a26874", - "is_guest": false, - "is_wep": false, - "ap_mac": "80:22:22:22:22:22", - "map_id": null, - "site_id": "574e86994566ffb914a2683c" - }, - { - "avg_client_signal": 0, - "bssid": "82:22:a8:22:22:22", - "ccq": 0, - "channel": 6, - "essid": "Extra Free", - "extchannel": 1, - "id": "574e96834566ffb914a26875", - "mac_filter_rejections": 0, - "name": "ath1", - "num_satisfaction_sta": 0, - "num_sta": 0, - "radio": "ng", - "radio_name": "wifi0", - "reasons_bar_chart": { - "phy_rate": 0, - "signal": 0, - "sleepy_client": 0, - "sta_arp_timeout": 0, - "sta_dns_timeout": 0, - "sta_ip_timeout": 0, - "stream_eff": 0, - "tcp_latency": 0, - "tcp_packet_loss": 0, - "wifi_latency": 0, - "wifi_retries": 0 - }, - "reasons_bar_chart_now": { - "phy_rate": 0, - "signal": 0, - "sleepy_client": 0, - "sta_arp_timeout": 0, - "sta_dns_timeout": 0, - "sta_ip_timeout": 0, - "stream_eff": 0, - "tcp_latency": 0, - "tcp_packet_loss": 0, - "wifi_latency": 0, - "wifi_retries": 0 - }, - "rx_bytes": 0, - "rx_crypts": 0, - "rx_dropped": 0, - "rx_errors": 0, - "rx_frags": 0, - "rx_nwids": 120385, - "rx_packets": 0, - "rx_tcp_stats": { - "goodbytes": 0, - "lat_avg": 0, - "lat_max": 0, - "lat_min": 4294967295, - "stalls": 0 - }, - "satisfaction": -1, - "satisfaction_now": -1, - "state": "RUN", - "tx_bytes": 0, - "tx_combined_retries": 0, - "tx_data_mpdu_bytes": 0, - "tx_dropped": 20262, - "tx_errors": 0, - "tx_packets": 0, - "tx_power": 22, - "tx_retries": 0, - "tx_rts_retries": 0, - "tx_success": 0, - "tx_tcp_stats": { - "goodbytes": 0, - "lat_avg": 0, - "lat_max": 0, - "lat_min": 4294967295, - "stalls": 0 - }, - "tx_total": 0, - "up": true, - "usage": "guest", - "wifi_tx_attempts": 0, - "wifi_tx_dropped": 0, - "wifi_tx_latency_mov": { - "avg": 0, - "max": 0, - "min": 4294967295, - "total": 0, - "total_count": 0 - }, - "t": "vap", - "wlanconf_id": "574e96834566ffb914a26875", - "is_guest": true, - "is_wep": false, - "ap_mac": "80:22:a8:22:22:22", - "map_id": null, - "site_id": "574e86994566ffb914a2683c" - }, - { - "avg_client_signal": -68, - "bssid": "80:22:22:22:22:22", - "ccq": 966, - "channel": 6, - "essid": "Extra Fast", - "extchannel": 1, - "id": "574e96614566ffb914a26874", - "mac_filter_rejections": 0, - "name": "ath0", - "num_satisfaction_sta": 2, - "num_sta": 2, - "radio": "ng", - "radio_name": "wifi0", - "reasons_bar_chart": { - "phy_rate": 0, - "signal": 0, - "sleepy_client": 0, - "sta_arp_timeout": 0, - "sta_dns_timeout": 0, - "sta_ip_timeout": 0, - "stream_eff": 0, - "tcp_latency": 0, - "tcp_packet_loss": 0, - "wifi_latency": 0, - "wifi_retries": 1 - }, - "reasons_bar_chart_now": { - "phy_rate": 0, - "signal": 0, - "sleepy_client": 0, - "sta_arp_timeout": 0, - "sta_dns_timeout": 0, - "sta_ip_timeout": 0, - "stream_eff": 0, - "tcp_latency": 0, - "tcp_packet_loss": 0, - "wifi_latency": 0, - "wifi_retries": 1 - }, - "rx_bytes": 1017366419, - "rx_crypts": 11013, - "rx_dropped": 12764, - "rx_errors": 12764, - "rx_frags": 0, - "rx_nwids": 177145, - "rx_packets": 22542668, - "rx_tcp_stats": { - "goodbytes": 114220296, - "lat_avg": 5, - "lat_max": 10, - "lat_min": 10, - "stalls": 0 - }, - "satisfaction": 93, - "satisfaction_now": 94, - "state": "RUN", - "tx_bytes": 965488630, - "tx_combined_retries": 8202639, - "tx_data_mpdu_bytes": 1145631754, - "tx_dropped": 43, - "tx_errors": 0, - "tx_packets": 22623798, - "tx_power": 22, - "tx_retries": 7194267, - "tx_rts_retries": 1008372, - "tx_success": 9545999, - "tx_tcp_stats": { - "goodbytes": 182912739, - "lat_avg": 5, - "lat_max": 10, - "lat_min": 10, - "stalls": 0 - }, - "tx_total": 9547096, - "up": true, - "usage": "user", - "wifi_tx_attempts": 16740276, - "wifi_tx_dropped": 1095, - "wifi_tx_latency_mov": { - "avg": 673, - "max": 13612, - "min": 0, - "total": 263176, - "total_count": 391 - }, - "t": "vap", - "wlanconf_id": "574e96614566ffb914a26874", - "is_guest": false, - "is_wep": false, - "ap_mac": "80:22:22:22:22:22", - "map_id": null, - "site_id": "574e86994566ffb914a2683c" - } - ], - "downlink_table": [], - "vwire_vap_table": [], - "bytes-d": 204913232, - "tx_bytes-d": 1921569, - "rx_bytes-d": 202991663, - "bytes-r": 9757772, - "last_uplink": { - "uplink_mac": "f0:22:22:22:22:22", - "uplink_remote_port": 15 - }, - "stat": { - "site_id": "574e86994566ffb914a2683c", - "o": "ap", - "oid": "80:22:a8:22:22:22", - "ap": "80:22:a8:22:22:22", - "time": 1562207100000, - "datetime": "2019-07-04T02:25:00Z", - "guest-wifi0-rx_packets": 0, - "guest-wifi1-rx_packets": 0, - "user-wifi1-rx_packets": 31373230, - "user-wifi0-rx_packets": 169790, - "user-rx_packets": 31543020, - "guest-rx_packets": 0, - "wifi0-rx_packets": 169790, - "wifi1-rx_packets": 31373230, - "rx_packets": 31543020, - "guest-wifi0-rx_bytes": 0, - "guest-wifi1-rx_bytes": 0, - "user-wifi1-rx_bytes": 42049645434, - "user-wifi0-rx_bytes": 16755639, - "user-rx_bytes": 42066401073, - "guest-rx_bytes": 0, - "wifi0-rx_bytes": 16755639, - "wifi1-rx_bytes": 42049645434, - "rx_bytes": 42066401073, - "guest-wifi0-rx_errors": 0, - "guest-wifi1-rx_errors": 0, - "user-wifi1-rx_errors": 150651, - "user-wifi0-rx_errors": 0, - "user-rx_errors": 150651, - "guest-rx_errors": 0, - "wifi0-rx_errors": 0, - "wifi1-rx_errors": 150651, - "rx_errors": 150651, - "guest-wifi0-rx_dropped": 0, - "guest-wifi1-rx_dropped": 0, - "user-wifi1-rx_dropped": 150651, - "user-wifi0-rx_dropped": 0, - "user-rx_dropped": 150651, - "guest-rx_dropped": 0, - "wifi0-rx_dropped": 0, - "wifi1-rx_dropped": 150651, - "rx_dropped": 150651, - "guest-wifi0-rx_crypts": 0, - "guest-wifi1-rx_crypts": 0, - "user-wifi1-rx_crypts": 150651, - "user-wifi0-rx_crypts": 0, - "user-rx_crypts": 150651, - "guest-rx_crypts": 0, - "wifi0-rx_crypts": 0, - "wifi1-rx_crypts": 150651, - "rx_crypts": 150651, - "guest-wifi0-rx_frags": 0, - "guest-wifi1-rx_frags": 0, - "user-wifi1-rx_frags": 0, - "user-wifi0-rx_frags": 0, - "user-rx_frags": 0, - "guest-rx_frags": 0, - "wifi0-rx_frags": 0, - "wifi1-rx_frags": 0, - "rx_frags": 0, - "guest-wifi0-tx_packets": 0, - "guest-wifi1-tx_packets": 0, - "user-wifi1-tx_packets": 7125589, - "user-wifi0-tx_packets": 210389, - "user-tx_packets": 7335978, - "guest-tx_packets": 0, - "wifi0-tx_packets": 210389, - "wifi1-tx_packets": 7125589, - "tx_packets": 7335978, - "guest-wifi0-tx_bytes": 0, - "guest-wifi1-tx_bytes": 0, - "user-wifi1-tx_bytes": 3011293823, - "user-wifi0-tx_bytes": 25966558, - "user-tx_bytes": 3037260381, - "guest-tx_bytes": 0, - "wifi0-tx_bytes": 25966558, - "wifi1-tx_bytes": 3011293823, - "tx_bytes": 3037260381, - "guest-wifi0-tx_errors": 0, - "guest-wifi1-tx_errors": 0, - "user-wifi1-tx_errors": 102193, - "user-wifi0-tx_errors": 0, - "user-tx_errors": 102193, - "guest-tx_errors": 0, - "wifi0-tx_errors": 0, - "wifi1-tx_errors": 102193, - "tx_errors": 102193, - "guest-wifi0-tx_dropped": 296, - "guest-wifi1-tx_dropped": 296, - "user-wifi1-tx_dropped": 0, - "user-wifi0-tx_dropped": 0, - "user-tx_dropped": 0, - "guest-tx_dropped": 592, - "wifi0-tx_dropped": 296, - "wifi1-tx_dropped": 296, - "tx_dropped": 592, - "guest-wifi0-tx_retries": 0, - "guest-wifi1-tx_retries": 0, - "user-wifi1-tx_retries": 519734, - "user-wifi0-tx_retries": 90225, - "user-tx_retries": 609959, - "guest-tx_retries": 0, - "wifi0-tx_retries": 90225, - "wifi1-tx_retries": 519734, - "tx_retries": 609959, - "guest-wifi0-mac_filter_rejections": 0, - "guest-wifi1-mac_filter_rejections": 0, - "user-wifi1-mac_filter_rejections": 0, - "user-wifi0-mac_filter_rejections": 0, - "user-mac_filter_rejections": 0, - "guest-mac_filter_rejections": 0, - "wifi0-mac_filter_rejections": 0, - "wifi1-mac_filter_rejections": 0, - "mac_filter_rejections": 0, - "guest-wifi0-wifi_tx_attempts": 0, - "guest-wifi1-wifi_tx_attempts": 0, - "user-wifi1-wifi_tx_attempts": 4419026, - "user-wifi0-wifi_tx_attempts": 255999, - "user-wifi_tx_attempts": 4675025, - "guest-wifi_tx_attempts": 0, - "wifi0-wifi_tx_attempts": 255999, - "wifi1-wifi_tx_attempts": 4419026, - "wifi_tx_attempts": 4675025, - "guest-wifi0-wifi_tx_dropped": 0, - "guest-wifi1-wifi_tx_dropped": 0, - "user-wifi1-wifi_tx_dropped": 25, - "user-wifi0-wifi_tx_dropped": 2, - "user-wifi_tx_dropped": 27, - "guest-wifi_tx_dropped": 0, - "wifi0-wifi_tx_dropped": 2, - "wifi1-wifi_tx_dropped": 25, - "wifi_tx_dropped": 27, - "bytes": 45103661454, - "duration": 17988000, - "user-wifi1-ath2-574e96614566ffb914a26874-rx_packets": 31373230, - "user-wifi1-ath2-574e96614566ffb914a26874-rx_bytes": 42049645434, - "user-wifi1-ath2-574e96614566ffb914a26874-tx_packets": 7125589, - "user-wifi1-ath2-574e96614566ffb914a26874-tx_bytes": 3011293823, - "user-wifi1-ath2-574e96614566ffb914a26874-tx_errors": 102193, - "user-wifi1-ath2-574e96614566ffb914a26874-tx_retries": 519734, - "user-wifi1-ath2-574e96614566ffb914a26874-wifi_tx_attempts": 4419026, - "user-wifi0-ath0-574e96614566ffb914a26874-rx_packets": 169790, - "user-wifi0-ath0-574e96614566ffb914a26874-rx_bytes": 16755639, - "user-wifi0-ath0-574e96614566ffb914a26874-tx_packets": 210389, - "user-wifi0-ath0-574e96614566ffb914a26874-tx_bytes": 25966558, - "user-wifi0-ath0-574e96614566ffb914a26874-tx_retries": 90225, - "user-wifi0-ath0-574e96614566ffb914a26874-wifi_tx_attempts": 255999, - "guest-wifi1-ath3-574e96834566ffb914a26875-tx_dropped": 296, - "guest-wifi0-ath1-574e96834566ffb914a26875-tx_dropped": 296, - "user-wifi1-ath2-574e96614566ffb914a26874-rx_errors": 150651, - "user-wifi1-ath2-574e96614566ffb914a26874-rx_dropped": 150651, - "user-wifi1-ath2-574e96614566ffb914a26874-rx_crypts": 150651, - "user-wifi0-ath0-574e96614566ffb914a26874-wifi_tx_dropped": 2, - "user-wifi1-ath2-574e96614566ffb914a26874-wifi_tx_dropped": 25 - }, - "tx_bytes": 3037260381, - "rx_bytes": 42066401073, - "bytes": 45103661454, - "vwireEnabled": false, - "uplink_table": [], - "num_sta": 6, - "user-num_sta": 6, - "guest-num_sta": 0 -} diff --git a/core/unifi/v4/examples/ugw.json b/core/unifi/v4/examples/ugw.json deleted file mode 100644 index 117b14f7..00000000 --- a/core/unifi/v4/examples/ugw.json +++ /dev/null @@ -1,371 +0,0 @@ -{ - "_id": "59a35da745663e6cc82600f6", - "adopted": true, - "cfgversion": "bf9f0335063fe6ea", - "config_network": { - "type": "dhcp", - "ip": "192.168.2.0" - }, - "ethernet_table": [ - { - "mac": "22:22:00:22:22:00", - "num_port": 1, - "name": "eth0" - }, - { - "mac": "22:22:00:22:22:00", - "num_port": 1, - "name": "eth1" - }, - { - "mac": "22:22:00:22:22:00", - "num_port": 1, - "name": "eth2" - } - ], - "fw_caps": 184323, - "inform_ip": "192.168.3.1", - "inform_url": "http://security:8080/inform", - "ip": "3.1.33.7", - "led_override": "default", - "license_state": "registered", - "mac": "22:22:00:22:22:00", - "model": "UGW3", - "name": "gateway", - "outdoor_mode_override": "default", - "serial": "xxxyyyzzz", - "site_id": "574e86994566ffb914a2683c", - "type": "ugw", - "usg_caps": 786431, - "version": "4.4.41.5193700", - "required_version": "4.0.0", - "ethernet_overrides": [ - { - "ifname": "eth1", - "networkgroup": "LAN" - }, - { - "ifname": "eth0", - "networkgroup": "WAN" - } - ], - "hw_caps": 0, - "board_rev": 16, - "unsupported": false, - "unsupported_reason": 0, - "device_id": "59a35da745663e6cc82600f6", - "state": 1, - "last_seen": 1562311857, - "upgradable": false, - "adoptable_when_upgraded": false, - "rollupgrade": false, - "known_cfgversion": "bf9f0335063fe6ea", - "uptime": 3191626, - "_uptime": 3191626, - "locating": false, - "connect_request_ip": "192.168.2.1", - "connect_request_port": "35615", - "sys_stats": { - "loadavg_1": "0.01", - "loadavg_15": "0.12", - "loadavg_5": "0.06", - "mem_buffer": 62406656, - "mem_total": 507412480, - "mem_used": 397500416 - }, - "system-stats": { - "cpu": "14", - "mem": "30", - "uptime": "3191066" - }, - "guest_token": "83342830AE9C0641DC39DD2759C122A1", - "speedtest-status": { - "latency": 14, - "rundate": 1562310531, - "runtime": 172, - "status_download": 2, - "status_ping": 2, - "status_summary": 2, - "status_upload": 2, - "xput_download": 157.36776733398438, - "xput_upload": 37.90521240234375 - }, - "speedtest-status-saved": true, - "wan1": { - "tx_bytes-r": 2852355, - "rx_bytes-r": 1224743, - "bytes-r": 4077098, - "max_speed": 1000, - "type": "wire", - "name": "wan", - "ifname": "eth0", - "ip": "3.1.33.7", - "netmask": "255.255.254.0", - "mac": "22:22:00:22:22:00", - "up": true, - "speed": 1000, - "full_duplex": true, - "rx_bytes": 2648236513108, - "rx_dropped": 34030, - "rx_errors": 0, - "rx_packets": 3068347172, - "tx_bytes": 3009601283006, - "tx_dropped": 0, - "tx_errors": 0, - "tx_packets": 2859713220, - "rx_multicast": 939111, - "enable": true, - "dns": [ - "1.1.1.1", - "8.8.8.8" - ], - "gateway": "3.1.33.8" - }, - "port_table": [ - { - "name": "wan", - "ifname": "eth0", - "ip": "3.1.33.7", - "netmask": "255.255.254.0", - "mac": "22:22:00:22:22:00", - "up": true, - "speed": 1000, - "full_duplex": true, - "rx_bytes": 2648236513108, - "rx_dropped": 34030, - "rx_errors": 0, - "rx_packets": 3068347172, - "tx_bytes": 3009601283006, - "tx_dropped": 0, - "tx_errors": 0, - "tx_packets": 2859713220, - "rx_multicast": 939111, - "enable": true, - "dns": [ - "216.146.35.35", - "216.146.36.36" - ], - "gateway": "3.1.33.8" - }, - { - "name": "lan", - "ifname": "eth1", - "ip": "192.168.2.1", - "netmask": "255.255.252.0", - "mac": "22:22:00:22:22:00", - "up": true, - "speed": 1000, - "full_duplex": true, - "rx_bytes": 2911311797255, - "rx_dropped": 3438, - "rx_errors": 0, - "rx_packets": 2659342049, - "tx_bytes": 2140222188895, - "tx_dropped": 0, - "tx_errors": 0, - "tx_packets": 2734245088, - "rx_multicast": 11929365, - "enable": true - }, - { - "name": "lan2", - "ifname": "eth2", - "ip": "0.0.0.0", - "netmask": "0.0.0.0", - "mac": "22:22:00:22:22:00", - "up": false, - "speed": 0, - "full_duplex": false, - "rx_bytes": 0, - "rx_dropped": 0, - "rx_errors": 0, - "rx_packets": 0, - "tx_bytes": 0, - "tx_dropped": 0, - "tx_errors": 0, - "tx_packets": 0, - "rx_multicast": 0, - "enable": false - } - ], - "network_table": [ - { - "_id": "574e8de34566ffb914a26862", - "is_nat": true, - "dhcpd_dns_enabled": false, - "purpose": "guest", - "dhcpd_leasetime": "86400", - "igmp_snooping": true, - "dhcpguard_enabled": false, - "dhcpd_start": "192.168.5.1", - "enabled": true, - "dhcpd_stop": "192.168.5.254", - "dhcpd_wins_enabled": false, - "domain_name": "guest.lan", - "dhcpd_enabled": true, - "ip_subnet": "192.168.5.0/23", - "vlan": "5", - "networkgroup": "LAN", - "name": "Public Wireless", - "site_id": "574e86994566ffb914a2683c", - "dhcpd_ip_1": "", - "vlan_enabled": true, - "dhcpd_gateway_enabled": false, - "dhcpd_time_offset_enabled": false, - "ipv6_interface_type": "none", - "dhcp_relay_enabled": false, - "mac": "22:22:00:22:22:00", - "is_guest": true, - "ip": "192.168.5.0", - "up": "true", - "num_sta": 1, - "rx_bytes": 578602537, - "rx_packets": 471151, - "tx_bytes": 182318948, - "tx_packets": 239651 - }, - { - "_id": "59a362f645663e6cc8260133", - "is_nat": true, - "dhcpd_dns_enabled": false, - "purpose": "corporate", - "dhcpd_leasetime": 86400, - "dhcpd_start": "192.168.68.2", - "dhcpd_stop": "192.168.68.250", - "enabled": true, - "domain_name": "secure.lan", - "dhcpd_enabled": true, - "vlan": "69", - "ip_subnet": "192.168.69.1/23", - "networkgroup": "LAN", - "name": "Security Network", - "site_id": "574e86994566ffb914a2683c", - "vlan_enabled": true, - "dhcpd_ntp_1": "192.168.69.1", - "dhcpd_gateway_enabled": false, - "dhcpd_time_offset_enabled": false, - "dhcp_relay_enabled": false, - "dhcpd_ntp_enabled": true, - "ipv6_interface_type": "none", - "dhcpd_unifi_controller": "192.168.3.1", - "igmp_snooping": true, - "mac": "22:22:00:22:22:00", - "is_guest": false, - "ip": "192.168.69.1", - "up": "true", - "num_sta": 11, - "rx_bytes": 5221725, - "rx_packets": 70663, - "tx_bytes": 0, - "tx_packets": 0 - }, - { - "_id": "574e869d4566ffb914a26841", - "purpose": "corporate", - "dhcpd_leasetime": "86400", - "igmp_snooping": false, - "dhcpd_ntp_1": "192.168.2.1", - "dhcpguard_enabled": false, - "dhcpd_gateway_enabled": false, - "dhcpd_time_offset_enabled": false, - "dhcpd_start": "192.168.1.1", - "dhcpd_unifi_controller": "192.168.3.1", - "dhcpd_stop": "192.168.1.254", - "enabled": true, - "domain_name": "home.lan", - "dhcpd_enabled": true, - "ip_subnet": "192.168.2.1/22", - "networkgroup": "LAN", - "dhcpd_ip_1": "", - "vlan_enabled": false, - "is_nat": true, - "dhcpd_dns_enabled": false, - "dhcp_relay_enabled": false, - "dhcpd_wins_enabled": false, - "upnp_lan_enabled": true, - "dhcpd_ntp_enabled": true, - "name": "Home Network", - "site_id": "574e86994566ffb914a2683c", - "attr_no_delete": true, - "attr_hidden_id": "LAN", - "ipv6_interface_type": "none", - "mac": "22:22:00:22:22:00", - "is_guest": false, - "ip": "192.168.2.1", - "up": "true", - "num_sta": 30, - "rx_bytes": 2099754971983, - "rx_packets": 2689749160, - "tx_bytes": 2877873632166, - "tx_packets": 2579198457 - } - ], - "uplink": { - "drops": 40, - "enable": true, - "full_duplex": true, - "gateways": [ - "3.1.33.8" - ], - "ip": "3.1.33.7", - "latency": 103, - "mac": "22:22:00:22:22:00", - "name": "eth0", - "nameservers": [ - "1.1.1.1", - "8.8.8.8" - ], - "netmask": "255.255.254.0", - "num_port": 1, - "rx_bytes": 2648236513108, - "rx_dropped": 34030, - "rx_errors": 0, - "rx_multicast": 939111, - "rx_packets": 3068347172, - "speed": 1000, - "speedtest_lastrun": 1562310531, - "speedtest_ping": 14, - "speedtest_status": "Success", - "tx_bytes": 3009601283006, - "tx_dropped": 0, - "tx_errors": 0, - "tx_packets": 2859713220, - "up": true, - "uptime": 559088, - "xput_down": 157.368, - "xput_up": 37.905, - "tx_bytes-r": 2852355, - "rx_bytes-r": 1224743, - "bytes-r": 4077098, - "max_speed": 1000, - "type": "wire" - }, - "stat": { - "site_id": "574e86994566ffb914a2683c", - "o": "gw", - "oid": "22:22:00:22:22:00", - "gw": "22:22:00:22:22:00", - "time": 1562207100000, - "datetime": "2019-07-04T02:25:00Z", - "duration": 104466000, - "wan-rx_packets": 151387924, - "wan-rx_bytes": 111251311739, - "wan-tx_packets": 182985900, - "wan-tx_bytes": 230372237709, - "lan-rx_packets": 173953163, - "lan-rx_bytes": 226862410885, - "lan-tx_packets": 137029474, - "lan-tx_bytes": 89478206254, - "wan-rx_dropped": 561, - "lan-rx_dropped": 29 - }, - "tx_bytes": 2648236513108, - "rx_bytes": 3009601283006, - "bytes": 5657837796114, - "num_sta": 41, - "user-num_sta": 41, - "guest-num_sta": 0, - "num_desktop": 7, - "num_mobile": 2, - "num_handheld": 8 -} diff --git a/core/unifi/v4/examples/usw.json b/core/unifi/v4/examples/usw.json deleted file mode 100644 index d70d6ab3..00000000 --- a/core/unifi/v4/examples/usw.json +++ /dev/null @@ -1,1720 +0,0 @@ -{ - "_id": "59a35cee45663e6cc82600f0", - "adopted": true, - "board_rev": 7, - "cfgversion": "669564dd04994088", - "config_network": { - "type": "dhcp", - "ip": "192.168.1.6" - }, - "dot1x_portctrl_enabled": false, - "ethernet_table": [ - { - "mac": "22:22:00:22:22:00", - "num_port": 26, - "name": "eth0" - }, - { - "mac": "22:22:00:22:22:00", - "name": "srv0" - } - ], - "flowctrl_enabled": false, - "fw_caps": 712229, - "has_fan": true, - "has_temperature": true, - "inform_ip": "192.168.3.1", - "inform_url": "http://security:8080/inform", - "ip": "192.168.1.7", - "jumboframe_enabled": false, - "led_override": "default", - "license_state": "registered", - "mac": "22:22:00:22:22:00", - "model": "US24P250", - "name": "switch", - "outdoor_mode_override": "default", - "port_overrides": [ - { - "name": "APC UPS", - "poe_mode": "off", - "port_idx": 1, - "portconf_id": "59a362f645663e6cc8260134" - }, - { - "poe_mode": "auto", - "port_idx": 2, - "portconf_id": "574e869d4566ffb914a26847" - }, - { - "name": "Camera: Gate", - "poe_mode": "auto", - "port_idx": 3, - "portconf_id": "59a362f645663e6cc8260134" - }, - { - "name": "Bubba's Desktop", - "poe_mode": "auto", - "port_idx": 4, - "portconf_id": "574e869d4566ffb914a26845" - }, - { - "name": "Lexi's Desktop", - "poe_mode": "off", - "port_idx": 5, - "portconf_id": "574e869d4566ffb914a26845" - }, - { - "name": "Camera: Car", - "poe_mode": "auto", - "port_idx": 6, - "portconf_id": "59a362f645663e6cc8260134" - }, - { - "name": "Camera: Garage", - "poe_mode": "auto", - "port_idx": 7, - "portconf_id": "59a362f645663e6cc8260134" - }, - { - "name": "Office Tertiary Desk PD14", - "poe_mode": "off", - "port_idx": 8, - "portconf_id": "574e869d4566ffb914a26847" - }, - { - "name": "Camera: Pool", - "poe_mode": "auto", - "port_idx": 9, - "portconf_id": "59a362f645663e6cc8260134" - }, - { - "name": "Security: Home Port", - "poe_mode": "off", - "port_idx": 10, - "portconf_id": "574e869d4566ffb914a26847" - }, - { - "name": "8ch Relay Board", - "poe_mode": "auto", - "port_idx": 11, - "portconf_id": "59a362f645663e6cc8260134" - }, - { - "name": "Security: Secure Port", - "poe_mode": "off", - "port_idx": 12, - "portconf_id": "59a362f645663e6cc8260134" - }, - { - "name": "Upstairs WAP", - "poe_mode": "auto", - "port_idx": 13, - "portconf_id": "574e869d4566ffb914a26845" - }, - { - "name": "Downstairs WAP", - "poe_mode": "auto", - "port_idx": 15, - "portconf_id": "574e869d4566ffb914a26845" - }, - { - "name": "David's Desk", - "poe_mode": "off", - "port_idx": 16, - "portconf_id": "574e869d4566ffb914a26845" - }, - { - "name": "Camera: Door", - "poe_mode": "auto", - "port_idx": 17, - "portconf_id": "59a362f645663e6cc8260134" - }, - { - "name": "Camera: Porch", - "poe_mode": "auto", - "port_idx": 19, - "portconf_id": "59a362f645663e6cc8260134" - }, - { - "name": "Camera: Road", - "port_idx": 21, - "portconf_id": "59a362f645663e6cc8260134" - }, - { - "name": "Livingroom Stereo", - "poe_mode": "off", - "port_idx": 22, - "portconf_id": "574e869d4566ffb914a26845" - }, - { - "name": "Homerun Prime", - "poe_mode": "off", - "port_idx": 23, - "portconf_id": "574e869d4566ffb914a26845" - }, - { - "name": "gateway", - "poe_mode": "off", - "port_idx": 24, - "portconf_id": "574e869d4566ffb914a26845" - } - ], - "port_table": [ - { - "port_idx": 1, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "59a362f645663e6cc8260134", - "poe_mode": "off", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Unknown", - "poe_current": "0.00", - "poe_enable": false, - "poe_good": false, - "poe_power": "0.00", - "poe_voltage": "0.00", - "rx_broadcast": 1202, - "rx_bytes": 227167212, - "rx_dropped": 0, - "rx_errors": 12, - "rx_multicast": 28260, - "rx_packets": 1153365, - "satisfaction": 85, - "speed": 100, - "stp_pathcost": 200000, - "stp_state": "forwarding", - "tx_broadcast": 417327, - "tx_bytes": 507571083, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 2284158, - "tx_packets": 4465717, - "up": true, - "tx_bytes-r": 45, - "rx_bytes-r": 5, - "bytes-r": 50, - "name": "APC UPS", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 2, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26847", - "poe_mode": "auto", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": false, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Unknown", - "poe_current": "0.00", - "poe_enable": false, - "poe_good": false, - "poe_power": "0.00", - "poe_voltage": "0.00", - "rx_broadcast": 1175, - "rx_bytes": 1068032535, - "rx_dropped": 150, - "rx_errors": 0, - "rx_multicast": 3489, - "rx_packets": 11624994, - "satisfaction": 90, - "speed": 0, - "stp_pathcost": 0, - "stp_state": "disabled", - "tx_broadcast": 62176, - "tx_bytes": 41832520833, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 302928, - "tx_packets": 28160117, - "up": false, - "tx_bytes-r": 0, - "rx_bytes-r": 0, - "bytes-r": 0, - "name": "Port 2", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 3, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "59a362f645663e6cc8260134", - "poe_mode": "auto", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Class 0", - "poe_current": "91.55", - "poe_enable": true, - "poe_good": true, - "poe_power": "4.84", - "poe_voltage": "52.88", - "rx_broadcast": 65216, - "rx_bytes": 3456851429405, - "rx_dropped": 157638, - "rx_errors": 0, - "rx_multicast": 164814, - "rx_packets": 2410688372, - "satisfaction": 90, - "speed": 100, - "stp_pathcost": 200000, - "stp_state": "forwarding", - "tx_broadcast": 353417, - "tx_bytes": 40005007443, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 2419630, - "tx_packets": 564763412, - "up": true, - "tx_bytes-r": 12085, - "rx_bytes-r": 888603, - "bytes-r": 900689, - "name": "Camera: Gate", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 4, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26845", - "poe_mode": "auto", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": false, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Unknown", - "poe_current": "0.00", - "poe_enable": false, - "poe_good": false, - "poe_power": "0.00", - "poe_voltage": "0.00", - "rx_broadcast": 646153, - "rx_bytes": 4581272050, - "rx_dropped": 15683, - "rx_errors": 0, - "rx_multicast": 36698, - "rx_packets": 53602118, - "satisfaction": 90, - "speed": 0, - "stp_pathcost": 0, - "stp_state": "disabled", - "tx_broadcast": 452081, - "tx_bytes": 166341729228, - "tx_dropped": 10704730, - "tx_errors": 0, - "tx_multicast": 3414231, - "tx_packets": 122098881, - "up": false, - "tx_bytes-r": 0, - "rx_bytes-r": 0, - "bytes-r": 0, - "name": "Bubba's Desktop", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 5, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26845", - "poe_mode": "off", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": false, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Unknown", - "poe_current": "0.00", - "poe_enable": false, - "poe_good": false, - "poe_power": "0.00", - "poe_voltage": "0.00", - "rx_broadcast": 1186, - "rx_bytes": 913565372, - "rx_dropped": 2079, - "rx_errors": 0, - "rx_multicast": 9915, - "rx_packets": 8040327, - "satisfaction": 90, - "speed": 0, - "stp_pathcost": 0, - "stp_state": "disabled", - "tx_broadcast": 99303, - "tx_bytes": 13691997722, - "tx_dropped": 126800, - "tx_errors": 0, - "tx_multicast": 619240, - "tx_packets": 11897488, - "up": false, - "tx_bytes-r": 0, - "rx_bytes-r": 0, - "bytes-r": 0, - "name": "Lexi's Desktop", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 6, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "59a362f645663e6cc8260134", - "poe_mode": "auto", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Class 2", - "poe_current": "75.07", - "poe_enable": true, - "poe_good": true, - "poe_power": "3.95", - "poe_voltage": "52.63", - "rx_broadcast": 15135, - "rx_bytes": 1683544880532, - "rx_dropped": 105097, - "rx_errors": 0, - "rx_multicast": 140206, - "rx_packets": 1145100603, - "satisfaction": 90, - "speed": 100, - "stp_pathcost": 200000, - "stp_state": "forwarding", - "tx_broadcast": 403490, - "tx_bytes": 25109031755, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 2363833, - "tx_packets": 356126846, - "up": true, - "tx_bytes-r": 7672, - "rx_bytes-r": 504473, - "bytes-r": 512145, - "name": "Camera: Car", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 7, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "59a362f645663e6cc8260134", - "poe_mode": "auto", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Class 0", - "poe_current": "92.28", - "poe_enable": true, - "poe_good": true, - "poe_power": "4.85", - "poe_voltage": "52.56", - "rx_broadcast": 65316, - "rx_bytes": 2610602428826, - "rx_dropped": 157634, - "rx_errors": 0, - "rx_multicast": 164757, - "rx_packets": 1825440143, - "satisfaction": 90, - "speed": 100, - "stp_pathcost": 200000, - "stp_state": "forwarding", - "tx_broadcast": 353314, - "tx_bytes": 30130225938, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 2419669, - "tx_packets": 424070512, - "up": true, - "tx_bytes-r": 9976, - "rx_bytes-r": 786139, - "bytes-r": 796116, - "name": "Camera: Garage", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 8, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26847", - "poe_mode": "off", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": false, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Unknown", - "poe_current": "0.00", - "poe_enable": false, - "poe_good": false, - "poe_power": "0.00", - "poe_voltage": "0.00", - "rx_broadcast": 1970, - "rx_bytes": 57788865632, - "rx_dropped": 49, - "rx_errors": 1, - "rx_multicast": 5397, - "rx_packets": 81214364, - "satisfaction": 75, - "speed": 0, - "stp_pathcost": 0, - "stp_state": "disabled", - "tx_broadcast": 243126, - "tx_bytes": 106910126818, - "tx_dropped": 343060, - "tx_errors": 0, - "tx_multicast": 1620633, - "tx_packets": 96321547, - "up": false, - "tx_bytes-r": 0, - "rx_bytes-r": 0, - "bytes-r": 0, - "name": "Office Tertiary Desk PD14", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 9, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "59a362f645663e6cc8260134", - "poe_mode": "auto", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Class 4", - "poe_current": "185.42", - "poe_enable": true, - "poe_good": true, - "poe_power": "9.81", - "poe_voltage": "52.88", - "rx_broadcast": 63647, - "rx_bytes": 2607385367644, - "rx_dropped": 157620, - "rx_errors": 0, - "rx_multicast": 164740, - "rx_packets": 1811240949, - "satisfaction": 90, - "speed": 100, - "stp_pathcost": 200000, - "stp_state": "forwarding", - "tx_broadcast": 354985, - "tx_bytes": 29502203517, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 2419671, - "tx_packets": 414986830, - "up": true, - "tx_bytes-r": 9281, - "rx_bytes-r": 781308, - "bytes-r": 790589, - "name": "Camera: Pool", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 10, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26847", - "poe_mode": "off", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Unknown", - "poe_current": "0.00", - "poe_enable": false, - "poe_good": false, - "poe_power": "0.00", - "poe_voltage": "0.00", - "rx_broadcast": 133159, - "rx_bytes": 2980426813696, - "rx_dropped": 86, - "rx_errors": 0, - "rx_multicast": 1194903, - "rx_packets": 2315914383, - "satisfaction": 90, - "speed": 1000, - "stp_pathcost": 20000, - "stp_state": "forwarding", - "tx_broadcast": 2154128, - "tx_bytes": 1464180769133, - "tx_dropped": 250473, - "tx_errors": 0, - "tx_multicast": 13471964, - "tx_packets": 2230137488, - "up": true, - "tx_bytes-r": 1250938, - "rx_bytes-r": 2919503, - "bytes-r": 4170441, - "name": "Security: Home Port", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 11, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "59a362f645663e6cc8260134", - "poe_mode": "auto", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Class 0", - "poe_current": "12.93", - "poe_enable": true, - "poe_good": true, - "poe_power": "0.69", - "poe_voltage": "53.01", - "rx_broadcast": 10728, - "rx_bytes": 252244504, - "rx_dropped": 0, - "rx_errors": 2, - "rx_multicast": 0, - "rx_packets": 2540659, - "satisfaction": 85, - "speed": 100, - "stp_pathcost": 200000, - "stp_state": "forwarding", - "tx_broadcast": 407892, - "tx_bytes": 496402591, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 2312237, - "tx_packets": 6542398, - "up": true, - "tx_bytes-r": 120, - "rx_bytes-r": 79, - "bytes-r": 199, - "name": "8ch Relay Board", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 12, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "59a362f645663e6cc8260134", - "poe_mode": "off", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Unknown", - "poe_current": "0.00", - "poe_enable": false, - "poe_good": false, - "poe_power": "0.00", - "poe_voltage": "0.00", - "rx_broadcast": 19342, - "rx_bytes": 190236042211, - "rx_dropped": 174281, - "rx_errors": 0, - "rx_multicast": 649832, - "rx_packets": 2704715442, - "satisfaction": 90, - "speed": 1000, - "stp_pathcost": 20000, - "stp_state": "forwarding", - "tx_broadcast": 395664, - "tx_bytes": 18974306738758, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 1886642, - "tx_packets": 13093826470, - "up": true, - "tx_bytes-r": 5653872, - "rx_bytes-r": 67700, - "bytes-r": 5721573, - "name": "Security: Secure Port", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 13, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26845", - "poe_mode": "auto", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Class 0", - "poe_current": "88.13", - "poe_enable": true, - "poe_good": true, - "poe_power": "4.65", - "poe_voltage": "52.76", - "rx_broadcast": 383577, - "rx_bytes": 550646722109, - "rx_dropped": 116302, - "rx_errors": 0, - "rx_multicast": 2950663, - "rx_packets": 892359442, - "satisfaction": 90, - "speed": 1000, - "stp_pathcost": 20000, - "stp_state": "forwarding", - "tx_broadcast": 2351476, - "tx_bytes": 1374251273399, - "tx_dropped": 614, - "tx_errors": 0, - "tx_multicast": 12430218, - "tx_packets": 1140545051, - "up": true, - "tx_bytes-r": 1098062, - "rx_bytes-r": 81853, - "bytes-r": 1179915, - "name": "Upstairs WAP", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 14, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26845", - "poe_mode": "auto", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": false, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Unknown", - "poe_current": "0.00", - "poe_enable": false, - "poe_good": false, - "poe_power": "0.00", - "poe_voltage": "0.00", - "rx_broadcast": 0, - "rx_bytes": 0, - "rx_dropped": 0, - "rx_errors": 0, - "rx_multicast": 0, - "rx_packets": 0, - "satisfaction": 100, - "speed": 0, - "stp_pathcost": 0, - "stp_state": "disabled", - "tx_broadcast": 0, - "tx_bytes": 0, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 0, - "tx_packets": 0, - "up": false, - "tx_bytes-r": 0, - "rx_bytes-r": 0, - "bytes-r": 0, - "name": "Port 14", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 15, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26845", - "poe_mode": "auto", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Class 0", - "poe_current": "71.65", - "poe_enable": true, - "poe_good": true, - "poe_power": "3.77", - "poe_voltage": "52.63", - "rx_broadcast": 196313, - "rx_bytes": 155746936125, - "rx_dropped": 19700, - "rx_errors": 0, - "rx_multicast": 2064123, - "rx_packets": 254212324, - "satisfaction": 90, - "speed": 1000, - "stp_pathcost": 20000, - "stp_state": "forwarding", - "tx_broadcast": 2538787, - "tx_bytes": 229690921008, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 13311081, - "tx_packets": 260289095, - "up": true, - "tx_bytes-r": 20824, - "rx_bytes-r": 4227, - "bytes-r": 25051, - "name": "Downstairs WAP", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 16, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26845", - "poe_mode": "off", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Unknown", - "poe_current": "0.00", - "poe_enable": false, - "poe_good": false, - "poe_power": "0.00", - "poe_voltage": "0.00", - "rx_broadcast": 11925, - "rx_bytes": 300038087723, - "rx_dropped": 6, - "rx_errors": 0, - "rx_multicast": 105090, - "rx_packets": 487779140, - "satisfaction": 90, - "speed": 1000, - "stp_pathcost": 20000, - "stp_state": "forwarding", - "tx_broadcast": 2698267, - "tx_bytes": 1161896194876, - "tx_dropped": 2542, - "tx_errors": 0, - "tx_multicast": 15097190, - "tx_packets": 936474098, - "up": true, - "tx_bytes-r": 792886, - "rx_bytes-r": 1134268, - "bytes-r": 1927154, - "name": "David's Desk", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 17, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "59a362f645663e6cc8260134", - "poe_mode": "auto", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Class 0", - "poe_current": "52.24", - "poe_enable": true, - "poe_good": true, - "poe_power": "2.75", - "poe_voltage": "52.69", - "rx_broadcast": 57982, - "rx_bytes": 3736764408104, - "rx_dropped": 157644, - "rx_errors": 1, - "rx_multicast": 157809, - "rx_packets": 2553432414, - "satisfaction": 75, - "speed": 100, - "stp_pathcost": 200000, - "stp_state": "forwarding", - "tx_broadcast": 360666, - "tx_bytes": 37300635720, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 2433676, - "tx_packets": 525589037, - "up": true, - "tx_bytes-r": 11826, - "rx_bytes-r": 1204374, - "bytes-r": 1216200, - "name": "Camera: Door", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 18, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26845", - "poe_mode": "auto", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Unknown", - "poe_current": "0.00", - "poe_enable": false, - "poe_good": false, - "poe_power": "0.00", - "poe_voltage": "0.00", - "rx_broadcast": 106288, - "rx_bytes": 2133344721406, - "rx_dropped": 25, - "rx_errors": 12, - "rx_multicast": 311666, - "rx_packets": 2159594753, - "satisfaction": 75, - "speed": 1000, - "stp_pathcost": 20000, - "stp_state": "forwarding", - "tx_broadcast": 2629049, - "tx_bytes": 1194122124612, - "tx_dropped": 7147, - "tx_errors": 0, - "tx_multicast": 15063781, - "tx_packets": 1677508931, - "up": true, - "tx_bytes-r": 37435, - "rx_bytes-r": 1009309, - "bytes-r": 1046744, - "name": "Port 18", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 19, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "59a362f645663e6cc8260134", - "poe_mode": "auto", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Class 0", - "poe_current": "84.22", - "poe_enable": true, - "poe_good": true, - "poe_power": "4.43", - "poe_voltage": "52.56", - "rx_broadcast": 59295, - "rx_bytes": 1565104688294, - "rx_dropped": 157648, - "rx_errors": 0, - "rx_multicast": 157775, - "rx_packets": 1148468555, - "satisfaction": 90, - "speed": 100, - "stp_pathcost": 200000, - "stp_state": "forwarding", - "tx_broadcast": 359378, - "tx_bytes": 1645861732, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 2433784, - "tx_packets": 21052239, - "up": true, - "tx_bytes-r": 8133, - "rx_bytes-r": 483735, - "bytes-r": 491868, - "name": "Camera: Porch", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 20, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26845", - "poe_mode": "auto", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": false, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Unknown", - "poe_current": "0.00", - "poe_enable": false, - "poe_good": false, - "poe_power": "0.00", - "poe_voltage": "0.00", - "rx_broadcast": 0, - "rx_bytes": 0, - "rx_dropped": 0, - "rx_errors": 0, - "rx_multicast": 0, - "rx_packets": 0, - "satisfaction": 100, - "speed": 0, - "stp_pathcost": 0, - "stp_state": "disabled", - "tx_broadcast": 0, - "tx_bytes": 0, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 0, - "tx_packets": 0, - "up": false, - "tx_bytes-r": 0, - "rx_bytes-r": 0, - "bytes-r": 0, - "name": "Port 20", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 21, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "59a362f645663e6cc8260134", - "poe_mode": "auto", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Class 0", - "poe_current": "123.90", - "poe_enable": true, - "poe_good": true, - "poe_power": "6.56", - "poe_voltage": "52.95", - "rx_broadcast": 61014, - "rx_bytes": 3317256188719, - "rx_dropped": 157642, - "rx_errors": 0, - "rx_multicast": 157803, - "rx_packets": 2220162515, - "satisfaction": 90, - "speed": 100, - "stp_pathcost": 200000, - "stp_state": "forwarding", - "tx_broadcast": 357637, - "tx_bytes": 30626674529, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 2433710, - "tx_packets": 428205094, - "up": true, - "tx_bytes-r": 9771, - "rx_bytes-r": 1006105, - "bytes-r": 1015877, - "name": "Camera: Road", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 22, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26845", - "poe_mode": "off", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Unknown", - "poe_current": "0.00", - "poe_enable": false, - "poe_good": false, - "poe_power": "0.00", - "poe_voltage": "0.00", - "rx_broadcast": 14465, - "rx_bytes": 794839703, - "rx_dropped": 3, - "rx_errors": 0, - "rx_multicast": 1080600, - "rx_packets": 5377988, - "satisfaction": 90, - "speed": 100, - "stp_pathcost": 200000, - "stp_state": "forwarding", - "tx_broadcast": 2720299, - "tx_bytes": 9381221794, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 14294088, - "tx_packets": 37961870, - "up": true, - "tx_bytes-r": 4900, - "rx_bytes-r": 536, - "bytes-r": 5436, - "name": "Livingroom Stereo", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 23, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26845", - "poe_mode": "off", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "poe_class": "Unknown", - "poe_current": "0.00", - "poe_enable": false, - "poe_good": false, - "poe_power": "0.00", - "poe_voltage": "0.00", - "rx_broadcast": 532640, - "rx_bytes": 331010131889, - "rx_dropped": 35400, - "rx_errors": 0, - "rx_multicast": 576408, - "rx_packets": 261698587, - "satisfaction": 90, - "speed": 1000, - "stp_pathcost": 20000, - "stp_state": "forwarding", - "tx_broadcast": 2202860, - "tx_bytes": 15811798849, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 14799244, - "tx_packets": 184788576, - "up": true, - "tx_bytes-r": 1611, - "rx_bytes-r": 3806, - "bytes-r": 5418, - "name": "Homerun Prime", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 24, - "media": "GE", - "port_poe": true, - "poe_caps": 7, - "speed_caps": 1048623, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26845", - "poe_mode": "off", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": true, - "is_uplink": true, - "jumbo": false, - "lldp_table": [ - { - "lldp_chassis_id": "22:22:00:22:22:00", - "lldp_port_id": "eth1", - "lldp_system_name": "gateway" - } - ], - "poe_class": "Unknown", - "poe_current": "0.00", - "poe_enable": false, - "poe_good": false, - "poe_power": "0.00", - "poe_voltage": "0.00", - "rx_broadcast": 186134, - "rx_bytes": 2149399426518, - "rx_dropped": 183, - "rx_errors": 0, - "rx_multicast": 4799002, - "rx_packets": 2730988091, - "satisfaction": 90, - "speed": 1000, - "stp_pathcost": 20000, - "stp_state": "forwarding", - "tx_broadcast": 2549473, - "tx_bytes": 2905955335082, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 11918890, - "tx_packets": 2655236464, - "up": true, - "tx_bytes-r": 2348698, - "rx_bytes-r": 393352, - "bytes-r": 2742050, - "name": "gateway", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 25, - "media": "SFP", - "port_poe": false, - "poe_caps": 0, - "speed_caps": 1048608, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26845", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": false, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "rx_broadcast": 0, - "rx_bytes": 0, - "rx_dropped": 0, - "rx_errors": 0, - "rx_multicast": 0, - "rx_packets": 0, - "satisfaction": 100, - "sfp_found": false, - "speed": 0, - "stp_pathcost": 0, - "stp_state": "disabled", - "tx_broadcast": 0, - "tx_bytes": 0, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 0, - "tx_packets": 0, - "up": false, - "tx_bytes-r": 0, - "rx_bytes-r": 0, - "bytes-r": 0, - "name": "SFP 1", - "masked": false, - "aggregated_by": false - }, - { - "port_idx": 26, - "media": "SFP", - "port_poe": false, - "poe_caps": 0, - "speed_caps": 1048608, - "op_mode": "switch", - "portconf_id": "574e869d4566ffb914a26845", - "autoneg": true, - "dot1x_mode": "unknown", - "dot1x_status": "disabled", - "enable": true, - "flowctrl_rx": false, - "flowctrl_tx": false, - "full_duplex": false, - "is_uplink": false, - "jumbo": false, - "lldp_table": [], - "rx_broadcast": 0, - "rx_bytes": 0, - "rx_dropped": 0, - "rx_errors": 0, - "rx_multicast": 0, - "rx_packets": 0, - "satisfaction": 100, - "sfp_found": false, - "speed": 0, - "stp_pathcost": 0, - "stp_state": "disabled", - "tx_broadcast": 0, - "tx_bytes": 0, - "tx_dropped": 0, - "tx_errors": 0, - "tx_multicast": 0, - "tx_packets": 0, - "up": false, - "tx_bytes-r": 0, - "rx_bytes-r": 0, - "bytes-r": 0, - "name": "SFP 2", - "masked": false, - "aggregated_by": false - } - ], - "serial": "xxxyyyzzz", - "site_id": "574e86994566ffb914a2683c", - "stp_priority": "32768", - "stp_version": "rstp", - "type": "usw", - "version": "4.0.42.10433", - "required_version": "3.3.1", - "switch_caps": { - "feature_caps": 1022, - "max_mirror_sessions": 1, - "max_aggregate_sessions": 6 - }, - "hw_caps": 0, - "unsupported": false, - "unsupported_reason": 0, - "sys_error_caps": 0, - "device_id": "59a35cee45663e6cc82600f0", - "state": 1, - "last_seen": 1562309680, - "upgradable": false, - "adoptable_when_upgraded": false, - "rollupgrade": false, - "known_cfgversion": "669564dd04994088", - "uptime": 3188809, - "_uptime": 3188809, - "locating": false, - "connect_request_ip": "192.168.1.7", - "connect_request_port": "45941", - "sys_stats": { - "loadavg_1": "1.83", - "loadavg_15": "1.72", - "loadavg_5": "1.77", - "mem_buffer": 0, - "mem_total": 262397952, - "mem_used": 131473408 - }, - "system-stats": { - "cpu": "59.3", - "mem": "50.1", - "uptime": "3188809" - }, - "ssh_session_table": [], - "fan_level": 50, - "general_temperature": 43, - "overheating": false, - "total_max_power": 222, - "downlink_table": [ - { - "port_idx": 13, - "speed": 1000, - "full_duplex": true, - "mac": "22:22:00:22:22:00" - }, - { - "port_idx": 15, - "speed": 1000, - "full_duplex": true, - "mac": "22:22:00:22:22:00" - } - ], - "uplink": { - "full_duplex": true, - "ip": "192.168.1.7", - "mac": "22:22:00:22:22:00", - "name": "eth0", - "netmask": "255.255.252.0", - "num_port": 26, - "rx_bytes": 2149399426518, - "rx_dropped": 183, - "rx_errors": 0, - "rx_multicast": 0, - "rx_packets": 2730988091, - "speed": 1000, - "tx_bytes": 2905955335082, - "tx_dropped": 0, - "tx_errors": 0, - "tx_packets": 2655236464, - "up": true, - "port_idx": 24, - "media": "GE", - "max_speed": 1000, - "uplink_mac": "22:22:00:22:22:00", - "type": "wire", - "tx_bytes-r": 2348698, - "rx_bytes-r": 393352 - }, - "last_uplink": { - "uplink_mac": "22:22:00:22:22:00" - }, - "uplink_depth": 1, - "dhcp_server_table": [], - "stat": { - "site_id": "574e86994566ffb914a2683c", - "o": "sw", - "oid": "22:22:00:22:22:00", - "sw": "22:22:00:22:22:00", - "time": 1562207400000, - "datetime": "2019-07-04T02:30:00Z", - "rx_packets": 1521931792, - "rx_bytes": 1640634193054, - "rx_errors": 0, - "rx_dropped": 44998, - "rx_crypts": 0, - "rx_frags": 0, - "tx_packets": 1526591275, - "tx_bytes": 1641404646603, - "tx_errors": 0, - "tx_dropped": 230234, - "tx_retries": 0, - "rx_multicast": 477933, - "rx_broadcast": 134416, - "tx_multicast": 4372775, - "tx_broadcast": 1123817, - "bytes": 3282038839657, - "duration": 102277000, - "port_1-rx_packets": 37407, - "port_1-rx_bytes": 7345154, - "port_1-tx_packets": 142648, - "port_1-tx_bytes": 15425151, - "port_1-tx_multicast": 72854, - "port_1-tx_broadcast": 13075, - "port_3-rx_packets": 88198959, - "port_3-rx_bytes": 127291063971, - "port_3-tx_packets": 20230363, - "port_3-tx_bytes": 1436625813, - "port_3-rx_broadcast": 2037, - "port_3-tx_multicast": 78496, - "port_3-tx_broadcast": 11062, - "port_6-rx_packets": 37102295, - "port_6-rx_bytes": 54565186228, - "port_6-tx_packets": 11561353, - "port_6-tx_bytes": 814818610, - "port_6-rx_multicast": 4504, - "port_6-tx_multicast": 76688, - "port_6-tx_broadcast": 12634, - "port_7-rx_packets": 59149016, - "port_7-rx_bytes": 84615020479, - "port_7-tx_packets": 14033190, - "port_7-tx_bytes": 996438501, - "port_7-tx_multicast": 78496, - "port_7-tx_broadcast": 11058, - "port_9-rx_packets": 58736633, - "port_9-rx_bytes": 84549190443, - "port_9-tx_packets": 14151617, - "port_9-tx_bytes": 1004772261, - "port_9-tx_multicast": 78496, - "port_9-tx_broadcast": 11058, - "port_10-rx_packets": 267372091, - "port_10-rx_bytes": 281500610536, - "port_10-tx_packets": 563250041, - "port_10-tx_bytes": 567769155042, - "port_10-rx_multicast": 43302, - "port_10-tx_multicast": 424255, - "port_10-tx_broadcast": 119711, - "port_11-rx_packets": 81983, - "port_11-rx_bytes": 8144416, - "port_11-tx_packets": 209313, - "port_11-tx_bytes": 15405574, - "port_11-tx_multicast": 73730, - "port_11-tx_broadcast": 12758, - "port_12-rx_packets": 103277309, - "port_12-rx_bytes": 7258199289, - "port_12-tx_packets": 439910260, - "port_12-tx_bytes": 639760721999, - "port_12-tx_multicast": 60704, - "port_12-tx_broadcast": 12565, - "port_13-rx_packets": 246443105, - "port_13-rx_bytes": 198040237192, - "port_13-tx_packets": 78593344, - "port_13-tx_bytes": 57869606583, - "port_13-rx_multicast": 137299, - "port_13-rx_broadcast": 65040, - "port_13-tx_multicast": 355704, - "port_13-tx_broadcast": 72404, - "port_15-rx_packets": 91090086, - "port_15-rx_bytes": 129066815209, - "port_15-tx_packets": 21964312, - "port_15-tx_bytes": 8996022939, - "port_15-rx_broadcast": 6271, - "port_15-tx_multicast": 470685, - "port_15-tx_broadcast": 131171, - "port_16-rx_packets": 186203471, - "port_16-rx_bytes": 238718016683, - "port_16-tx_packets": 111909553, - "port_16-tx_bytes": 116205334442, - "port_16-tx_multicast": 484907, - "port_16-tx_broadcast": 137180, - "port_17-rx_packets": 88192775, - "port_17-rx_bytes": 129333707339, - "port_17-tx_packets": 18059043, - "port_17-tx_bytes": 1280177720, - "port_17-tx_multicast": 78951, - "port_17-tx_broadcast": 11288, - "port_18-rx_packets": 47274835, - "port_18-rx_bytes": 52416730761, - "port_18-tx_packets": 31288433, - "port_18-tx_bytes": 19604228682, - "port_18-rx_multicast": 10027, - "port_18-tx_multicast": 478207, - "port_18-tx_broadcast": 136852, - "port_19-rx_packets": 37113361, - "port_19-rx_bytes": 51866531433, - "port_19-tx_packets": 11858558, - "port_19-tx_bytes": 835844449, - "port_19-tx_multicast": 78952, - "port_19-tx_broadcast": 11216, - "port_21-rx_packets": 72039284, - "port_21-rx_bytes": 107639322810, - "port_21-tx_packets": 14367901, - "port_21-tx_bytes": 1026379138, - "port_21-rx_broadcast": 1926, - "port_21-tx_multicast": 78951, - "port_21-tx_broadcast": 11173, - "port_22-rx_packets": 176103, - "port_22-rx_bytes": 25390561, - "port_22-tx_packets": 1272735, - "port_22-tx_bytes": 294225324, - "port_22-rx_multicast": 35968, - "port_22-tx_multicast": 452266, - "port_22-tx_broadcast": 137038, - "port_23-rx_packets": 4246915, - "port_23-rx_bytes": 4976913808, - "port_23-rx_dropped": 1138, - "port_23-tx_packets": 2141027, - "port_23-tx_bytes": 251388436, - "port_23-rx_multicast": 18478, - "port_23-rx_broadcast": 17522, - "port_23-tx_multicast": 469756, - "port_23-tx_broadcast": 119922, - "port_24-rx_packets": 134576026, - "port_24-rx_bytes": 88659302916, - "port_24-tx_packets": 170136735, - "port_24-tx_bytes": 221668518676, - "port_24-rx_multicast": 153949, - "port_24-tx_multicast": 376773, - "port_24-tx_broadcast": 132998, - "port_1-rx_multicast": 881, - "port_3-rx_dropped": 5055, - "port_3-rx_multicast": 5283, - "port_6-rx_dropped": 3370, - "port_7-rx_dropped": 5052, - "port_7-rx_multicast": 5280, - "port_9-rx_dropped": 5052, - "port_9-rx_multicast": 5280, - "port_9-rx_broadcast": 2041, - "port_10-rx_broadcast": 4628, - "port_12-rx_dropped": 5055, - "port_12-rx_multicast": 19895, - "port_13-rx_dropped": 3759, - "port_17-rx_dropped": 5055, - "port_17-rx_multicast": 5055, - "port_17-rx_broadcast": 1811, - "port_19-rx_dropped": 5055, - "port_19-rx_multicast": 5055, - "port_19-rx_broadcast": 1883, - "port_21-rx_dropped": 5055, - "port_21-rx_multicast": 5055, - "port_7-rx_broadcast": 2041, - "port_18-rx_broadcast": 590, - "port_16-rx_multicast": 3329, - "port_15-rx_dropped": 800, - "port_15-rx_multicast": 17552, - "port_16-rx_broadcast": 262, - "port_11-rx_broadcast": 341, - "port_12-rx_broadcast": 534, - "port_6-rx_broadcast": 465, - "port_24-rx_broadcast": 4447, - "port_22-rx_broadcast": 404, - "port_10-tx_dropped": 195211, - "port_16-tx_dropped": 251, - "port_1-rx_broadcast": 20, - "port_4-rx_packets": 620138, - "port_4-rx_bytes": 96463826, - "port_4-rx_dropped": 552, - "port_4-tx_packets": 1510849, - "port_4-tx_bytes": 1559557263, - "port_4-tx_dropped": 34772, - "port_4-rx_multicast": 1741, - "port_4-rx_broadcast": 22153, - "port_4-tx_multicast": 103904, - "port_4-tx_broadcast": 18654 - }, - "tx_bytes": 2149399426518, - "rx_bytes": 2905955335082, - "bytes": 5055354761600, - "num_sta": 16, - "user-num_sta": 16, - "guest-num_sta": 0 -}, diff --git a/core/unifi/v4/go.mod b/core/unifi/v4/go.mod deleted file mode 100644 index 9757df3f..00000000 --- a/core/unifi/v4/go.mod +++ /dev/null @@ -1,9 +0,0 @@ -module golift.io/unifi/v4 - -go 1.13 - -require ( - github.com/davecgh/go-spew v1.1.1 - github.com/pmezard/go-difflib v1.0.0 - github.com/stretchr/testify v1.4.0 -) diff --git a/core/unifi/v4/go.sum b/core/unifi/v4/go.sum deleted file mode 100644 index 1041afa2..00000000 --- a/core/unifi/v4/go.sum +++ /dev/null @@ -1,11 +0,0 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/core/unifi/v4/ids.go b/core/unifi/v4/ids.go deleted file mode 100644 index 6af0c8ab..00000000 --- a/core/unifi/v4/ids.go +++ /dev/null @@ -1,150 +0,0 @@ -package unifi - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "time" -) - -// IDSList contains a list that contains all of the IDS Events on a controller. -type IDSList []*IDS - -// IDS holds an Intrusion Prevention System Event. -type IDS struct { - SourceName string `json:"-"` - ID string `json:"_id"` - Archived FlexBool `json:"archived"` - Timestamp int64 `json:"timestamp"` - FlowID int64 `json:"flow_id"` - InIface string `json:"in_iface"` - EventType string `json:"event_type"` - SrcIP string `json:"src_ip"` - SrcMac string `json:"src_mac"` - SrcPort int `json:"src_port,omitempty"` - DestIP string `json:"dest_ip"` - DstMac string `json:"dst_mac"` - DestPort int `json:"dest_port,omitempty"` - Proto string `json:"proto"` - AppProto string `json:"app_proto,omitempty"` - Host string `json:"host"` - Usgip string `json:"usgip"` - UniqueAlertid string `json:"unique_alertid"` - SrcipCountry string `json:"srcipCountry"` - DstipCountry FlexBool `json:"dstipCountry"` - UsgipCountry string `json:"usgipCountry"` - SrcipGeo struct { - ContinentCode string `json:"continent_code"` - CountryCode string `json:"country_code"` - CountryCode3 string `json:"country_code3"` - CountryName string `json:"country_name"` - Region string `json:"region"` - City string `json:"city"` - PostalCode string `json:"postal_code"` - Latitude float64 `json:"latitude"` - Longitude float64 `json:"longitude"` - DmaCode int64 `json:"dma_code"` - AreaCode int64 `json:"area_code"` - } `json:"srcipGeo"` - DstipGeo bool `json:"dstipGeo"` - UsgipGeo struct { - ContinentCode string `json:"continent_code"` - CountryCode string `json:"country_code"` - CountryCode3 string `json:"country_code3"` - CountryName string `json:"country_name"` - Region string `json:"region"` - City string `json:"city"` - PostalCode string `json:"postal_code"` - Latitude float64 `json:"latitude"` - Longitude float64 `json:"longitude"` - DmaCode int64 `json:"dma_code"` - AreaCode int64 `json:"area_code"` - } `json:"usgipGeo"` - SrcipASN string `json:"srcipASN"` - DstipASN string `json:"dstipASN"` - UsgipASN string `json:"usgipASN"` - Catname string `json:"catname"` - InnerAlertAction string `json:"inner_alert_action"` - InnerAlertGID int64 `json:"inner_alert_gid"` - InnerAlertSignatureID int64 `json:"inner_alert_signature_id"` - InnerAlertRev int64 `json:"inner_alert_rev"` - InnerAlertSignature string `json:"inner_alert_signature"` - InnerAlertCategory string `json:"inner_alert_category"` - InnerAlertSeverity int64 `json:"inner_alert_severity"` - Key string `json:"key"` - Subsystem string `json:"subsystem"` - SiteID string `json:"site_id"` - SiteName string `json:"-"` - Time int64 `json:"time"` - Datetime time.Time `json:"datetime"` - Msg string `json:"msg"` - IcmpType int64 `json:"icmp_type,omitempty"` - IcmpCode int64 `json:"icmp_code,omitempty"` -} - -// GetIDS returns Intrusion Detection Systems events. -// Returns all events that happened in site between from and to. -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) - if err != nil { - return data, err - } - - for i := range ids { - ids[i].SourceName = u.URL - } - - data = append(data, ids...) - } - - return data, nil -} - -// 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) { - var response struct { - Data []*IDS `json:"data"` - } - - URIpath := fmt.Sprintf(APIIPSEvents, site.Name) - - params := fmt.Sprintf(`{"start":"%v000","end":"%v000","_limit":50000}`, from.Unix(), to.Unix()) - - req, err := u.UniReq(URIpath, params) - if err != nil { - return nil, err - } - - resp, err := u.Do(req) - if err != nil { - return nil, err - } - - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("invalid status code from server %s", resp.Status) - } - - if err := json.Unmarshal(body, &response); err != nil { - return nil, err - } - - for i := range response.Data { - response.Data[i].SiteName = site.SiteName - } - - return response.Data, nil -} diff --git a/core/unifi/v4/site.go b/core/unifi/v4/site.go deleted file mode 100644 index 20018b03..00000000 --- a/core/unifi/v4/site.go +++ /dev/null @@ -1,124 +0,0 @@ -package unifi - -import ( - "fmt" - "strings" -) - -// GetSites returns a list of configured sites on the UniFi controller. -func (u *Unifi) GetSites() (Sites, error) { - var response struct { - Data []*Site `json:"data"` - } - - if err := u.GetData(APISiteList, &response); err != nil { - return nil, err - } - - sites := []string{} // used for debug log only - - for i, d := range response.Data { - // Add special SourceName value. - response.Data[i].SourceName = u.URL - // If the human name is missing (description), set it to the cryptic name. - response.Data[i].Desc = pick(d.Desc, d.Name) - // Add the custom site name to each site. used as a Grafana filter somewhere. - response.Data[i].SiteName = d.Desc + " (" + d.Name + ")" - sites = append(sites, d.Name) // used for debug log only - } - - u.DebugLog("Found %d site(s): %s", len(sites), strings.Join(sites, ",")) - - return response.Data, nil -} - -// GetSiteDPI garners dpi data for sites. -func (u *Unifi) GetSiteDPI(sites Sites) ([]*DPITable, error) { - data := []*DPITable{} - - for _, site := range sites { - u.DebugLog("Polling Controller, retreiving Site DPI data, site %s (%s) ", site.Name, site.Desc) - - var response struct { - Data []*DPITable `json:"data"` - } - - siteDPIpath := fmt.Sprintf(APISiteDPI, site.Name) - if err := u.GetData(siteDPIpath, &response, `{"type":"by_app"}`); err != nil { - return nil, err - } - - if l := len(response.Data); l > 1 { - return nil, fmt.Errorf("dpi data table contains more than 1 item; please open a bug report") - } else if l != 1 { - continue - } - - response.Data[0].SourceName = site.SourceName - response.Data[0].SiteName = site.SiteName - data = append(data, response.Data[0]) - } - - return data, nil -} - -// Sites is a struct to match Devices and Clients. -type Sites []*Site - -// Site represents a site's data. -type Site struct { - SourceName string `json:"-"` - ID string `json:"_id"` - Name string `json:"name"` - Desc string `json:"desc"` - SiteName string `json:"-"` - AttrHiddenID string `json:"attr_hidden_id"` - AttrNoDelete FlexBool `json:"attr_no_delete"` - Health []struct { - Subsystem string `json:"subsystem"` - NumUser FlexInt `json:"num_user,omitempty"` - NumGuest FlexInt `json:"num_guest,omitempty"` - NumIot FlexInt `json:"num_iot,omitempty"` - TxBytesR FlexInt `json:"tx_bytes-r,omitempty"` - RxBytesR FlexInt `json:"rx_bytes-r,omitempty"` - Status string `json:"status"` - NumAp FlexInt `json:"num_ap,omitempty"` - NumAdopted FlexInt `json:"num_adopted,omitempty"` - NumDisabled FlexInt `json:"num_disabled,omitempty"` - NumDisconnected FlexInt `json:"num_disconnected,omitempty"` - NumPending FlexInt `json:"num_pending,omitempty"` - NumGw FlexInt `json:"num_gw,omitempty"` - WanIP string `json:"wan_ip,omitempty"` - Gateways []string `json:"gateways,omitempty"` - Netmask string `json:"netmask,omitempty"` - Nameservers []string `json:"nameservers,omitempty"` - NumSta FlexInt `json:"num_sta,omitempty"` - GwMac string `json:"gw_mac,omitempty"` - GwName string `json:"gw_name,omitempty"` - GwSystemStats struct { - CPU FlexInt `json:"cpu"` - Mem FlexInt `json:"mem"` - Uptime FlexInt `json:"uptime"` - } `json:"gw_system-stats,omitempty"` - GwVersion string `json:"gw_version,omitempty"` - Latency FlexInt `json:"latency,omitempty"` - Uptime FlexInt `json:"uptime,omitempty"` - Drops FlexInt `json:"drops,omitempty"` - XputUp FlexInt `json:"xput_up,omitempty"` - XputDown FlexInt `json:"xput_down,omitempty"` - SpeedtestStatus string `json:"speedtest_status,omitempty"` - SpeedtestLastrun FlexInt `json:"speedtest_lastrun,omitempty"` - SpeedtestPing FlexInt `json:"speedtest_ping,omitempty"` - LanIP string `json:"lan_ip,omitempty"` - NumSw FlexInt `json:"num_sw,omitempty"` - RemoteUserEnabled FlexBool `json:"remote_user_enabled,omitempty"` - RemoteUserNumActive FlexInt `json:"remote_user_num_active,omitempty"` - RemoteUserNumInactive FlexInt `json:"remote_user_num_inactive,omitempty"` - RemoteUserRxBytes FlexInt `json:"remote_user_rx_bytes,omitempty"` - RemoteUserTxBytes FlexInt `json:"remote_user_tx_bytes,omitempty"` - RemoteUserRxPackets FlexInt `json:"remote_user_rx_packets,omitempty"` - RemoteUserTxPackets FlexInt `json:"remote_user_tx_packets,omitempty"` - SiteToSiteEnabled FlexBool `json:"site_to_site_enabled,omitempty"` - } `json:"health"` - NumNewAlarms FlexInt `json:"num_new_alarms"` -} diff --git a/core/unifi/v4/types.go b/core/unifi/v4/types.go deleted file mode 100644 index ed298f40..00000000 --- a/core/unifi/v4/types.go +++ /dev/null @@ -1,132 +0,0 @@ -package unifi - -import ( - "encoding/json" - "fmt" - "net/http" - "strconv" - "strings" -) - -// This is a list of unifi API paths. -// The %s in each string must be replaced with a Site.Name. -const ( - // APIStatusPath shows Controller version. - APIStatusPath string = "/status" - // APISiteList is the path to the api site list. - APISiteList string = "/api/stat/sites" - // APISiteDPI is site DPI data. - APISiteDPI string = "/api/s/%s/stat/sitedpi" - // APISiteDPI is site DPI data. - APIClientDPI string = "/api/s/%s/stat/stadpi" - // APIClientPath is Unifi Clients API Path - APIClientPath string = "/api/s/%s/stat/sta" - // APIDevicePath is where we get data about Unifi devices. - APIDevicePath string = "/api/s/%s/stat/device" - // APINetworkPath contains network-configuration data. Not really graphable. - APINetworkPath string = "/api/s/%s/rest/networkconf" - // APIUserGroupPath contains usergroup configurations. - APIUserGroupPath string = "/api/s/%s/rest/usergroup" - // APILoginPath is Unifi Controller Login API Path - APILoginPath string = "/api/login" - // APIIPSEvents returns Intrusion Detection Systems Events - APIIPSEvents string = "/api/s/%s/stat/ips/event" -) - -// Logger is a base type to deal with changing log outputs. Create a logger -// that matches this interface to capture debug and error logs. -type Logger func(msg string, fmt ...interface{}) - -// discardLogs is the default debug logger. -func discardLogs(msg string, v ...interface{}) { - // do nothing. -} - -// 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 - UDMs []*UDM -} - -// Config is the data passed into our library. This configures things and allows -// us to connect to a controller and write log messages. -type Config struct { - User string - Pass string - URL string - VerifySSL bool - ErrorLog Logger - DebugLog Logger -} - -// Unifi is what you get in return for providing a password! Unifi represents -// a controller that you can make authenticated requests to. Use this to make -// additional requests for devices, clients or other custom data. Do not set -// the loggers to nil. Set them to DiscardLogs if you want no logs. -type Unifi struct { - *http.Client - *Config - *server -} - -// server is the /status endpoint from the Unifi controller. -type server struct { - Up FlexBool `json:"up"` - ServerVersion string `json:"server_version"` - UUID string `json:"uuid"` -} - -// FlexInt provides a container and unmarshalling for fields that may be -// numbers or strings in the Unifi API. -type FlexInt struct { - Val float64 - Txt string -} - -// UnmarshalJSON converts a string or number to an integer. -// Generally, do call this directly, it's used in the json interface. -func (f *FlexInt) UnmarshalJSON(b []byte) error { - var unk interface{} - - if err := json.Unmarshal(b, &unk); err != nil { - return err - } - - switch i := unk.(type) { - case float64: - f.Val = i - f.Txt = strconv.FormatFloat(i, 'f', -1, 64) - case string: - f.Txt = i - f.Val, _ = strconv.ParseFloat(i, 64) - case nil: - f.Txt = "0" - f.Val = 0 - default: - return fmt.Errorf("cannot unmarshal to FlexInt: %s", b) - } - - return nil -} - -// FlexBool provides a container and unmarshalling for fields that may be -// boolean or strings in the Unifi API. -type FlexBool struct { - Val bool - Txt string -} - -// UnmarshalJSON method converts armed/disarmed, yes/no, active/inactive or 0/1 to true/false. -// Really it converts ready, ok, up, t, armed, yes, active, enabled, 1, true to true. Anything else is false. -func (f *FlexBool) UnmarshalJSON(b []byte) error { - f.Txt = strings.Trim(string(b), `"`) - f.Val = f.Txt == "1" || strings.EqualFold(f.Txt, "true") || strings.EqualFold(f.Txt, "yes") || - strings.EqualFold(f.Txt, "t") || strings.EqualFold(f.Txt, "armed") || strings.EqualFold(f.Txt, "active") || - strings.EqualFold(f.Txt, "enabled") || strings.EqualFold(f.Txt, "ready") || strings.EqualFold(f.Txt, "up") || - strings.EqualFold(f.Txt, "ok") - - return nil -} diff --git a/core/unifi/v4/types_test.go b/core/unifi/v4/types_test.go deleted file mode 100644 index a7eeef06..00000000 --- a/core/unifi/v4/types_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package unifi - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestFlexInt(t *testing.T) { - t.Parallel() - a := assert.New(t) - five, seven := 5, 7 - - var r struct { - Five FlexInt `json:"five"` - Seven FlexInt `json:"seven"` - Auto FlexInt `json:"auto"` - Channel FlexInt `json:"channel"` - Nil FlexInt `json:"nil"` - } - - // test unmarshalling the custom type three times with different values. - a.Nil(json.Unmarshal([]byte(`{"five": "5", "seven": 7, "auto": "auto", "nil": null}`), &r)) - // test number in string. - a.EqualValues(five, r.Five.Val) - a.EqualValues("5", r.Five.Txt) - // test number. - a.EqualValues(seven, r.Seven.Val) - a.EqualValues("7", r.Seven.Txt) - // test string. - a.EqualValues(0, r.Auto.Val) - a.EqualValues("auto", r.Auto.Txt) - // test (error) struct. - a.NotNil(json.Unmarshal([]byte(`{"channel": {}}`), &r), - "a non-string and non-number must produce an error.") - a.EqualValues(0, r.Channel.Val) - // test null. - a.EqualValues(0, r.Nil.Val) - a.EqualValues("0", r.Nil.Txt) -} diff --git a/core/unifi/v4/uap.go b/core/unifi/v4/uap.go deleted file mode 100644 index 172504b8..00000000 --- a/core/unifi/v4/uap.go +++ /dev/null @@ -1,566 +0,0 @@ -package unifi - -import ( - "encoding/json" - "time" -) - -// UAP represents all the data from the Ubiquiti Controller for a Unifi Access Point. -// This was auto generated then edited by hand to get all the data types right. -type UAP struct { - SourceName string `json:"-"` - ID string `json:"_id"` - Adopted FlexBool `json:"adopted"` - AntennaTable []struct { - Default FlexBool `json:"default"` - ID FlexInt `json:"id"` - Name string `json:"name"` - Wifi0Gain FlexInt `json:"wifi0_gain"` - Wifi1Gain FlexInt `json:"wifi1_gain"` - } `json:"antenna_table"` - BandsteeringMode string `json:"bandsteering_mode,omitempty"` - BoardRev int `json:"board_rev"` - Cfgversion string `json:"cfgversion"` - ConfigNetwork struct { - Type string `json:"type"` - IP string `json:"ip"` - } `json:"config_network"` - CountrycodeTable []int `json:"countrycode_table"` - EthernetTable []struct { - Mac string `json:"mac"` - NumPort FlexInt `json:"num_port"` - Name string `json:"name"` - } `json:"ethernet_table"` - FwCaps int `json:"fw_caps"` - HasEth1 FlexBool `json:"has_eth1"` - HasSpeaker FlexBool `json:"has_speaker"` - InformIP string `json:"inform_ip"` - InformURL string `json:"inform_url"` - IP string `json:"ip"` - LedOverride string `json:"led_override"` - Mac string `json:"mac"` - MeshStaVapEnabled FlexBool `json:"mesh_sta_vap_enabled"` - Model string `json:"model"` - Name string `json:"name"` - OutdoorModeOverride string `json:"outdoor_mode_override"` - PortTable []Port `json:"port_table"` - RadioTable RadioTable `json:"radio_table"` - ScanRadioTable []interface{} `json:"scan_radio_table"` - Serial string `json:"serial"` - SiteID string `json:"site_id"` - SiteName string `json:"-"` - Type string `json:"type"` - Version string `json:"version"` - VwireTable []interface{} `json:"vwire_table"` - WifiCaps int `json:"wifi_caps"` - WlangroupIDNa string `json:"wlangroup_id_na"` - WlangroupIDNg string `json:"wlangroup_id_ng"` - RequiredVersion string `json:"required_version"` - HwCaps int `json:"hw_caps"` - Unsupported FlexBool `json:"unsupported"` - UnsupportedReason FlexInt `json:"unsupported_reason"` - SysErrorCaps int `json:"sys_error_caps"` - HasFan FlexBool `json:"has_fan"` - HasTemperature FlexBool `json:"has_temperature"` - DeviceID string `json:"device_id"` - State int `json:"state"` - LastSeen FlexInt `json:"last_seen"` - Upgradable FlexBool `json:"upgradable"` - AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` - Rollupgrade FlexBool `json:"rollupgrade"` - KnownCfgversion string `json:"known_cfgversion"` - Uptime FlexInt `json:"uptime"` - UUptime FlexInt `json:"_uptime"` - Locating FlexBool `json:"locating"` - ConnectRequestIP string `json:"connect_request_ip"` - ConnectRequestPort string `json:"connect_request_port"` - SysStats SysStats `json:"sys_stats"` - SystemStats SystemStats `json:"system-stats"` - SSHSessionTable []interface{} `json:"ssh_session_table"` - Scanning FlexBool `json:"scanning"` - SpectrumScanning FlexBool `json:"spectrum_scanning"` - GuestToken string `json:"guest_token"` - Meshv3PeerMac string `json:"meshv3_peer_mac"` - Satisfaction FlexInt `json:"satisfaction"` - Isolated FlexBool `json:"isolated"` - RadioTableStats RadioTableStats `json:"radio_table_stats"` - Uplink struct { - FullDuplex FlexBool `json:"full_duplex"` - IP string `json:"ip"` - Mac string `json:"mac"` - MaxVlan int `json:"max_vlan"` - Name string `json:"name"` - Netmask string `json:"netmask"` - NumPort int `json:"num_port"` - RxBytes FlexInt `json:"rx_bytes"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxMulticast FlexInt `json:"rx_multicast"` - RxPackets FlexInt `json:"rx_packets"` - Speed FlexInt `json:"speed"` - TxBytes FlexInt `json:"tx_bytes"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxPackets FlexInt `json:"tx_packets"` - Up FlexBool `json:"up"` - MaxSpeed FlexInt `json:"max_speed"` - Type string `json:"type"` - TxBytesR FlexInt `json:"tx_bytes-r"` - RxBytesR FlexInt `json:"rx_bytes-r"` - UplinkMac string `json:"uplink_mac"` - UplinkRemotePort int `json:"uplink_remote_port"` - } `json:"uplink"` - VapTable VapTable `json:"vap_table"` - DownlinkTable []struct { - PortIdx int `json:"port_idx"` - Speed int `json:"speed"` - FullDuplex bool `json:"full_duplex"` - Mac string `json:"mac"` - } `json:"downlink_table,omitempty"` - VwireVapTable []interface{} `json:"vwire_vap_table"` - BytesD FlexInt `json:"bytes-d"` - TxBytesD FlexInt `json:"tx_bytes-d"` - RxBytesD FlexInt `json:"rx_bytes-d"` - BytesR FlexInt `json:"bytes-r"` - LastUplink struct { - UplinkMac string `json:"uplink_mac"` - UplinkRemotePort int `json:"uplink_remote_port"` - } `json:"last_uplink"` - Stat UAPStat `json:"stat"` - TxBytes FlexInt `json:"tx_bytes"` - RxBytes FlexInt `json:"rx_bytes"` - Bytes FlexInt `json:"bytes"` - VwireEnabled FlexBool `json:"vwireEnabled"` - UplinkTable []interface{} `json:"uplink_table"` - NumSta FlexInt `json:"num_sta"` - UserNumSta FlexInt `json:"user-num_sta"` - GuestNumSta FlexInt `json:"guest-num_sta"` - TwoPhaseAdopt FlexBool `json:"two_phase_adopt,omitempty"` -} - -// UAPStat holds the "stat" data for an access point. -// This is split out because of a JSON data format change from 5.10 to 5.11. -type UAPStat struct { - *Ap -} - -// Ap is a subtype of UAPStat to make unmarshalling of different controller versions possible. -type Ap struct { - SiteID string `json:"site_id"` - O string `json:"o"` - Oid string `json:"oid"` - Ap string `json:"ap"` - Time FlexInt `json:"time"` - Datetime time.Time `json:"datetime"` - Bytes FlexInt `json:"bytes"` - Duration FlexInt `json:"duration"` - WifiTxDropped FlexInt `json:"wifi_tx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxDropped FlexInt `json:"rx_dropped"` - RxFrags FlexInt `json:"rx_frags"` - RxCrypts FlexInt `json:"rx_crypts"` - TxPackets FlexInt `json:"tx_packets"` - TxBytes FlexInt `json:"tx_bytes"` - TxErrors FlexInt `json:"tx_errors"` - TxDropped FlexInt `json:"tx_dropped"` - TxRetries FlexInt `json:"tx_retries"` - RxPackets FlexInt `json:"rx_packets"` - RxBytes FlexInt `json:"rx_bytes"` - UserRxDropped FlexInt `json:"user-rx_dropped"` - GuestRxDropped FlexInt `json:"guest-rx_dropped"` - UserRxErrors FlexInt `json:"user-rx_errors"` - GuestRxErrors FlexInt `json:"guest-rx_errors"` - UserRxPackets FlexInt `json:"user-rx_packets"` - GuestRxPackets FlexInt `json:"guest-rx_packets"` - UserRxBytes FlexInt `json:"user-rx_bytes"` - GuestRxBytes FlexInt `json:"guest-rx_bytes"` - UserRxCrypts FlexInt `json:"user-rx_crypts"` - GuestRxCrypts FlexInt `json:"guest-rx_crypts"` - UserRxFrags FlexInt `json:"user-rx_frags"` - GuestRxFrags FlexInt `json:"guest-rx_frags"` - UserTxPackets FlexInt `json:"user-tx_packets"` - GuestTxPackets FlexInt `json:"guest-tx_packets"` - UserTxBytes FlexInt `json:"user-tx_bytes"` - GuestTxBytes FlexInt `json:"guest-tx_bytes"` - UserTxErrors FlexInt `json:"user-tx_errors"` - GuestTxErrors FlexInt `json:"guest-tx_errors"` - UserTxDropped FlexInt `json:"user-tx_dropped"` - GuestTxDropped FlexInt `json:"guest-tx_dropped"` - UserTxRetries FlexInt `json:"user-tx_retries"` - GuestTxRetries FlexInt `json:"guest-tx_retries"` - MacFilterRejections FlexInt `json:"mac_filter_rejections"` - UserMacFilterRejections FlexInt `json:"user-mac_filter_rejections"` - GuestMacFilterRejections FlexInt `json:"guest-mac_filter_rejections"` - WifiTxAttempts FlexInt `json:"wifi_tx_attempts"` - UserWifiTxDropped FlexInt `json:"user-wifi_tx_dropped"` - GuestWifiTxDropped FlexInt `json:"guest-wifi_tx_dropped"` - UserWifiTxAttempts FlexInt `json:"user-wifi_tx_attempts"` - GuestWifiTxAttempts FlexInt `json:"guest-wifi_tx_attempts"` - - // UAP-AC-PRO names, others may differ. - /* These are all in VAP TABLE */ - /* - GuestWifi0RxPackets FlexInt `json:"guest-wifi0-rx_packets"` - GuestWifi1RxPackets FlexInt `json:"guest-wifi1-rx_packets"` - UserWifi1RxPackets FlexInt `json:"user-wifi1-rx_packets"` - UserWifi0RxPackets FlexInt `json:"user-wifi0-rx_packets"` - Wifi0RxPackets FlexInt `json:"wifi0-rx_packets"` - Wifi1RxPackets FlexInt `json:"wifi1-rx_packets"` - GuestWifi0RxBytes FlexInt `json:"guest-wifi0-rx_bytes"` - GuestWifi1RxBytes FlexInt `json:"guest-wifi1-rx_bytes"` - UserWifi1RxBytes FlexInt `json:"user-wifi1-rx_bytes"` - UserWifi0RxBytes FlexInt `json:"user-wifi0-rx_bytes"` - Wifi0RxBytes FlexInt `json:"wifi0-rx_bytes"` - Wifi1RxBytes FlexInt `json:"wifi1-rx_bytes"` - GuestWifi0RxErrors FlexInt `json:"guest-wifi0-rx_errors"` - GuestWifi1RxErrors FlexInt `json:"guest-wifi1-rx_errors"` - UserWifi1RxErrors FlexInt `json:"user-wifi1-rx_errors"` - UserWifi0RxErrors FlexInt `json:"user-wifi0-rx_errors"` - Wifi0RxErrors FlexInt `json:"wifi0-rx_errors"` - Wifi1RxErrors FlexInt `json:"wifi1-rx_errors"` - GuestWifi0RxDropped FlexInt `json:"guest-wifi0-rx_dropped"` - GuestWifi1RxDropped FlexInt `json:"guest-wifi1-rx_dropped"` - UserWifi1RxDropped FlexInt `json:"user-wifi1-rx_dropped"` - UserWifi0RxDropped FlexInt `json:"user-wifi0-rx_dropped"` - Wifi0RxDropped FlexInt `json:"wifi0-rx_dropped"` - Wifi1RxDropped FlexInt `json:"wifi1-rx_dropped"` - GuestWifi0RxCrypts FlexInt `json:"guest-wifi0-rx_crypts"` - GuestWifi1RxCrypts FlexInt `json:"guest-wifi1-rx_crypts"` - UserWifi1RxCrypts FlexInt `json:"user-wifi1-rx_crypts"` - UserWifi0RxCrypts FlexInt `json:"user-wifi0-rx_crypts"` - Wifi0RxCrypts FlexInt `json:"wifi0-rx_crypts"` - Wifi1RxCrypts FlexInt `json:"wifi1-rx_crypts"` - GuestWifi0RxFrags FlexInt `json:"guest-wifi0-rx_frags"` - GuestWifi1RxFrags FlexInt `json:"guest-wifi1-rx_frags"` - UserWifi1RxFrags FlexInt `json:"user-wifi1-rx_frags"` - UserWifi0RxFrags FlexInt `json:"user-wifi0-rx_frags"` - Wifi0RxFrags FlexInt `json:"wifi0-rx_frags"` - Wifi1RxFrags FlexInt `json:"wifi1-rx_frags"` - GuestWifi0TxPackets FlexInt `json:"guest-wifi0-tx_packets"` - GuestWifi1TxPackets FlexInt `json:"guest-wifi1-tx_packets"` - UserWifi1TxPackets FlexInt `json:"user-wifi1-tx_packets"` - UserWifi0TxPackets FlexInt `json:"user-wifi0-tx_packets"` - Wifi0TxPackets FlexInt `json:"wifi0-tx_packets"` - Wifi1TxPackets FlexInt `json:"wifi1-tx_packets"` - GuestWifi0TxBytes FlexInt `json:"guest-wifi0-tx_bytes"` - GuestWifi1TxBytes FlexInt `json:"guest-wifi1-tx_bytes"` - UserWifi1TxBytes FlexInt `json:"user-wifi1-tx_bytes"` - UserWifi0TxBytes FlexInt `json:"user-wifi0-tx_bytes"` - Wifi0TxBytes FlexInt `json:"wifi0-tx_bytes"` - Wifi1TxBytes FlexInt `json:"wifi1-tx_bytes"` - GuestWifi0TxErrors FlexInt `json:"guest-wifi0-tx_errors"` - GuestWifi1TxErrors FlexInt `json:"guest-wifi1-tx_errors"` - UserWifi1TxErrors FlexInt `json:"user-wifi1-tx_errors"` - UserWifi0TxErrors FlexInt `json:"user-wifi0-tx_errors"` - Wifi0TxErrors FlexInt `json:"wifi0-tx_errors"` - Wifi1TxErrors FlexInt `json:"wifi1-tx_errors"` - GuestWifi0TxDropped FlexInt `json:"guest-wifi0-tx_dropped"` - GuestWifi1TxDropped FlexInt `json:"guest-wifi1-tx_dropped"` - UserWifi1TxDropped FlexInt `json:"user-wifi1-tx_dropped"` - UserWifi0TxDropped FlexInt `json:"user-wifi0-tx_dropped"` - Wifi0TxDropped FlexInt `json:"wifi0-tx_dropped"` - Wifi1TxDropped FlexInt `json:"wifi1-tx_dropped"` - GuestWifi0TxRetries FlexInt `json:"guest-wifi0-tx_retries"` - GuestWifi1TxRetries FlexInt `json:"guest-wifi1-tx_retries"` - UserWifi1TxRetries FlexInt `json:"user-wifi1-tx_retries"` - UserWifi0TxRetries FlexInt `json:"user-wifi0-tx_retries"` - Wifi0TxRetries FlexInt `json:"wifi0-tx_retries"` - Wifi1TxRetries FlexInt `json:"wifi1-tx_retries"` - GuestWifi0MacFilterRejections FlexInt `json:"guest-wifi0-mac_filter_rejections"` - GuestWifi1MacFilterRejections FlexInt `json:"guest-wifi1-mac_filter_rejections"` - UserWifi1MacFilterRejections FlexInt `json:"user-wifi1-mac_filter_rejections"` - UserWifi0MacFilterRejections FlexInt `json:"user-wifi0-mac_filter_rejections"` - Wifi0MacFilterRejections FlexInt `json:"wifi0-mac_filter_rejections"` - Wifi1MacFilterRejections FlexInt `json:"wifi1-mac_filter_rejections"` - GuestWifi0WifiTxAttempts FlexInt `json:"guest-wifi0-wifi_tx_attempts"` - GuestWifi1WifiTxAttempts FlexInt `json:"guest-wifi1-wifi_tx_attempts"` - UserWifi1WifiTxAttempts FlexInt `json:"user-wifi1-wifi_tx_attempts"` - UserWifi0WifiTxAttempts FlexInt `json:"user-wifi0-wifi_tx_attempts"` - Wifi0WifiTxAttempts FlexInt `json:"wifi0-wifi_tx_attempts"` - Wifi1WifiTxAttempts FlexInt `json:"wifi1-wifi_tx_attempts"` - GuestWifi0WifiTxDropped FlexInt `json:"guest-wifi0-wifi_tx_dropped"` - GuestWifi1WifiTxDropped FlexInt `json:"guest-wifi1-wifi_tx_dropped"` - UserWifi1WifiTxDropped FlexInt `json:"user-wifi1-wifi_tx_dropped"` - UserWifi0WifiTxDropped FlexInt `json:"user-wifi0-wifi_tx_dropped"` - Wifi0WifiTxDropped FlexInt `json:"wifi0-wifi_tx_dropped"` - Wifi1WifiTxDropped FlexInt `json:"wifi1-wifi_tx_dropped"` - // UDM Names - GuestRa0RxPackets FlexInt `json:"guest-ra0-rx_packets"` - UserRa0RxPackets FlexInt `json:"user-ra0-rx_packets"` - Ra0RxPackets FlexInt `json:"ra0-rx_packets"` - GuestRa0RxBytes FlexInt `json:"guest-ra0-rx_bytes"` - UserRa0RxBytes FlexInt `json:"user-ra0-rx_bytes"` - Ra0RxBytes FlexInt `json:"ra0-rx_bytes"` - GuestRa0RxErrors FlexInt `json:"guest-ra0-rx_errors"` - UserRa0RxErrors FlexInt `json:"user-ra0-rx_errors"` - Ra0RxErrors FlexInt `json:"ra0-rx_errors"` - GuestRa0RxDropped FlexInt `json:"guest-ra0-rx_dropped"` - UserRa0RxDropped FlexInt `json:"user-ra0-rx_dropped"` - Ra0RxDropped FlexInt `json:"ra0-rx_dropped"` - GuestRa0RxCrypts FlexInt `json:"guest-ra0-rx_crypts"` - UserRa0RxCrypts FlexInt `json:"user-ra0-rx_crypts"` - Ra0RxCrypts FlexInt `json:"ra0-rx_crypts"` - GuestRa0RxFrags FlexInt `json:"guest-ra0-rx_frags"` - UserRa0RxFrags FlexInt `json:"user-ra0-rx_frags"` - Ra0RxFrags FlexInt `json:"ra0-rx_frags"` - GuestRa0TxPackets FlexInt `json:"guest-ra0-tx_packets"` - UserRa0TxPackets FlexInt `json:"user-ra0-tx_packets"` - Ra0TxPackets FlexInt `json:"ra0-tx_packets"` - GuestRa0TxBytes FlexInt `json:"guest-ra0-tx_bytes"` - UserRa0TxBytes FlexInt `json:"user-ra0-tx_bytes"` - Ra0TxBytes FlexInt `json:"ra0-tx_bytes"` - GuestRa0TxErrors FlexInt `json:"guest-ra0-tx_errors"` - UserRa0TxErrors FlexInt `json:"user-ra0-tx_errors"` - Ra0TxErrors FlexInt `json:"ra0-tx_errors"` - GuestRa0TxDropped FlexInt `json:"guest-ra0-tx_dropped"` - UserRa0TxDropped FlexInt `json:"user-ra0-tx_dropped"` - Ra0TxDropped FlexInt `json:"ra0-tx_dropped"` - GuestRa0TxRetries FlexInt `json:"guest-ra0-tx_retries"` - UserRa0TxRetries FlexInt `json:"user-ra0-tx_retries"` - Ra0TxRetries FlexInt `json:"ra0-tx_retries"` - GuestRa0MacFilterRejections FlexInt `json:"guest-ra0-mac_filter_rejections"` - UserRa0MacFilterRejections FlexInt `json:"user-ra0-mac_filter_rejections"` - Ra0MacFilterRejections FlexInt `json:"ra0-mac_filter_rejections"` - GuestRa0WifiTxAttempts FlexInt `json:"guest-ra0-wifi_tx_attempts"` - UserRa0WifiTxAttempts FlexInt `json:"user-ra0-wifi_tx_attempts"` - Ra0WifiTxAttempts FlexInt `json:"ra0-wifi_tx_attempts"` - GuestRa0WifiTxDropped FlexInt `json:"guest-ra0-wifi_tx_dropped"` - UserRa0WifiTxDropped FlexInt `json:"user-ra0-wifi_tx_dropped"` - Ra0WifiTxDropped FlexInt `json:"ra0-wifi_tx_dropped"` - GuestRai0RxPackets FlexInt `json:"guest-rai0-rx_packets"` - UserRai0RxPackets FlexInt `json:"user-rai0-rx_packets"` - Rai0RxPackets FlexInt `json:"rai0-rx_packets"` - GuestRai0RxBytes FlexInt `json:"guest-rai0-rx_bytes"` - UserRai0RxBytes FlexInt `json:"user-rai0-rx_bytes"` - Rai0RxBytes FlexInt `json:"rai0-rx_bytes"` - GuestRai0RxErrors FlexInt `json:"guest-rai0-rx_errors"` - UserRai0RxErrors FlexInt `json:"user-rai0-rx_errors"` - Rai0RxErrors FlexInt `json:"rai0-rx_errors"` - GuestRai0RxDropped FlexInt `json:"guest-rai0-rx_dropped"` - UserRai0RxDropped FlexInt `json:"user-rai0-rx_dropped"` - Rai0RxDropped FlexInt `json:"rai0-rx_dropped"` - GuestRai0RxCrypts FlexInt `json:"guest-rai0-rx_crypts"` - UserRai0RxCrypts FlexInt `json:"user-rai0-rx_crypts"` - Rai0RxCrypts FlexInt `json:"rai0-rx_crypts"` - GuestRai0RxFrags FlexInt `json:"guest-rai0-rx_frags"` - UserRai0RxFrags FlexInt `json:"user-rai0-rx_frags"` - Rai0RxFrags FlexInt `json:"rai0-rx_frags"` - GuestRai0TxPackets FlexInt `json:"guest-rai0-tx_packets"` - UserRai0TxPackets FlexInt `json:"user-rai0-tx_packets"` - Rai0TxPackets FlexInt `json:"rai0-tx_packets"` - GuestRai0TxBytes FlexInt `json:"guest-rai0-tx_bytes"` - UserRai0TxBytes FlexInt `json:"user-rai0-tx_bytes"` - Rai0TxBytes FlexInt `json:"rai0-tx_bytes"` - GuestRai0TxErrors FlexInt `json:"guest-rai0-tx_errors"` - UserRai0TxErrors FlexInt `json:"user-rai0-tx_errors"` - Rai0TxErrors FlexInt `json:"rai0-tx_errors"` - GuestRai0TxDropped FlexInt `json:"guest-rai0-tx_dropped"` - UserRai0TxDropped FlexInt `json:"user-rai0-tx_dropped"` - Rai0TxDropped FlexInt `json:"rai0-tx_dropped"` - GuestRai0TxRetries FlexInt `json:"guest-rai0-tx_retries"` - UserRai0TxRetries FlexInt `json:"user-rai0-tx_retries"` - Rai0TxRetries FlexInt `json:"rai0-tx_retries"` - GuestRai0MacFilterRejections FlexInt `json:"guest-rai0-mac_filter_rejections"` - UserRai0MacFilterRejections FlexInt `json:"user-rai0-mac_filter_rejections"` - Rai0MacFilterRejections FlexInt `json:"rai0-mac_filter_rejections"` - GuestRai0WifiTxAttempts FlexInt `json:"guest-rai0-wifi_tx_attempts"` - UserRai0WifiTxAttempts FlexInt `json:"user-rai0-wifi_tx_attempts"` - Rai0WifiTxAttempts FlexInt `json:"rai0-wifi_tx_attempts"` - GuestRai0WifiTxDropped FlexInt `json:"guest-rai0-wifi_tx_dropped"` - UserRai0WifiTxDropped FlexInt `json:"user-rai0-wifi_tx_dropped"` - Rai0WifiTxDropped FlexInt `json:"rai0-wifi_tx_dropped"` - */ -} - -// RadioTable is part of the data for UAPs and UDMs. -type RadioTable []struct { - AntennaGain FlexInt `json:"antenna_gain"` - BuiltinAntGain FlexInt `json:"builtin_ant_gain"` - BuiltinAntenna FlexBool `json:"builtin_antenna"` - Channel FlexInt `json:"channel"` - CurrentAntennaGain FlexInt `json:"current_antenna_gain"` - HasDfs FlexBool `json:"has_dfs"` - HasFccdfs FlexBool `json:"has_fccdfs"` - HasHt160 FlexBool `json:"has_ht160"` - Ht FlexInt `json:"ht"` - Is11Ac FlexBool `json:"is_11ac"` - MaxTxpower FlexInt `json:"max_txpower"` - MinRssi FlexInt `json:"min_rssi,omitempty"` - MinRssiEnabled FlexBool `json:"min_rssi_enabled"` - MinTxpower FlexInt `json:"min_txpower"` - Name string `json:"name"` - Nss FlexInt `json:"nss"` - Radio string `json:"radio"` - RadioCaps FlexInt `json:"radio_caps"` - SensLevelEnabled FlexBool `json:"sens_level_enabled"` - TxPower FlexInt `json:"tx_power"` - TxPowerMode string `json:"tx_power_mode"` - VwireEnabled FlexBool `json:"vwire_enabled"` - WlangroupID string `json:"wlangroup_id"` -} - -// RadioTableStats is part of the data shared between UAP and UDM -type RadioTableStats []struct { - Name string `json:"name"` - Channel FlexInt `json:"channel"` - Radio string `json:"radio"` - AstTxto interface{} `json:"ast_txto"` - AstCst interface{} `json:"ast_cst"` - AstBeXmit FlexInt `json:"ast_be_xmit"` - CuTotal FlexInt `json:"cu_total"` - CuSelfRx FlexInt `json:"cu_self_rx"` - CuSelfTx FlexInt `json:"cu_self_tx"` - Gain FlexInt `json:"gain"` - Satisfaction FlexInt `json:"satisfaction"` - State string `json:"state"` - Extchannel FlexInt `json:"extchannel"` - TxPower FlexInt `json:"tx_power"` - TxPackets FlexInt `json:"tx_packets"` - TxRetries FlexInt `json:"tx_retries"` - NumSta FlexInt `json:"num_sta"` - GuestNumSta FlexInt `json:"guest-num_sta"` - UserNumSta FlexInt `json:"user-num_sta"` -} - -// VapTable holds much of the UAP wireless data. Shared by UDM. -type VapTable []struct { - AnomaliesBarChart struct { - HighDNSLatency FlexInt `json:"high_dns_latency"` - HighTCPLatency FlexInt `json:"high_tcp_latency"` - HighTCPPacketLoss FlexInt `json:"high_tcp_packet_loss"` - HighWifiLatency FlexInt `json:"high_wifi_latency"` - HighWifiRetries FlexInt `json:"high_wifi_retries"` - LowPhyRate FlexInt `json:"low_phy_rate"` - PoorStreamEff FlexInt `json:"poor_stream_eff"` - SleepyClient FlexInt `json:"sleepy_client"` - StaArpTimeout FlexInt `json:"sta_arp_timeout"` - StaDNSTimeout FlexInt `json:"sta_dns_timeout"` - StaIPTimeout FlexInt `json:"sta_ip_timeout"` - WeakSignal FlexInt `json:"weak_signal"` - } `json:"anomalies_bar_chart"` - AnomaliesBarChartNow struct { - HighDNSLatency FlexInt `json:"high_dns_latency"` - HighTCPLatency FlexInt `json:"high_tcp_latency"` - HighTCPPacketLoss FlexInt `json:"high_tcp_packet_loss"` - HighWifiLatency FlexInt `json:"high_wifi_latency"` - HighWifiRetries FlexInt `json:"high_wifi_retries"` - LowPhyRate FlexInt `json:"low_phy_rate"` - PoorStreamEff FlexInt `json:"poor_stream_eff"` - SleepyClient FlexInt `json:"sleepy_client"` - StaArpTimeout FlexInt `json:"sta_arp_timeout"` - StaDNSTimeout FlexInt `json:"sta_dns_timeout"` - StaIPTimeout FlexInt `json:"sta_ip_timeout"` - WeakSignal FlexInt `json:"weak_signal"` - } `json:"anomalies_bar_chart_now"` - ReasonsBarChart struct { - PhyRate FlexInt `json:"phy_rate"` - Signal FlexInt `json:"signal"` - SleepyClient FlexInt `json:"sleepy_client"` - StaArpTimeout FlexInt `json:"sta_arp_timeout"` - StaDNSLatency FlexInt `json:"sta_dns_latency"` - StaDNSTimeout FlexInt `json:"sta_dns_timeout"` - StaIPTimeout FlexInt `json:"sta_ip_timeout"` - StreamEff FlexInt `json:"stream_eff"` - TCPLatency FlexInt `json:"tcp_latency"` - TCPPacketLoss FlexInt `json:"tcp_packet_loss"` - WifiLatency FlexInt `json:"wifi_latency"` - WifiRetries FlexInt `json:"wifi_retries"` - } `json:"reasons_bar_chart"` - ReasonsBarChartNow struct { - PhyRate FlexInt `json:"phy_rate"` - Signal FlexInt `json:"signal"` - SleepyClient FlexInt `json:"sleepy_client"` - StaArpTimeout FlexInt `json:"sta_arp_timeout"` - StaDNSLatency FlexInt `json:"sta_dns_latency"` - StaDNSTimeout FlexInt `json:"sta_dns_timeout"` - StaIPTimeout FlexInt `json:"sta_ip_timeout"` - StreamEff FlexInt `json:"stream_eff"` - TCPLatency FlexInt `json:"tcp_latency"` - TCPPacketLoss FlexInt `json:"tcp_packet_loss"` - WifiLatency FlexInt `json:"wifi_latency"` - WifiRetries FlexInt `json:"wifi_retries"` - } `json:"reasons_bar_chart_now"` - RxTCPStats struct { - Goodbytes FlexInt `json:"goodbytes"` - LatAvg FlexInt `json:"lat_avg"` - LatMax FlexInt `json:"lat_max"` - LatMin FlexInt `json:"lat_min"` - Stalls FlexInt `json:"stalls"` - } `json:"rx_tcp_stats"` - TxTCPStats struct { - Goodbytes FlexInt `json:"goodbytes"` - LatAvg FlexInt `json:"lat_avg"` - LatMax FlexInt `json:"lat_max"` - LatMin FlexInt `json:"lat_min"` - Stalls FlexInt `json:"stalls"` - } `json:"tx_tcp_stats"` - WifiTxLatencyMov struct { - Avg FlexInt `json:"avg"` - Max FlexInt `json:"max"` - Min FlexInt `json:"min"` - Total FlexInt `json:"total"` - TotalCount FlexInt `json:"total_count"` - } `json:"wifi_tx_latency_mov"` - ApMac string `json:"ap_mac"` - AvgClientSignal FlexInt `json:"avg_client_signal"` - Bssid string `json:"bssid"` - Ccq int `json:"ccq"` - Channel FlexInt `json:"channel"` - DNSAvgLatency FlexInt `json:"dns_avg_latency"` - Essid string `json:"essid"` - Extchannel int `json:"extchannel"` - ID string `json:"id"` - IsGuest FlexBool `json:"is_guest"` - IsWep FlexBool `json:"is_wep"` - MacFilterRejections int `json:"mac_filter_rejections"` - MapID interface{} `json:"map_id"` - Name string `json:"name"` - NumSatisfactionSta FlexInt `json:"num_satisfaction_sta"` - NumSta int `json:"num_sta"` - Radio string `json:"radio"` - RadioName string `json:"radio_name"` - RxBytes FlexInt `json:"rx_bytes"` - RxCrypts FlexInt `json:"rx_crypts"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxFrags FlexInt `json:"rx_frags"` - RxNwids FlexInt `json:"rx_nwids"` - RxPackets FlexInt `json:"rx_packets"` - Satisfaction FlexInt `json:"satisfaction"` - SatisfactionNow FlexInt `json:"satisfaction_now"` - SiteID string `json:"site_id"` - State string `json:"state"` - T string `json:"t"` - TxBytes FlexInt `json:"tx_bytes"` - TxCombinedRetries FlexInt `json:"tx_combined_retries"` - TxDataMpduBytes FlexInt `json:"tx_data_mpdu_bytes"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxPackets FlexInt `json:"tx_packets"` - TxPower FlexInt `json:"tx_power"` - TxRetries FlexInt `json:"tx_retries"` - TxRtsRetries FlexInt `json:"tx_rts_retries"` - TxSuccess FlexInt `json:"tx_success"` - TxTotal FlexInt `json:"tx_total"` - Up FlexBool `json:"up"` - Usage string `json:"usage"` - WifiTxAttempts FlexInt `json:"wifi_tx_attempts"` - WifiTxDropped FlexInt `json:"wifi_tx_dropped"` - WlanconfID string `json:"wlanconf_id"` -} - -// UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Access Point Stat data. -func (v *UAPStat) UnmarshalJSON(data []byte) error { - var n struct { - Ap `json:"ap"` - } - - v.Ap = &n.Ap - - err := json.Unmarshal(data, v.Ap) // controller version 5.10. - if err != nil { - return json.Unmarshal(data, &n) // controller version 5.11. - } - - return nil -} diff --git a/core/unifi/v4/uap_test.go b/core/unifi/v4/uap_test.go deleted file mode 100644 index 155b3539..00000000 --- a/core/unifi/v4/uap_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package unifi - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestUAPUnmarshalJSON(t *testing.T) { - testcontroller511 := `{ - "ap": { - "site_id": "mySite", - "o": "ap", - "oid": "00:00:00:00:00:00", - "ap": "00:00:00:00:00:00", - "time": 1577742600000, - "datetime": "2019-12-30T09:50:00Z", - "user-wifi1-rx_packets": 6596670, - "user-wifi0-rx_packets": 42659527, - "user-rx_packets": 49294197, - "guest-rx_packets": 0, - "wifi0-rx_packets": 42639527, - "wifi1-rx_packets": 6591670, - "rx_packets": 49299197}}` - - testcontroller510 := `{ - "site_id": "mySite", - "o": "ap", - "oid": "00:00:00:00:00:00", - "ap": "00:00:00:00:00:00", - "time": 1577742600000, - "datetime": "2019-12-30T09:50:00Z", - "user-wifi1-rx_packets": 6596670, - "user-wifi0-rx_packets": 42659527, - "user-rx_packets": 49294197, - "guest-rx_packets": 0, - "wifi0-rx_packets": 42639527, - "wifi1-rx_packets": 6591670, - "rx_packets": 49299197}` - - t.Parallel() - a := assert.New(t) - rxPakcets := 49299197 - u := &UAPStat{} - err := u.UnmarshalJSON([]byte(testcontroller510)) - a.Nil(err, "must be no error unmarshaling test strings") - a.Equal(float64(rxPakcets), u.RxPackets.Val, "data was not properly unmarshaled") - - u = &UAPStat{} // reset - err = u.UnmarshalJSON([]byte(testcontroller511)) - a.Nil(err, "must be no error unmarshaling test strings") - a.Equal(float64(rxPakcets), u.RxPackets.Val, "data was not properly unmarshaled") -} diff --git a/core/unifi/v4/udm.go b/core/unifi/v4/udm.go deleted file mode 100644 index 16842809..00000000 --- a/core/unifi/v4/udm.go +++ /dev/null @@ -1,183 +0,0 @@ -package unifi - -// UDM represents all the data from the Ubiquiti Controller for a Unifi Dream Machine. -// The UDM shares several structs/type-data with USW and USG. -type UDM struct { - SourceName string `json:"-"` - SiteID string `json:"site_id"` - SiteName string `json:"-"` - Mac string `json:"mac"` - Adopted FlexBool `json:"adopted"` - Serial string `json:"serial"` - IP string `json:"ip"` - Uptime FlexInt `json:"uptime"` - Model string `json:"model"` - Version string `json:"version"` - Name string `json:"name"` - Default FlexBool `json:"default"` - Locating FlexBool `json:"locating"` - Type string `json:"type"` - Unsupported FlexBool `json:"unsupported"` - UnsupportedReason FlexInt `json:"unsupported_reason"` - DiscoveredVia string `json:"discovered_via"` - AdoptIP string `json:"adopt_ip"` - AdoptURL string `json:"adopt_url"` - State FlexInt `json:"state"` - AdoptStatus FlexInt `json:"adopt_status"` - UpgradeState FlexInt `json:"upgrade_state"` - LastSeen FlexInt `json:"last_seen"` - AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` - Cfgversion string `json:"cfgversion"` - ConfigNetwork struct { - Type string `json:"type"` - IP string `json:"ip"` - } `json:"config_network"` - VwireTable []interface{} `json:"vwire_table"` - Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"` - JumboframeEnabled FlexBool `json:"jumboframe_enabled"` - FlowctrlEnabled FlexBool `json:"flowctrl_enabled"` - StpVersion string `json:"stp_version"` - StpPriority FlexInt `json:"stp_priority"` - PowerSourceCtrlEnabled FlexBool `json:"power_source_ctrl_enabled"` - LicenseState string `json:"license_state"` - ID string `json:"_id"` - DeviceID string `json:"device_id"` - AdoptState FlexInt `json:"adopt_state"` - AdoptTries FlexInt `json:"adopt_tries"` - AdoptManual FlexBool `json:"adopt_manual"` - InformURL string `json:"inform_url"` - InformIP string `json:"inform_ip"` - RequiredVersion string `json:"required_version"` - BoardRev FlexInt `json:"board_rev"` - EthernetTable []struct { - Mac string `json:"mac"` - NumPort FlexInt `json:"num_port"` - Name string `json:"name"` - } `json:"ethernet_table"` - PortTable []Port `json:"port_table"` - EthernetOverrides []struct { - Ifname string `json:"ifname"` - Networkgroup string `json:"networkgroup"` - } `json:"ethernet_overrides"` - UsgCaps FlexInt `json:"usg_caps"` - HasSpeaker FlexBool `json:"has_speaker"` - HasEth1 FlexBool `json:"has_eth1"` - FwCaps FlexInt `json:"fw_caps"` - HwCaps FlexInt `json:"hw_caps"` - WifiCaps FlexInt `json:"wifi_caps"` - SwitchCaps struct { - MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` - MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` - } `json:"switch_caps"` - HasFan FlexBool `json:"has_fan"` - HasTemperature FlexBool `json:"has_temperature"` - RulesetInterfaces interface{} `json:"ruleset_interfaces"` - /* struct { - Br0 string `json:"br0"` - Eth0 string `json:"eth0"` - Eth1 string `json:"eth1"` - Eth2 string `json:"eth2"` - Eth3 string `json:"eth3"` - Eth4 string `json:"eth4"` - Eth5 string `json:"eth5"` - Eth6 string `json:"eth6"` - Eth7 string `json:"eth7"` - Eth8 string `json:"eth8"` - } */ - KnownCfgversion string `json:"known_cfgversion"` - SysStats SysStats `json:"sys_stats"` - SystemStats SystemStats `json:"system-stats"` - GuestToken string `json:"guest_token"` - Overheating FlexBool `json:"overheating"` - SpeedtestStatus SpeedtestStatus `json:"speedtest-status"` - SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"` - Wan1 Wan `json:"wan1"` - Wan2 Wan `json:"wan2"` - Uplink Uplink `json:"uplink"` - ConnectRequestIP string `json:"connect_request_ip"` - ConnectRequestPort string `json:"connect_request_port"` - DownlinkTable []interface{} `json:"downlink_table"` - WlangroupIDNa string `json:"wlangroup_id_na"` - WlangroupIDNg string `json:"wlangroup_id_ng"` - BandsteeringMode string `json:"bandsteering_mode"` - RadioTable *RadioTable `json:"radio_table,omitempty"` - RadioTableStats *RadioTableStats `json:"radio_table_stats,omitempty"` - VapTable *VapTable `json:"vap_table"` - XInformAuthkey string `json:"x_inform_authkey"` - NetworkTable NetworkTable `json:"network_table"` - PortOverrides []struct { - PortIdx FlexInt `json:"port_idx"` - PortconfID string `json:"portconf_id"` - } `json:"port_overrides"` - Stat UDMStat `json:"stat"` - TxBytes FlexInt `json:"tx_bytes"` - RxBytes FlexInt `json:"rx_bytes"` - Bytes FlexInt `json:"bytes"` - BytesD FlexInt `json:"bytes-d"` - TxBytesD FlexInt `json:"tx_bytes-d"` - RxBytesD FlexInt `json:"rx_bytes-d"` - BytesR FlexInt `json:"bytes-r"` - NumSta FlexInt `json:"num_sta"` // USG - WlanNumSta FlexInt `json:"wlan-num_sta"` // UAP - LanNumSta FlexInt `json:"lan-num_sta"` // USW - UserWlanNumSta FlexInt `json:"user-wlan-num_sta"` // UAP - UserLanNumSta FlexInt `json:"user-lan-num_sta"` // USW - UserNumSta FlexInt `json:"user-num_sta"` // USG - GuestWlanNumSta FlexInt `json:"guest-wlan-num_sta"` // UAP - GuestLanNumSta FlexInt `json:"guest-lan-num_sta"` // USW - GuestNumSta FlexInt `json:"guest-num_sta"` // USG - NumDesktop FlexInt `json:"num_desktop"` // USG - NumMobile FlexInt `json:"num_mobile"` // USG - NumHandheld FlexInt `json:"num_handheld"` // USG -} - -// NetworkTable is the list of networks on a gateway. -type NetworkTable []struct { - ID string `json:"_id"` - AttrNoDelete FlexBool `json:"attr_no_delete"` - AttrHiddenID string `json:"attr_hidden_id"` - Name string `json:"name"` - SiteID string `json:"site_id"` - VlanEnabled FlexBool `json:"vlan_enabled"` - Purpose string `json:"purpose"` - IPSubnet string `json:"ip_subnet"` - Ipv6InterfaceType string `json:"ipv6_interface_type"` - DomainName string `json:"domain_name"` - IsNat FlexBool `json:"is_nat"` - DhcpdEnabled FlexBool `json:"dhcpd_enabled"` - DhcpdStart string `json:"dhcpd_start"` - DhcpdStop string `json:"dhcpd_stop"` - Dhcpdv6Enabled FlexBool `json:"dhcpdv6_enabled"` - Ipv6RaEnabled FlexBool `json:"ipv6_ra_enabled"` - LteLanEnabled FlexBool `json:"lte_lan_enabled"` - Networkgroup string `json:"networkgroup"` - DhcpdLeasetime FlexInt `json:"dhcpd_leasetime"` - DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"` - DhcpdGatewayEnabled FlexBool `json:"dhcpd_gateway_enabled"` - DhcpdTimeOffsetEnabled FlexBool `json:"dhcpd_time_offset_enabled"` - Ipv6PdStart string `json:"ipv6_pd_start"` - Ipv6PdStop string `json:"ipv6_pd_stop"` - DhcpdDNS1 string `json:"dhcpd_dns_1"` - DhcpdDNS2 string `json:"dhcpd_dns_2"` - DhcpdDNS3 string `json:"dhcpd_dns_3"` - DhcpdDNS4 string `json:"dhcpd_dns_4"` - Enabled FlexBool `json:"enabled"` - DhcpRelayEnabled FlexBool `json:"dhcp_relay_enabled"` - Mac string `json:"mac"` - IsGuest FlexBool `json:"is_guest"` - IP string `json:"ip"` - Up FlexBool `json:"up"` - NumSta FlexInt `json:"num_sta"` - RxBytes FlexInt `json:"rx_bytes"` - RxPackets FlexInt `json:"rx_packets"` - TxBytes FlexInt `json:"tx_bytes"` - TxPackets FlexInt `json:"tx_packets"` -} - -// UDMStat holds the "stat" data for a dream machine. -// A dream machine is a USG + USW + Controller -type UDMStat struct { - *Gw `json:"gw"` - *Sw `json:"sw"` - *Ap `json:"ap,omitempty"` -} diff --git a/core/unifi/v4/unifi.go b/core/unifi/v4/unifi.go deleted file mode 100644 index 2b3ba865..00000000 --- a/core/unifi/v4/unifi.go +++ /dev/null @@ -1,160 +0,0 @@ -// Package unifi provides a set of types to unload (unmarshal) Ubiquiti UniFi -// controller data. Also provided are methods to easily get data for devices - -// things like access points and switches, and for clients - the things -// connected to those access points and switches. As a bonus, each device and -// client type provided has an attached method to create InfluxDB datapoints. -package unifi - -import ( - "bytes" - "crypto/tls" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/http/cookiejar" - "strings" - "time" -) - -// NewUnifi creates a http.Client with authenticated cookies. -// Used to make additional, authenticated requests to the APIs. -// Start here. -func NewUnifi(config *Config) (*Unifi, error) { - jar, err := cookiejar.New(nil) - if err != nil { - return nil, err - } - - config.URL = strings.TrimRight(config.URL, "/") - - if config.ErrorLog == nil { - config.ErrorLog = discardLogs - } - - if config.DebugLog == nil { - config.DebugLog = discardLogs - } - - u := &Unifi{Config: config, - Client: &http.Client{ - Jar: jar, - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: !config.VerifySSL}, - }, - }, - } - if err := u.Login(); err != nil { - return u, err - } - - if err := u.GetServerData(); err != nil { - return u, fmt.Errorf("unable to get server version: %v", err) - } - - return u, nil -} - -// Login is a helper method. It can be called to grab a new authentication cookie. -func (u *Unifi) Login() error { - start := time.Now() - - // magic login. - req, err := u.UniReq(APILoginPath, fmt.Sprintf(`{"username":"%s","password":"%s"}`, u.User, u.Pass)) - if err != nil { - return err - } - - resp, err := u.Do(req) - if err != nil { - return err - } - - defer resp.Body.Close() // we need no data here. - _, _ = io.Copy(ioutil.Discard, resp.Body) // avoid leaking. - u.DebugLog("Requested %s: elapsed %v, returned %d bytes", - APILoginPath, time.Since(start).Round(time.Millisecond), resp.ContentLength) - - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("authentication failed (user: %s): %s (status: %s)", - u.User, u.URL+APILoginPath, resp.Status) - } - - return nil -} - -// GetServerData sets the controller's version and UUID. Only call this if you -// previously called Login and suspect the controller version has changed. -func (u *Unifi) GetServerData() error { - var response struct { - Data server `json:"meta"` - } - - u.server = &response.Data - - return u.GetData(APIStatusPath, &response) -} - -// GetData makes a unifi request and unmarshals the response into a provided pointer. -func (u *Unifi) GetData(apiPath string, v interface{}, params ...string) error { - start := time.Now() - - body, err := u.GetJSON(apiPath, params...) - if err != nil { - return err - } - - u.DebugLog("Requested %s: elapsed %v, returned %d bytes", - apiPath, time.Since(start).Round(time.Millisecond), len(body)) - - return json.Unmarshal(body, v) -} - -// UniReq is a small helper function that adds an Accept header. -// Use this if you're unmarshalling UniFi data into custom types. -// And if you're doing that... sumbut a pull request with your new struct. :) -// This is a helper method that is exposed for convenience. -func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err error) { - switch params { - case "": - req, err = http.NewRequest("GET", u.URL+apiPath, nil) - default: - req, err = http.NewRequest("POST", u.URL+apiPath, bytes.NewBufferString(params)) - } - - if err != nil { - return - } - - req.Header.Add("Accept", "application/json") - u.DebugLog("Requesting %s, with params: %v", apiPath, params != "") - - return -} - -// GetJSON returns the raw JSON from a path. This is useful for debugging. -func (u *Unifi) GetJSON(apiPath string, params ...string) ([]byte, error) { - req, err := u.UniReq(apiPath, strings.Join(params, " ")) - if err != nil { - return []byte{}, err - } - - resp, err := u.Do(req) - if err != nil { - return []byte{}, err - } - - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return body, err - } - - if resp.StatusCode != http.StatusOK { - err = fmt.Errorf("invalid status code from server %s", resp.Status) - } - - return body, err -} diff --git a/core/unifi/v4/unifi_test.go b/core/unifi/v4/unifi_test.go deleted file mode 100644 index 9c9015fb..00000000 --- a/core/unifi/v4/unifi_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package unifi - -import ( - "io/ioutil" - "net/http" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestNewUnifi(t *testing.T) { - t.Parallel() - a := assert.New(t) - u := "http://127.0.0.1:64431" - c := &Config{ - User: "user1", - Pass: "pass2", - URL: u, - VerifySSL: false, - DebugLog: discardLogs, - } - authReq, err := NewUnifi(c) - a.NotNil(err) - a.EqualValues(u, authReq.URL) - a.Contains(err.Error(), "connection refused", "an invalid destination should produce a connection error.") -} - -func TestUniReq(t *testing.T) { - t.Parallel() - a := assert.New(t) - p := "/test/path" - u := "http://some.url:8443" - // Test empty parameters. - authReq := &Unifi{Client: &http.Client{}, Config: &Config{URL: u, DebugLog: discardLogs}} - r, err := authReq.UniReq(p, "") - a.Nil(err, "newrequest must not produce an error") - a.EqualValues(p, r.URL.Path, - "the provided apiPath was not added to http request") - a.EqualValues(u, r.URL.Scheme+"://"+r.URL.Host, "URL improperly encoded") - a.EqualValues("GET", r.Method, "without parameters the method must be GET") - a.EqualValues("application/json", r.Header.Get("Accept"), "Accept header must be set to application/json") - - // Test with parameters - k := "key1=value9&key2=value7" - authReq = &Unifi{Client: &http.Client{}, Config: &Config{URL: "http://some.url:8443", DebugLog: discardLogs}} - r, err = authReq.UniReq(p, k) - a.Nil(err, "newrequest must not produce an error") - a.EqualValues(p, r.URL.Path, - "the provided apiPath was not added to http request") - a.EqualValues(u, r.URL.Scheme+"://"+r.URL.Host, "URL improperly encoded") - a.EqualValues("POST", r.Method, "with parameters the method must be POST") - a.EqualValues("application/json", r.Header.Get("Accept"), "Accept header must be set to application/json") - // Check the parameters. - d, err := ioutil.ReadAll(r.Body) - a.Nil(err, "problem reading request body, POST parameters may be malformed") - a.EqualValues(k, string(d), "POST parameters improperly encoded") -} - -/* NOT DONE: OPEN web server, check parameters posted, more. This test is incomplete. -a.EqualValues(`{"username": "user1","password": "pass2"}`, string(post_params), - "user/pass json parameters improperly encoded") -*/ diff --git a/core/unifi/v4/usg.go b/core/unifi/v4/usg.go deleted file mode 100644 index d7aff5a1..00000000 --- a/core/unifi/v4/usg.go +++ /dev/null @@ -1,252 +0,0 @@ -package unifi - -import ( - "encoding/json" - "time" -) - -// USG represents all the data from the Ubiquiti Controller for a Unifi Security Gateway. -type USG struct { - SourceName string `json:"-"` - ID string `json:"_id"` - Adopted FlexBool `json:"adopted"` - Cfgversion string `json:"cfgversion"` - ConfigNetwork struct { - Type string `json:"type"` - IP string `json:"ip"` - } `json:"config_network"` - EthernetTable []struct { - Mac string `json:"mac"` - NumPort FlexInt `json:"num_port"` - Name string `json:"name"` - } `json:"ethernet_table"` - FwCaps FlexInt `json:"fw_caps"` - InformIP string `json:"inform_ip"` - InformURL string `json:"inform_url"` - IP string `json:"ip"` - LedOverride string `json:"led_override"` - LicenseState string `json:"license_state"` - Mac string `json:"mac"` - Model string `json:"model"` - Name string `json:"name"` - OutdoorModeOverride string `json:"outdoor_mode_override"` - Serial string `json:"serial"` - SiteID string `json:"site_id"` - SiteName string `json:"-"` - Type string `json:"type"` - UsgCaps FlexInt `json:"usg_caps"` - Version string `json:"version"` - RequiredVersion string `json:"required_version"` - EthernetOverrides []struct { - Ifname string `json:"ifname"` - Networkgroup string `json:"networkgroup"` - } `json:"ethernet_overrides"` - HwCaps FlexInt `json:"hw_caps"` - BoardRev FlexInt `json:"board_rev"` - Unsupported FlexBool `json:"unsupported"` - UnsupportedReason FlexInt `json:"unsupported_reason"` - DeviceID string `json:"device_id"` - State FlexInt `json:"state"` - LastSeen FlexInt `json:"last_seen"` - Upgradable FlexBool `json:"upgradable"` - AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` - Rollupgrade FlexBool `json:"rollupgrade"` - KnownCfgversion string `json:"known_cfgversion"` - Uptime FlexInt `json:"uptime"` - Locating FlexBool `json:"locating"` - ConnectRequestIP string `json:"connect_request_ip"` - ConnectRequestPort string `json:"connect_request_port"` - SysStats SysStats `json:"sys_stats"` - SystemStats SystemStats `json:"system-stats"` - GuestToken string `json:"guest_token"` - SpeedtestStatus SpeedtestStatus `json:"speedtest-status"` - SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"` - Wan1 Wan `json:"wan1"` - Wan2 Wan `json:"wan2"` - PortTable []struct { - Name string `json:"name"` - Ifname string `json:"ifname"` - IP string `json:"ip"` - Netmask string `json:"netmask"` - Mac string `json:"mac"` - Up FlexBool `json:"up"` - Speed FlexInt `json:"speed"` - FullDuplex FlexBool `json:"full_duplex"` - RxBytes FlexInt `json:"rx_bytes"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxPackets FlexInt `json:"rx_packets"` - TxBytes FlexInt `json:"tx_bytes"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxPackets FlexInt `json:"tx_packets"` - RxMulticast FlexInt `json:"rx_multicast"` - Enable FlexBool `json:"enable"` - DNS []string `json:"dns,omitempty"` - Gateway string `json:"gateway,omitempty"` - } `json:"port_table"` - NetworkTable NetworkTable `json:"network_table"` - Uplink Uplink `json:"uplink"` - Stat USGStat `json:"stat"` - TxBytes FlexInt `json:"tx_bytes"` - RxBytes FlexInt `json:"rx_bytes"` - Bytes FlexInt `json:"bytes"` - NumSta FlexInt `json:"num_sta"` - UserNumSta FlexInt `json:"user-num_sta"` - GuestNumSta FlexInt `json:"guest-num_sta"` - NumDesktop FlexInt `json:"num_desktop"` - NumMobile FlexInt `json:"num_mobile"` - NumHandheld FlexInt `json:"num_handheld"` -} - -// Uplink is the Internet connection (or uplink) on a UniFi device. -type Uplink struct { - BytesR FlexInt `json:"bytes-r"` - Drops FlexInt `json:"drops"` - Enable FlexBool `json:"enable,omitempty"` - FullDuplex FlexBool `json:"full_duplex"` - Gateways []string `json:"gateways,omitempty"` - IP string `json:"ip"` - Latency FlexInt `json:"latency"` - Mac string `json:"mac,omitempty"` - MaxSpeed FlexInt `json:"max_speed"` - Name string `json:"name"` - Nameservers []string `json:"nameservers"` - Netmask string `json:"netmask"` - NumPort FlexInt `json:"num_port"` - RxBytes FlexInt `json:"rx_bytes"` - RxBytesR FlexInt `json:"rx_bytes-r"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxMulticast FlexInt `json:"rx_multicast"` - RxPackets FlexInt `json:"rx_packets"` - Speed FlexInt `json:"speed"` - SpeedtestLastrun FlexInt `json:"speedtest_lastrun,omitempty"` - SpeedtestPing FlexInt `json:"speedtest_ping,omitempty"` - SpeedtestStatus string `json:"speedtest_status,omitempty"` - TxBytes FlexInt `json:"tx_bytes"` - TxBytesR FlexInt `json:"tx_bytes-r"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxPackets FlexInt `json:"tx_packets"` - Type string `json:"type"` - Up FlexBool `json:"up"` - Uptime FlexInt `json:"uptime"` - XputDown FlexInt `json:"xput_down,omitempty"` - XputUp FlexInt `json:"xput_up,omitempty"` -} - -// Wan is a Wan interface on a USG or UDM. -type Wan struct { - Autoneg FlexBool `json:"autoneg"` - BytesR FlexInt `json:"bytes-r"` - DNS []string `json:"dns"` - Enable FlexBool `json:"enable"` - FlowctrlRx FlexBool `json:"flowctrl_rx"` - FlowctrlTx FlexBool `json:"flowctrl_tx"` - FullDuplex FlexBool `json:"full_duplex"` - Gateway string `json:"gateway"` // may be deprecated - IP string `json:"ip"` - Ifname string `json:"ifname"` - IsUplink FlexBool `json:"is_uplink"` - Mac string `json:"mac"` - MaxSpeed FlexInt `json:"max_speed"` - Media string `json:"media"` - Name string `json:"name"` - Netmask string `json:"netmask"` // may be deprecated - NumPort int `json:"num_port"` - PortIdx int `json:"port_idx"` - PortPoe FlexBool `json:"port_poe"` - RxBroadcast FlexInt `json:"rx_broadcast"` - RxBytes FlexInt `json:"rx_bytes"` - RxBytesR FlexInt `json:"rx_bytes-r"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxMulticast FlexInt `json:"rx_multicast"` - RxPackets FlexInt `json:"rx_packets"` - Speed FlexInt `json:"speed"` - TxBroadcast FlexInt `json:"tx_broadcast"` - TxBytes FlexInt `json:"tx_bytes"` - TxBytesR FlexInt `json:"tx_bytes-r"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxMulticast FlexInt `json:"tx_multicast"` - TxPackets FlexInt `json:"tx_packets"` - Type string `json:"type"` - Up FlexBool `json:"up"` -} - -// SpeedtestStatus is the speed test info on a USG or UDM. -type SpeedtestStatus struct { - Latency FlexInt `json:"latency"` - Rundate FlexInt `json:"rundate"` - Runtime FlexInt `json:"runtime"` - ServerDesc string `json:"server_desc,omitempty"` - StatusDownload FlexInt `json:"status_download"` - StatusPing FlexInt `json:"status_ping"` - StatusSummary FlexInt `json:"status_summary"` - StatusUpload FlexInt `json:"status_upload"` - XputDownload FlexInt `json:"xput_download"` - XputUpload FlexInt `json:"xput_upload"` -} - -// SystemStats is system info for a UDM, USG, USW. -type SystemStats struct { - CPU FlexInt `json:"cpu"` - Mem FlexInt `json:"mem"` - Uptime FlexInt `json:"uptime"` -} - -// SysStats is load info for a UDM, USG, USW. -type SysStats struct { - Loadavg1 FlexInt `json:"loadavg_1"` - Loadavg15 FlexInt `json:"loadavg_15"` - Loadavg5 FlexInt `json:"loadavg_5"` - MemBuffer FlexInt `json:"mem_buffer"` - MemTotal FlexInt `json:"mem_total"` - MemUsed FlexInt `json:"mem_used"` -} - -// USGStat holds the "stat" data for a gateway. -// This is split out because of a JSON data format change from 5.10 to 5.11. -type USGStat struct { - *Gw -} - -// Gw is a subtype of USGStat to make unmarshalling of different controller versions possible. -type Gw struct { - SiteID string `json:"site_id"` - O string `json:"o"` - Oid string `json:"oid"` - Gw string `json:"gw"` - Time FlexInt `json:"time"` - Datetime time.Time `json:"datetime"` - Duration FlexInt `json:"duration"` - WanRxPackets FlexInt `json:"wan-rx_packets"` - WanRxBytes FlexInt `json:"wan-rx_bytes"` - WanRxDropped FlexInt `json:"wan-rx_dropped"` - WanTxPackets FlexInt `json:"wan-tx_packets"` - WanTxBytes FlexInt `json:"wan-tx_bytes"` - LanRxPackets FlexInt `json:"lan-rx_packets"` - LanRxBytes FlexInt `json:"lan-rx_bytes"` - LanTxPackets FlexInt `json:"lan-tx_packets"` - LanTxBytes FlexInt `json:"lan-tx_bytes"` - LanRxDropped FlexInt `json:"lan-rx_dropped"` - WanRxErrors FlexInt `json:"wan-rx_errors,omitempty"` -} - -// UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Gateway Stat data. -func (v *USGStat) UnmarshalJSON(data []byte) error { - var n struct { - Gw `json:"gw"` - } - - v.Gw = &n.Gw - - err := json.Unmarshal(data, v.Gw) // controller version 5.10. - if err != nil { - return json.Unmarshal(data, &n) // controller version 5.11. - } - - return nil -} diff --git a/core/unifi/v4/usg_test.go b/core/unifi/v4/usg_test.go deleted file mode 100644 index 16bb6a18..00000000 --- a/core/unifi/v4/usg_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package unifi - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestUSGUnmarshalJSON(t *testing.T) { - testcontroller511 := `{ - "gw": { - "site_id": "mySite", - "o": "gw", - "oid": "00:00:00:00:00:00", - "gw": "00:00:00:00:00:00", - "time": 1577742600000, - "datetime": "2019-12-30T09:50:00Z", - "bytes": 0, - "duration": 3590568000, - "wan-rx_packets": 299729434558, - "wan-rx_bytes": 299882768958208, - "wan-tx_packets": 249639259523, - "wan-tx_bytes": 169183252492369, - "lan-rx_packets": 78912349453, - "lan-rx_bytes": 37599596992669, - "lan-tx_packets": 12991234992, - "lan-tx_bytes": 11794664098210}}` - - testcontroller510 := `{ - "site_id": "mySite", - "o": "gw", - "oid": "00:00:00:00:00:00", - "gw": "00:00:00:00:00:00", - "time": 1577742600000, - "datetime": "2019-12-30T09:50:00Z", - "bytes": 0, - "duration": 3590568000, - "wan-rx_packets": 299729434558, - "wan-rx_bytes": 299882768958208, - "wan-tx_packets": 249639259523, - "wan-tx_bytes": 169183252492369, - "lan-rx_packets": 78912349453, - "lan-rx_bytes": 37599596992669, - "lan-tx_packets": 12991234992, - "lan-tx_bytes": 11794664098210}` - - t.Parallel() - a := assert.New(t) - - u := &USGStat{} - lanRx := 37599596992669 - err := u.UnmarshalJSON([]byte(testcontroller510)) - a.Nil(err, "must be no error unmarshaling test strings") - a.Equal(float64(lanRx), u.LanRxBytes.Val, "data was not properly unmarshaled") - - u = &USGStat{} // reset - err = u.UnmarshalJSON([]byte(testcontroller511)) - a.Nil(err, "must be no error unmarshaling test strings") - a.Equal(float64(lanRx), u.LanRxBytes.Val, "data was not properly unmarshaled") -} diff --git a/core/unifi/v4/usw.go b/core/unifi/v4/usw.go deleted file mode 100644 index 242b2053..00000000 --- a/core/unifi/v4/usw.go +++ /dev/null @@ -1,377 +0,0 @@ -package unifi - -import ( - "encoding/json" - "time" -) - -// USW represents all the data from the Ubiquiti Controller for a Unifi Switch. -type USW struct { - SourceName string `json:"-"` - SiteName string `json:"-"` - ID string `json:"_id"` - Adopted FlexBool `json:"adopted"` - BoardRev FlexInt `json:"board_rev"` - Cfgversion string `json:"cfgversion"` - ConfigNetwork struct { - Type string `json:"type"` - IP string `json:"ip"` - } `json:"config_network"` - Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"` - EthernetTable []struct { - Mac string `json:"mac"` - NumPort FlexInt `json:"num_port,omitempty"` - Name string `json:"name"` - } `json:"ethernet_table"` - FlowctrlEnabled FlexBool `json:"flowctrl_enabled"` - FwCaps FlexInt `json:"fw_caps"` - HasFan FlexBool `json:"has_fan"` - HasTemperature FlexBool `json:"has_temperature"` - InformIP string `json:"inform_ip"` - InformURL string `json:"inform_url"` - IP string `json:"ip"` - JumboframeEnabled FlexBool `json:"jumboframe_enabled"` - LedOverride string `json:"led_override"` - LicenseState string `json:"license_state"` - Mac string `json:"mac"` - Model string `json:"model"` - Name string `json:"name"` - OutdoorModeOverride string `json:"outdoor_mode_override"` - PortOverrides []struct { - Name string `json:"name,omitempty"` - PoeMode string `json:"poe_mode,omitempty"` - PortIdx FlexInt `json:"port_idx"` - PortconfID string `json:"portconf_id"` - } `json:"port_overrides"` - PortTable []Port `json:"port_table"` - Serial string `json:"serial"` - SiteID string `json:"site_id"` - StpPriority FlexInt `json:"stp_priority"` - StpVersion string `json:"stp_version"` - Type string `json:"type"` - Version string `json:"version"` - RequiredVersion string `json:"required_version"` - SwitchCaps struct { - FeatureCaps FlexInt `json:"feature_caps"` - MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` - MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` - } `json:"switch_caps"` - HwCaps FlexInt `json:"hw_caps"` - Unsupported FlexBool `json:"unsupported"` - UnsupportedReason FlexInt `json:"unsupported_reason"` - SysErrorCaps FlexInt `json:"sys_error_caps"` - DeviceID string `json:"device_id"` - State FlexInt `json:"state"` - LastSeen FlexInt `json:"last_seen"` - Upgradable FlexBool `json:"upgradable,omitempty"` - AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded,omitempty"` - Rollupgrade FlexBool `json:"rollupgrade,omitempty"` - KnownCfgversion string `json:"known_cfgversion"` - Uptime FlexInt `json:"uptime"` - Locating FlexBool `json:"locating"` - ConnectRequestIP string `json:"connect_request_ip"` - ConnectRequestPort string `json:"connect_request_port"` - SysStats SysStats `json:"sys_stats"` - SystemStats SystemStats `json:"system-stats"` - FanLevel FlexInt `json:"fan_level"` - GeneralTemperature FlexInt `json:"general_temperature"` - Overheating FlexBool `json:"overheating"` - TotalMaxPower FlexInt `json:"total_max_power"` - DownlinkTable []struct { - PortIdx FlexInt `json:"port_idx"` - Speed FlexInt `json:"speed"` - FullDuplex FlexBool `json:"full_duplex"` - Mac string `json:"mac"` - } `json:"downlink_table"` - Uplink Uplink `json:"uplink"` - LastUplink struct { - UplinkMac string `json:"uplink_mac"` - } `json:"last_uplink"` - UplinkDepth FlexInt `json:"uplink_depth"` - Stat USWStat `json:"stat"` - TxBytes FlexInt `json:"tx_bytes"` - RxBytes FlexInt `json:"rx_bytes"` - Bytes FlexInt `json:"bytes"` - NumSta FlexInt `json:"num_sta"` - UserNumSta FlexInt `json:"user-num_sta"` - GuestNumSta FlexInt `json:"guest-num_sta"` -} - -// Port is a physical connection on a USW or UDM. -type Port struct { - AggregatedBy FlexBool `json:"aggregated_by"` - Autoneg FlexBool `json:"autoneg,omitempty"` - BytesR FlexInt `json:"bytes-r"` - DNS []string `json:"dns,omitempty"` - Dot1XMode string `json:"dot1x_mode"` - Dot1XStatus string `json:"dot1x_status"` - Enable FlexBool `json:"enable"` - FlowctrlRx FlexBool `json:"flowctrl_rx"` - FlowctrlTx FlexBool `json:"flowctrl_tx"` - FullDuplex FlexBool `json:"full_duplex"` - IP string `json:"ip,omitempty"` - Ifname string `json:"ifname,omitempty"` - IsUplink FlexBool `json:"is_uplink"` - Mac string `json:"mac,omitempty"` - Jumbo FlexBool `json:"jumbo,omitempty"` - Masked FlexBool `json:"masked"` - Media string `json:"media"` - Name string `json:"name"` - NetworkName string `json:"network_name,omitempty"` - NumPort int `json:"num_port,omitempty"` - OpMode string `json:"op_mode"` - PoeCaps FlexInt `json:"poe_caps"` - PoeClass string `json:"poe_class,omitempty"` - PoeCurrent FlexInt `json:"poe_current,omitempty"` - PoeEnable FlexBool `json:"poe_enable,omitempty"` - PoeGood FlexBool `json:"poe_good,omitempty"` - PoeMode string `json:"poe_mode,omitempty"` - PoePower FlexInt `json:"poe_power,omitempty"` - PoeVoltage FlexInt `json:"poe_voltage,omitempty"` - PortDelta struct { - TimeDelta int64 `json:"time_delta"` - } `json:"port_delta,omitempty"` - PortIdx FlexInt `json:"port_idx"` - PortPoe FlexBool `json:"port_poe"` - PortconfID string `json:"portconf_id"` - RxBroadcast FlexInt `json:"rx_broadcast"` - RxBytes FlexInt `json:"rx_bytes"` - RxBytesR FlexInt `json:"rx_bytes-r"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxMulticast FlexInt `json:"rx_multicast"` - RxPackets FlexInt `json:"rx_packets"` - Satisfaction FlexInt `json:"satisfaction,omitempty"` - SfpFound FlexBool `json:"sfp_found,omitempty"` - Speed FlexInt `json:"speed"` - SpeedCaps FlexInt `json:"speed_caps"` - StpPathcost FlexInt `json:"stp_pathcost"` - StpState string `json:"stp_state"` - TxBroadcast FlexInt `json:"tx_broadcast"` - TxBytes FlexInt `json:"tx_bytes"` - TxBytesR FlexInt `json:"tx_bytes-r"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxMulticast FlexInt `json:"tx_multicast"` - TxPackets FlexInt `json:"tx_packets"` - Type string `json:"type,omitempty"` - Up FlexBool `json:"up"` -} - -// USWStat holds the "stat" data for a switch. -// This is split out because of a JSON data format change from 5.10 to 5.11. -type USWStat struct { - *Sw -} - -// Sw is a subtype of USWStat to make unmarshalling of different controller versions possible. -type Sw struct { - SiteID string `json:"site_id"` - O string `json:"o"` - Oid string `json:"oid"` - Sw string `json:"sw"` - Time FlexInt `json:"time"` - Datetime time.Time `json:"datetime"` - RxPackets FlexInt `json:"rx_packets"` - RxBytes FlexInt `json:"rx_bytes"` - RxErrors FlexInt `json:"rx_errors"` - RxDropped FlexInt `json:"rx_dropped"` - RxCrypts FlexInt `json:"rx_crypts"` - RxFrags FlexInt `json:"rx_frags"` - TxPackets FlexInt `json:"tx_packets"` - TxBytes FlexInt `json:"tx_bytes"` - TxErrors FlexInt `json:"tx_errors"` - TxDropped FlexInt `json:"tx_dropped"` - TxRetries FlexInt `json:"tx_retries"` - RxMulticast FlexInt `json:"rx_multicast"` - RxBroadcast FlexInt `json:"rx_broadcast"` - TxMulticast FlexInt `json:"tx_multicast"` - TxBroadcast FlexInt `json:"tx_broadcast"` - Bytes FlexInt `json:"bytes"` - Duration FlexInt `json:"duration"` - /* These are all in port table */ - /* - Port1RxPackets FlexInt `json:"port_1-rx_packets,omitempty"` - Port1RxBytes FlexInt `json:"port_1-rx_bytes,omitempty"` - Port1TxPackets FlexInt `json:"port_1-tx_packets,omitempty"` - Port1TxBytes FlexInt `json:"port_1-tx_bytes,omitempty"` - Port1TxMulticast FlexInt `json:"port_1-tx_multicast"` - Port1TxBroadcast FlexInt `json:"port_1-tx_broadcast"` - Port3RxPackets FlexInt `json:"port_3-rx_packets,omitempty"` - Port3RxBytes FlexInt `json:"port_3-rx_bytes,omitempty"` - Port3TxPackets FlexInt `json:"port_3-tx_packets,omitempty"` - Port3TxBytes FlexInt `json:"port_3-tx_bytes,omitempty"` - Port3RxBroadcast FlexInt `json:"port_3-rx_broadcast"` - Port3TxMulticast FlexInt `json:"port_3-tx_multicast"` - Port3TxBroadcast FlexInt `json:"port_3-tx_broadcast"` - Port6RxPackets FlexInt `json:"port_6-rx_packets,omitempty"` - Port6RxBytes FlexInt `json:"port_6-rx_bytes,omitempty"` - Port6TxPackets FlexInt `json:"port_6-tx_packets,omitempty"` - Port6TxBytes FlexInt `json:"port_6-tx_bytes,omitempty"` - Port6RxMulticast FlexInt `json:"port_6-rx_multicast"` - Port6TxMulticast FlexInt `json:"port_6-tx_multicast"` - Port6TxBroadcast FlexInt `json:"port_6-tx_broadcast"` - Port7RxPackets FlexInt `json:"port_7-rx_packets,omitempty"` - Port7RxBytes FlexInt `json:"port_7-rx_bytes,omitempty"` - Port7TxPackets FlexInt `json:"port_7-tx_packets,omitempty"` - Port7TxBytes FlexInt `json:"port_7-tx_bytes,omitempty"` - Port7TxMulticast FlexInt `json:"port_7-tx_multicast"` - Port7TxBroadcast FlexInt `json:"port_7-tx_broadcast"` - Port9RxPackets FlexInt `json:"port_9-rx_packets,omitempty"` - Port9RxBytes FlexInt `json:"port_9-rx_bytes,omitempty"` - Port9TxPackets FlexInt `json:"port_9-tx_packets,omitempty"` - Port9TxBytes FlexInt `json:"port_9-tx_bytes,omitempty"` - Port9TxMulticast FlexInt `json:"port_9-tx_multicast"` - Port9TxBroadcast FlexInt `json:"port_9-tx_broadcast"` - Port10RxPackets FlexInt `json:"port_10-rx_packets,omitempty"` - Port10RxBytes FlexInt `json:"port_10-rx_bytes,omitempty"` - Port10TxPackets FlexInt `json:"port_10-tx_packets,omitempty"` - Port10TxBytes FlexInt `json:"port_10-tx_bytes,omitempty"` - Port10RxMulticast FlexInt `json:"port_10-rx_multicast"` - Port10TxMulticast FlexInt `json:"port_10-tx_multicast"` - Port10TxBroadcast FlexInt `json:"port_10-tx_broadcast"` - Port11RxPackets FlexInt `json:"port_11-rx_packets,omitempty"` - Port11RxBytes FlexInt `json:"port_11-rx_bytes,omitempty"` - Port11TxPackets FlexInt `json:"port_11-tx_packets,omitempty"` - Port11TxBytes FlexInt `json:"port_11-tx_bytes,omitempty"` - Port11TxMulticast FlexInt `json:"port_11-tx_multicast"` - Port11TxBroadcast FlexInt `json:"port_11-tx_broadcast"` - Port12RxPackets FlexInt `json:"port_12-rx_packets,omitempty"` - Port12RxBytes FlexInt `json:"port_12-rx_bytes,omitempty"` - Port12TxPackets FlexInt `json:"port_12-tx_packets,omitempty"` - Port12TxBytes FlexInt `json:"port_12-tx_bytes,omitempty"` - Port12TxMulticast FlexInt `json:"port_12-tx_multicast"` - Port12TxBroadcast FlexInt `json:"port_12-tx_broadcast"` - Port13RxPackets FlexInt `json:"port_13-rx_packets,omitempty"` - Port13RxBytes FlexInt `json:"port_13-rx_bytes,omitempty"` - Port13TxPackets FlexInt `json:"port_13-tx_packets,omitempty"` - Port13TxBytes FlexInt `json:"port_13-tx_bytes,omitempty"` - Port13RxMulticast FlexInt `json:"port_13-rx_multicast"` - Port13RxBroadcast FlexInt `json:"port_13-rx_broadcast"` - Port13TxMulticast FlexInt `json:"port_13-tx_multicast"` - Port13TxBroadcast FlexInt `json:"port_13-tx_broadcast"` - Port15RxPackets FlexInt `json:"port_15-rx_packets,omitempty"` - Port15RxBytes FlexInt `json:"port_15-rx_bytes,omitempty"` - Port15TxPackets FlexInt `json:"port_15-tx_packets,omitempty"` - Port15TxBytes FlexInt `json:"port_15-tx_bytes,omitempty"` - Port15RxBroadcast FlexInt `json:"port_15-rx_broadcast"` - Port15TxMulticast FlexInt `json:"port_15-tx_multicast"` - Port15TxBroadcast FlexInt `json:"port_15-tx_broadcast"` - Port16RxPackets FlexInt `json:"port_16-rx_packets,omitempty"` - Port16RxBytes FlexInt `json:"port_16-rx_bytes,omitempty"` - Port16TxPackets FlexInt `json:"port_16-tx_packets,omitempty"` - Port16TxBytes FlexInt `json:"port_16-tx_bytes,omitempty"` - Port16TxMulticast FlexInt `json:"port_16-tx_multicast"` - Port16TxBroadcast FlexInt `json:"port_16-tx_broadcast"` - Port17RxPackets FlexInt `json:"port_17-rx_packets,omitempty"` - Port17RxBytes FlexInt `json:"port_17-rx_bytes,omitempty"` - Port17TxPackets FlexInt `json:"port_17-tx_packets,omitempty"` - Port17TxBytes FlexInt `json:"port_17-tx_bytes,omitempty"` - Port17TxMulticast FlexInt `json:"port_17-tx_multicast"` - Port17TxBroadcast FlexInt `json:"port_17-tx_broadcast"` - Port18RxPackets FlexInt `json:"port_18-rx_packets,omitempty"` - Port18RxBytes FlexInt `json:"port_18-rx_bytes,omitempty"` - Port18TxPackets FlexInt `json:"port_18-tx_packets,omitempty"` - Port18TxBytes FlexInt `json:"port_18-tx_bytes,omitempty"` - Port18RxMulticast FlexInt `json:"port_18-rx_multicast"` - Port18TxMulticast FlexInt `json:"port_18-tx_multicast"` - Port18TxBroadcast FlexInt `json:"port_18-tx_broadcast"` - Port19RxPackets FlexInt `json:"port_19-rx_packets,omitempty"` - Port19RxBytes FlexInt `json:"port_19-rx_bytes,omitempty"` - Port19TxPackets FlexInt `json:"port_19-tx_packets,omitempty"` - Port19TxBytes FlexInt `json:"port_19-tx_bytes,omitempty"` - Port19TxMulticast FlexInt `json:"port_19-tx_multicast"` - Port19TxBroadcast FlexInt `json:"port_19-tx_broadcast"` - Port21RxPackets FlexInt `json:"port_21-rx_packets,omitempty"` - Port21RxBytes FlexInt `json:"port_21-rx_bytes,omitempty"` - Port21TxPackets FlexInt `json:"port_21-tx_packets,omitempty"` - Port21TxBytes FlexInt `json:"port_21-tx_bytes,omitempty"` - Port21RxBroadcast FlexInt `json:"port_21-rx_broadcast"` - Port21TxMulticast FlexInt `json:"port_21-tx_multicast"` - Port21TxBroadcast FlexInt `json:"port_21-tx_broadcast"` - Port22RxPackets FlexInt `json:"port_22-rx_packets,omitempty"` - Port22RxBytes FlexInt `json:"port_22-rx_bytes,omitempty"` - Port22TxPackets FlexInt `json:"port_22-tx_packets,omitempty"` - Port22TxBytes FlexInt `json:"port_22-tx_bytes,omitempty"` - Port22RxMulticast FlexInt `json:"port_22-rx_multicast"` - Port22TxMulticast FlexInt `json:"port_22-tx_multicast"` - Port22TxBroadcast FlexInt `json:"port_22-tx_broadcast"` - Port23RxPackets FlexInt `json:"port_23-rx_packets,omitempty"` - Port23RxBytes FlexInt `json:"port_23-rx_bytes,omitempty"` - Port23RxDropped FlexInt `json:"port_23-rx_dropped"` - Port23TxPackets FlexInt `json:"port_23-tx_packets,omitempty"` - Port23TxBytes FlexInt `json:"port_23-tx_bytes,omitempty"` - Port23RxMulticast FlexInt `json:"port_23-rx_multicast"` - Port23RxBroadcast FlexInt `json:"port_23-rx_broadcast"` - Port23TxMulticast FlexInt `json:"port_23-tx_multicast"` - Port23TxBroadcast FlexInt `json:"port_23-tx_broadcast"` - Port24RxPackets FlexInt `json:"port_24-rx_packets,omitempty"` - Port24RxBytes FlexInt `json:"port_24-rx_bytes,omitempty"` - Port24TxPackets FlexInt `json:"port_24-tx_packets,omitempty"` - Port24TxBytes FlexInt `json:"port_24-tx_bytes,omitempty"` - Port24RxMulticast FlexInt `json:"port_24-rx_multicast"` - Port24TxMulticast FlexInt `json:"port_24-tx_multicast"` - Port24TxBroadcast FlexInt `json:"port_24-tx_broadcast"` - Port1RxMulticast FlexInt `json:"port_1-rx_multicast"` - Port3RxDropped FlexInt `json:"port_3-rx_dropped"` - Port3RxMulticast FlexInt `json:"port_3-rx_multicast"` - Port6RxDropped FlexInt `json:"port_6-rx_dropped"` - Port7RxDropped FlexInt `json:"port_7-rx_dropped"` - Port7RxMulticast FlexInt `json:"port_7-rx_multicast"` - Port9RxDropped FlexInt `json:"port_9-rx_dropped"` - Port9RxMulticast FlexInt `json:"port_9-rx_multicast"` - Port9RxBroadcast FlexInt `json:"port_9-rx_broadcast"` - Port10RxBroadcast FlexInt `json:"port_10-rx_broadcast"` - Port12RxDropped FlexInt `json:"port_12-rx_dropped"` - Port12RxMulticast FlexInt `json:"port_12-rx_multicast"` - Port13RxDropped FlexInt `json:"port_13-rx_dropped"` - Port17RxDropped FlexInt `json:"port_17-rx_dropped"` - Port17RxMulticast FlexInt `json:"port_17-rx_multicast"` - Port17RxBroadcast FlexInt `json:"port_17-rx_broadcast"` - Port19RxDropped FlexInt `json:"port_19-rx_dropped"` - Port19RxMulticast FlexInt `json:"port_19-rx_multicast"` - Port19RxBroadcast FlexInt `json:"port_19-rx_broadcast"` - Port21RxDropped FlexInt `json:"port_21-rx_dropped"` - Port21RxMulticast FlexInt `json:"port_21-rx_multicast"` - Port7RxBroadcast FlexInt `json:"port_7-rx_broadcast"` - Port18RxBroadcast FlexInt `json:"port_18-rx_broadcast"` - Port16RxMulticast FlexInt `json:"port_16-rx_multicast"` - Port15RxDropped FlexInt `json:"port_15-rx_dropped"` - Port15RxMulticast FlexInt `json:"port_15-rx_multicast"` - Port16RxBroadcast FlexInt `json:"port_16-rx_broadcast"` - Port11RxBroadcast FlexInt `json:"port_11-rx_broadcast"` - Port12RxBroadcast FlexInt `json:"port_12-rx_broadcast"` - Port6RxBroadcast FlexInt `json:"port_6-rx_broadcast"` - Port24RxBroadcast FlexInt `json:"port_24-rx_broadcast"` - Port22RxBroadcast FlexInt `json:"port_22-rx_broadcast"` - Port10TxDropped FlexInt `json:"port_10-tx_dropped"` - Port16TxDropped FlexInt `json:"port_16-tx_dropped"` - Port1RxBroadcast FlexInt `json:"port_1-rx_broadcast"` - Port4RxPackets FlexInt `json:"port_4-rx_packets,omitempty"` - Port4RxBytes FlexInt `json:"port_4-rx_bytes,omitempty"` - Port4RxDropped FlexInt `json:"port_4-rx_dropped"` - Port4TxPackets FlexInt `json:"port_4-tx_packets,omitempty"` - Port4TxBytes FlexInt `json:"port_4-tx_bytes,omitempty"` - Port4TxDropped FlexInt `json:"port_4-tx_dropped"` - Port4RxMulticast FlexInt `json:"port_4-rx_multicast"` - Port4RxBroadcast FlexInt `json:"port_4-rx_broadcast"` - Port4TxMulticast FlexInt `json:"port_4-tx_multicast"` - Port4TxBroadcast FlexInt `json:"port_4-tx_broadcast"` - */ -} - -// UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Switch Stat data. -func (v *USWStat) UnmarshalJSON(data []byte) error { - var n struct { - Sw `json:"sw"` - } - - v.Sw = &n.Sw - - err := json.Unmarshal(data, v.Sw) // controller version 5.10. - if err != nil { - return json.Unmarshal(data, &n) // controller version 5.11. - } - - return nil -} diff --git a/core/unifi/v4/usw_test.go b/core/unifi/v4/usw_test.go deleted file mode 100644 index 66bfac63..00000000 --- a/core/unifi/v4/usw_test.go +++ /dev/null @@ -1,75 +0,0 @@ -package unifi - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func testGetControllerJSON() (string, string) { - return `{ - "sw": { - "site_id": "mySite", - "o": "sw", - "oid": "00:00:00:00:00:00", - "sw": "00:00:00:00:00:00", - "time": 1577742600000, - "datetime": "2019-12-30T09:40:00Z", - "rx_packets": 321, - "rx_bytes": 321, - "rx_errors": 123, - "rx_dropped": 123, - "rx_crypts": 123, - "rx_frags": 123, - "tx_packets": 123, - "tx_bytes": 123, - "tx_errors": 0, - "tx_dropped": 0, - "tx_retries": 0, - "rx_multicast": 123, - "rx_broadcast": 123, - "tx_multicast": 123, - "tx_broadcast": 123, - "bytes": 123, - "duration": 123}}`, - `{ - "site_id": "mySite", - "o": "sw", - "oid": "00:00:00:00:00:00", - "sw": "00:00:00:00:00:00", - "time": 1577742600000, - "datetime": "2019-12-30T09:40:00Z", - "rx_packets": 321, - "rx_bytes": 321, - "rx_errors": 123, - "rx_dropped": 123, - "rx_crypts": 123, - "rx_frags": 123, - "tx_packets": 123, - "tx_bytes": 123, - "tx_errors": 0, - "tx_dropped": 0, - "tx_retries": 0, - "rx_multicast": 123, - "rx_broadcast": 123, - "tx_multicast": 123, - "tx_broadcast": 123, - "bytes": 123, - "duration": 123}` -} - -func TestUSWUnmarshalJSON(t *testing.T) { - t.Parallel() - a := assert.New(t) - testcontroller511, testcontroller510 := testGetControllerJSON() - rxMulticast := 123 - u := &USWStat{} - err := u.UnmarshalJSON([]byte(testcontroller510)) - a.Nil(err, "must be no error unmarshaling test strings") - a.Equal(float64(rxMulticast), u.RxMulticast.Val, "data was not properly unmarshaled") - - u = &USWStat{} // reset - err = u.UnmarshalJSON([]byte(testcontroller511)) - a.Nil(err, "must be no error unmarshaling test strings") - a.Equal(float64(rxMulticast), u.RxMulticast.Val, "data was not properly unmarshaled") -} From d6114a77db91c4e7e8a24e120b714e3a3216f90b Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sat, 28 Dec 2019 20:09:40 -0800 Subject: [PATCH 127/194] Move repo --- core/unifi/README.md | 6 +++--- core/unifi/devices.go | 2 +- core/unifi/go.mod | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/unifi/README.md b/core/unifi/README.md index 87f58e06..33d8a563 100644 --- a/core/unifi/README.md +++ b/core/unifi/README.md @@ -7,9 +7,9 @@ data. The data is provided in a large struct you can consume in your application This library is designed to PULL data FROM the controller. It has no methods that update settings or change things on the controller. -[Someone expressed interest](https://github.com/golift/unifi/issues/31) in +[Someone expressed interest](https://github.com/unifi-poller/unifi/issues/31) in adding methods to update data, and I'm okay with that. I'll even help add them. -[Tell me what you want to do](https://github.com/golift/unifi/issues/new), and we'll make it happen. +[Tell me what you want to do](https://github.com/unifi-poller/unifi/issues/new), and we'll make it happen. Pull requests, feature requests, code reviews and feedback are welcomed! @@ -18,7 +18,7 @@ Here's a working example: package main import "log" -import "golift.io/unifi" +import "github.com/unifi-poller/unifi" func main() { c := *unifi.Config{ diff --git a/core/unifi/devices.go b/core/unifi/devices.go index d877d9c4..febcec37 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -88,7 +88,7 @@ func (u *Unifi) unmarshalDevice(dev string, data json.RawMessage, v interface{}) json, err := data.MarshalJSON() u.DebugLog("Failed Payload: %s (marshal err: %v)", json, err) u.DebugLog("The above payload can prove useful during torubleshooting when you open an Issue:") - u.DebugLog("==- https://github.com/golift/unifi/issues/new -==") + u.DebugLog("==- https://github.com/unifi-poller/unifi/issues/new -==") } return err diff --git a/core/unifi/go.mod b/core/unifi/go.mod index 80ac2e5c..04a641c0 100644 --- a/core/unifi/go.mod +++ b/core/unifi/go.mod @@ -1,4 +1,4 @@ -module golift.io/unifi +module github.com/unifi-poller/unifi go 1.13 From f8c624482223a9a45dee462f86a1a98422af163e Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 29 Dec 2019 01:04:09 -0800 Subject: [PATCH 128/194] fix build --- core/unifi/.travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/.travis.yml b/core/unifi/.travis.yml index 4346066d..46ed9dd0 100644 --- a/core/unifi/.travis.yml +++ b/core/unifi/.travis.yml @@ -5,7 +5,7 @@ before_install: # download super-linter: golangci-lint - curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin latest install: -- go mod vendor +- go mod download script: - golangci-lint run --enable-all -e G402 -D gochecknoglobals - go test ./... From 4a8a9e118f096b0573c449ea0b404952414c3fa2 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 29 Dec 2019 01:05:44 -0800 Subject: [PATCH 129/194] update license text --- core/unifi/LICENSE | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/core/unifi/LICENSE b/core/unifi/LICENSE index 9187a167..2c74f096 100644 --- a/core/unifi/LICENSE +++ b/core/unifi/LICENSE @@ -1,23 +1,22 @@ -MIT License - -Copyright (c) 2019 Go Lift - Building Strong Go Tools -Copyright (c) 2018 David Newhall II +MIT LICENSE. +Copyright (c) 2018-2020 David Newhall II Copyright (c) 2016 Garrett Bjerkhoel -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From 6350bf19e6516318aa2b133d6d47b528e4d04305 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Mon, 30 Dec 2019 15:58:13 -0800 Subject: [PATCH 130/194] add string methods to special structs --- core/unifi/types.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/unifi/types.go b/core/unifi/types.go index ed298f40..be5e3d83 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -112,6 +112,10 @@ func (f *FlexInt) UnmarshalJSON(b []byte) error { return nil } +func (f *FlexInt) String() string { + return f.Txt +} + // FlexBool provides a container and unmarshalling for fields that may be // boolean or strings in the Unifi API. type FlexBool struct { @@ -130,3 +134,7 @@ func (f *FlexBool) UnmarshalJSON(b []byte) error { return nil } + +func (f *FlexBool) String() string { + return f.Txt +} From d3863975b695627c883259d3b972cbe97f0f1107 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Mon, 30 Dec 2019 16:04:25 -0800 Subject: [PATCH 131/194] fix lint --- core/unifi/site.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/unifi/site.go b/core/unifi/site.go index 20018b03..03207ae1 100644 --- a/core/unifi/site.go +++ b/core/unifi/site.go @@ -5,6 +5,9 @@ import ( "strings" ) +// Satisfy gomnd +const oneItem = 1 + // GetSites returns a list of configured sites on the UniFi controller. func (u *Unifi) GetSites() (Sites, error) { var response struct { @@ -48,9 +51,9 @@ func (u *Unifi) GetSiteDPI(sites Sites) ([]*DPITable, error) { return nil, err } - if l := len(response.Data); l > 1 { + if l := len(response.Data); l > oneItem { return nil, fmt.Errorf("dpi data table contains more than 1 item; please open a bug report") - } else if l != 1 { + } else if l != oneItem { continue } From ad4aca0f5358bb139079d8be26db53349e736f8c Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Fri, 31 Jan 2020 12:18:02 -0800 Subject: [PATCH 132/194] convert dhcpend time to flexint --- core/unifi/clients.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/clients.go b/core/unifi/clients.go index ca4ea34d..5956c5ff 100644 --- a/core/unifi/clients.go +++ b/core/unifi/clients.go @@ -81,7 +81,7 @@ type Client struct { DevFamily FlexInt `json:"dev_family"` DevID FlexInt `json:"dev_id"` DevVendor FlexInt `json:"dev_vendor,omitempty"` - DhcpendTime int `json:"dhcpend_time,omitempty"` + DhcpendTime FlexInt `json:"dhcpend_time,omitempty"` Satisfaction FlexInt `json:"satisfaction,omitempty"` Essid string `json:"essid"` FirstSeen int64 `json:"first_seen"` From 5197a7239028ce8a87cef76fdd273e41d06dbca5 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Tue, 4 Feb 2020 01:46:34 -0800 Subject: [PATCH 133/194] Add support for new api paths. --- core/unifi/go.mod | 1 + core/unifi/go.sum | 5 ++++ core/unifi/types.go | 25 +++++++++++++++--- core/unifi/unifi.go | 63 ++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 87 insertions(+), 7 deletions(-) diff --git a/core/unifi/go.mod b/core/unifi/go.mod index 04a641c0..f72667b3 100644 --- a/core/unifi/go.mod +++ b/core/unifi/go.mod @@ -6,4 +6,5 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/pmezard/go-difflib v1.0.0 github.com/stretchr/testify v1.4.0 + golang.org/x/net v0.0.0-20200202094626-16171245cfb2 ) diff --git a/core/unifi/go.sum b/core/unifi/go.sum index 1041afa2..35df3bcb 100644 --- a/core/unifi/go.sum +++ b/core/unifi/go.sum @@ -6,6 +6,11 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +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/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/core/unifi/types.go b/core/unifi/types.go index be5e3d83..3f682919 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -23,16 +23,32 @@ const ( APIClientPath string = "/api/s/%s/stat/sta" // APIDevicePath is where we get data about Unifi devices. APIDevicePath string = "/api/s/%s/stat/device" - // APINetworkPath contains network-configuration data. Not really graphable. - APINetworkPath string = "/api/s/%s/rest/networkconf" - // APIUserGroupPath contains usergroup configurations. - APIUserGroupPath string = "/api/s/%s/rest/usergroup" // APILoginPath is Unifi Controller Login API Path APILoginPath string = "/api/login" + // APILoginPathNew is how we log into UDM 5.12.55+ + APILoginPathNew string = "/api/auth/login" // APIIPSEvents returns Intrusion Detection Systems Events APIIPSEvents string = "/api/s/%s/stat/ips/event" + // APIPrefixNew is the prefix added to the new API paths; except login. duh. + APIPrefixNew string = "/proxy/network" ) +// path returns the correct api path based on the new variable. +// new is based on the unifi-controller output. is it new or old output? +func (u *Unifi) path(path string) string { + if u.isNew { + if path == APILoginPath { + return APILoginPathNew + } + + if !strings.HasPrefix(path, APIPrefixNew) && path != APILoginPathNew { + return APIPrefixNew + path + } + } + + return path +} + // Logger is a base type to deal with changing log outputs. Create a logger // that matches this interface to capture debug and error logs. type Logger func(msg string, fmt ...interface{}) @@ -70,6 +86,7 @@ type Unifi struct { *http.Client *Config *server + isNew bool } // server is the /status endpoint from the Unifi controller. diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 2b3ba865..c0a437a3 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -14,15 +14,18 @@ import ( "io/ioutil" "net/http" "net/http/cookiejar" + "net/url" "strings" "time" + + "golang.org/x/net/publicsuffix" ) // NewUnifi creates a http.Client with authenticated cookies. // Used to make additional, authenticated requests to the APIs. // Start here. func NewUnifi(config *Config) (*Unifi, error) { - jar, err := cookiejar.New(nil) + jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List}) if err != nil { return nil, err } @@ -45,6 +48,11 @@ func NewUnifi(config *Config) (*Unifi, error) { }, }, } + + if err := u.checkNewStyleAPI(); err != nil { + return u, err + } + if err := u.Login(); err != nil { return u, err } @@ -58,6 +66,7 @@ func NewUnifi(config *Config) (*Unifi, error) { // Login is a helper method. It can be called to grab a new authentication cookie. func (u *Unifi) Login() error { + APILoginPath := u.path(APILoginPath) start := time.Now() // magic login. @@ -84,6 +93,47 @@ func (u *Unifi) Login() error { return nil } +// with the release of controller version 5.12.55 on UDM in Jan 2020 the api paths +// changed and broke this library. This function runs when `NewUnifi()` is called to +// check if this is a newer controller or not. If it is, we set new to true. +// Setting new to true makes the path() method return different (new) paths. +func (u *Unifi) checkNewStyleAPI() error { + u.DebugLog("Requesting %s/ to determine API paths", u.URL) + + req, err := http.NewRequest("GET", u.URL+"/", nil) + if err != nil { + return err + } + + // We can't share these cookies with other requests, so make a new client. + // Checking the return code on the first request so don't follow a redirect. + client := &http.Client{ + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: !u.VerifySSL}, + }, + } + + resp, err := client.Do(req) + if err != nil { + return err + } + + defer resp.Body.Close() // we need no data here. + _, _ = io.Copy(ioutil.Discard, resp.Body) // avoid leaking. + + if resp.StatusCode == http.StatusOK { + // The new version returns a "200" for a / request. + u.isNew = true + u.DebugLog("Using NEW UniFi controller API paths!") + } + + // The old version returns a "302" (to /manage) for a / request + return nil +} + // GetServerData sets the controller's version and UUID. Only call this if you // previously called Login and suspect the controller version has changed. func (u *Unifi) GetServerData() error { @@ -116,7 +166,7 @@ func (u *Unifi) GetData(apiPath string, v interface{}, params ...string) error { // And if you're doing that... sumbut a pull request with your new struct. :) // This is a helper method that is exposed for convenience. func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err error) { - switch params { + switch apiPath = u.path(apiPath); params { case "": req, err = http.NewRequest("GET", u.URL+apiPath, nil) default: @@ -128,7 +178,14 @@ func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err er } req.Header.Add("Accept", "application/json") - u.DebugLog("Requesting %s, with params: %v", apiPath, params != "") + req.Header.Add("Content-Type", "application/json; charset=utf-8") + + if u.Client.Jar != nil { + parsedURL, _ := url.Parse(u.URL + apiPath) + u.DebugLog("Requesting %s, with params: %v, cookies: %d", apiPath, params != "", len(u.Client.Jar.Cookies(parsedURL))) + } else { + u.DebugLog("Requesting %s, with params: %v,", apiPath, params != "") + } return } From 60a7be9351ba8ad5fea9150ff51255fc248116f2 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Tue, 4 Feb 2020 02:43:16 -0800 Subject: [PATCH 134/194] fix log output --- core/unifi/unifi.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index c0a437a3..a72b9613 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -156,7 +156,7 @@ func (u *Unifi) GetData(apiPath string, v interface{}, params ...string) error { } u.DebugLog("Requested %s: elapsed %v, returned %d bytes", - apiPath, time.Since(start).Round(time.Millisecond), len(body)) + u.path(apiPath), time.Since(start).Round(time.Millisecond), len(body)) return json.Unmarshal(body, v) } From bee5bd5f92f05acbaa7eb97c755f4f28df9d89c0 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Tue, 4 Feb 2020 12:04:50 -0800 Subject: [PATCH 135/194] play the csrf game --- core/unifi/types.go | 1 + core/unifi/unifi.go | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/core/unifi/types.go b/core/unifi/types.go index 3f682919..cb0d778d 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -87,6 +87,7 @@ type Unifi struct { *Config *server isNew bool + csrf string } // server is the /status endpoint from the Unifi controller. diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index a72b9613..7254091c 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -66,7 +66,6 @@ func NewUnifi(config *Config) (*Unifi, error) { // Login is a helper method. It can be called to grab a new authentication cookie. func (u *Unifi) Login() error { - APILoginPath := u.path(APILoginPath) start := time.Now() // magic login. @@ -83,11 +82,11 @@ func (u *Unifi) Login() error { defer resp.Body.Close() // we need no data here. _, _ = io.Copy(ioutil.Discard, resp.Body) // avoid leaking. u.DebugLog("Requested %s: elapsed %v, returned %d bytes", - APILoginPath, time.Since(start).Round(time.Millisecond), resp.ContentLength) + req.URL, time.Since(start).Round(time.Millisecond), resp.ContentLength) if resp.StatusCode != http.StatusOK { return fmt.Errorf("authentication failed (user: %s): %s (status: %s)", - u.User, u.URL+APILoginPath, resp.Status) + u.User, req.URL, resp.Status) } return nil @@ -127,7 +126,7 @@ func (u *Unifi) checkNewStyleAPI() error { if resp.StatusCode == http.StatusOK { // The new version returns a "200" for a / request. u.isNew = true - u.DebugLog("Using NEW UniFi controller API paths!") + u.DebugLog("Using NEW UniFi controller API paths for %s", req.URL) } // The old version returns a "302" (to /manage) for a / request @@ -156,7 +155,7 @@ func (u *Unifi) GetData(apiPath string, v interface{}, params ...string) error { } u.DebugLog("Requested %s: elapsed %v, returned %d bytes", - u.path(apiPath), time.Since(start).Round(time.Millisecond), len(body)) + u.URL+u.path(apiPath), time.Since(start).Round(time.Millisecond), len(body)) return json.Unmarshal(body, v) } @@ -177,14 +176,16 @@ func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err er return } + // Add the saved CSRF header. + req.Header.Set("X-CSRF-Token", u.csrf) req.Header.Add("Accept", "application/json") req.Header.Add("Content-Type", "application/json; charset=utf-8") if u.Client.Jar != nil { - parsedURL, _ := url.Parse(u.URL + apiPath) - u.DebugLog("Requesting %s, with params: %v, cookies: %d", apiPath, params != "", len(u.Client.Jar.Cookies(parsedURL))) + parsedURL, _ := url.Parse(req.URL.String()) + u.DebugLog("Requesting %s, with params: %v, cookies: %d", req.URL, params != "", len(u.Client.Jar.Cookies(parsedURL))) } else { - u.DebugLog("Requesting %s, with params: %v,", apiPath, params != "") + u.DebugLog("Requesting %s, with params: %v,", req.URL, params != "") } return @@ -209,8 +210,13 @@ func (u *Unifi) GetJSON(apiPath string, params ...string) ([]byte, error) { return body, err } + // Save the returned CSRF header. + if csrf := resp.Header.Get("x-csrf-token"); csrf != "" { + u.csrf = resp.Header.Get("x-csrf-token") + } + if resp.StatusCode != http.StatusOK { - err = fmt.Errorf("invalid status code from server %s", resp.Status) + err = fmt.Errorf("invalid status code from server for %s: %s", req.URL, resp.Status) } return body, err From e1583f0d8912a71c898c0bc69f442d56c50567be Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Tue, 4 Feb 2020 12:58:16 -0800 Subject: [PATCH 136/194] allow controlling New externally --- core/unifi/types.go | 6 +++--- core/unifi/unifi.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/unifi/types.go b/core/unifi/types.go index cb0d778d..de474c64 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -36,7 +36,7 @@ const ( // path returns the correct api path based on the new variable. // new is based on the unifi-controller output. is it new or old output? func (u *Unifi) path(path string) string { - if u.isNew { + if u.New { if path == APILoginPath { return APILoginPathNew } @@ -76,6 +76,7 @@ type Config struct { VerifySSL bool ErrorLog Logger DebugLog Logger + New bool } // Unifi is what you get in return for providing a password! Unifi represents @@ -86,8 +87,7 @@ type Unifi struct { *http.Client *Config *server - isNew bool - csrf string + csrf string } // server is the /status endpoint from the Unifi controller. diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 7254091c..7614ce5e 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -125,7 +125,7 @@ func (u *Unifi) checkNewStyleAPI() error { if resp.StatusCode == http.StatusOK { // The new version returns a "200" for a / request. - u.isNew = true + u.New = true u.DebugLog("Using NEW UniFi controller API paths for %s", req.URL) } From 4ce9f2c83a53d7d9d50a5b2a2bcc86a2acc02d78 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Tue, 4 Feb 2020 14:17:30 -0800 Subject: [PATCH 137/194] fix malign --- core/unifi/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/types.go b/core/unifi/types.go index de474c64..d8c56a76 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -74,9 +74,9 @@ type Config struct { Pass string URL string VerifySSL bool + New bool ErrorLog Logger DebugLog Logger - New bool } // Unifi is what you get in return for providing a password! Unifi represents From 69a11fc51e73973489c9544cbfc8a62141744916 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Tue, 4 Feb 2020 17:04:21 -0800 Subject: [PATCH 138/194] make UAP state like UDM state --- core/unifi/uap.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/uap.go b/core/unifi/uap.go index 172504b8..23f20c29 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -63,7 +63,7 @@ type UAP struct { HasFan FlexBool `json:"has_fan"` HasTemperature FlexBool `json:"has_temperature"` DeviceID string `json:"device_id"` - State int `json:"state"` + State FlexInt `json:"state"` LastSeen FlexInt `json:"last_seen"` Upgradable FlexBool `json:"upgradable"` AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` From 12eccf511bef2c61ed1cce4d3c3e550f15ecf7d5 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sat, 13 Jun 2020 19:05:10 -0700 Subject: [PATCH 139/194] trim whitespace of client and device names --- core/unifi/.travis.yml | 6 ++---- core/unifi/clients.go | 5 +++-- core/unifi/devices.go | 9 +++++---- core/unifi/dpi.go | 4 ++-- core/unifi/go.mod | 5 +++-- core/unifi/go.sum | 5 +++++ core/unifi/ids.go | 4 +++- core/unifi/site.go | 13 +++++++------ core/unifi/types.go | 8 +++++++- core/unifi/types_test.go | 2 +- core/unifi/uap.go | 2 +- core/unifi/uap_test.go | 2 +- core/unifi/udm.go | 2 +- core/unifi/unifi.go | 16 +++++++++++----- core/unifi/unifi_test.go | 2 +- core/unifi/usg_test.go | 2 +- core/unifi/usw_test.go | 2 +- 17 files changed, 55 insertions(+), 34 deletions(-) diff --git a/core/unifi/.travis.yml b/core/unifi/.travis.yml index 46ed9dd0..654efb02 100644 --- a/core/unifi/.travis.yml +++ b/core/unifi/.travis.yml @@ -1,11 +1,9 @@ language: go go: -- 1.13.x +- 1.14.x before_install: # download super-linter: golangci-lint - curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin latest -install: -- go mod download script: -- golangci-lint run --enable-all -e G402 -D gochecknoglobals +- golangci-lint run --enable-all - go test ./... diff --git a/core/unifi/clients.go b/core/unifi/clients.go index 5956c5ff..a5a76019 100644 --- a/core/unifi/clients.go +++ b/core/unifi/clients.go @@ -2,6 +2,7 @@ package unifi import ( "fmt" + "strings" ) // GetClients returns a response full of clients' data from the UniFi Controller. @@ -26,8 +27,8 @@ func (u *Unifi) GetClients(sites Sites) (Clients, error) { // Add the special "Site Name" to each client. This becomes a Grafana filter somewhere. response.Data[i].SiteName = site.Desc + " (" + site.Name + ")" // Fix name and hostname fields. Sometimes one or the other is blank. - response.Data[i].Hostname = pick(d.Hostname, d.Name, d.Mac) - response.Data[i].Name = pick(d.Name, d.Hostname) + response.Data[i].Hostname = strings.TrimSpace(pick(d.Hostname, d.Name, d.Mac)) + response.Data[i].Name = strings.TrimSpace(pick(d.Name, d.Hostname)) } data = append(data, response.Data...) diff --git a/core/unifi/devices.go b/core/unifi/devices.go index febcec37..9ddfefe6 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -3,6 +3,7 @@ package unifi import ( "encoding/json" "fmt" + "strings" ) // GetDevices returns a response full of devices' data from the UniFi Controller. @@ -50,25 +51,25 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { case "uap": dev := &UAP{SiteName: siteName, SourceName: u.URL} if u.unmarshalDevice(assetType, r, dev) == nil { - dev.Name = pick(dev.Name, dev.Mac) + dev.Name = strings.TrimSpace(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, SourceName: u.URL} if u.unmarshalDevice(assetType, r, dev) == nil { - dev.Name = pick(dev.Name, dev.Mac) + dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) devices.USGs = append(devices.USGs, dev) } case "usw": dev := &USW{SiteName: siteName, SourceName: u.URL} if u.unmarshalDevice(assetType, r, dev) == nil { - dev.Name = pick(dev.Name, dev.Mac) + dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) devices.USWs = append(devices.USWs, dev) } case "udm": dev := &UDM{SiteName: siteName, SourceName: u.URL} if u.unmarshalDevice(assetType, r, dev) == nil { - dev.Name = pick(dev.Name, dev.Mac) + dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) devices.UDMs = append(devices.UDMs, dev) } default: diff --git a/core/unifi/dpi.go b/core/unifi/dpi.go index 86170d03..6dc3d843 100644 --- a/core/unifi/dpi.go +++ b/core/unifi/dpi.go @@ -56,7 +56,7 @@ func (d DPIMap) Keys() []string { // DPICats maps the categories to descriptions. // From: https://fw-download.ubnt.com/data/usg-dpi/1628-debian-v1.442.0-05f5a57eaef344358bd5a8e84a184c18.tar -var DPICats = DPIMap{ +var DPICats = DPIMap{ // nolint: gochecknoglobals 0: "Instant Messengers", 1: "Peer-to-Peer Networks", 3: "File Sharing", @@ -83,7 +83,7 @@ var DPICats = DPIMap{ // DPIApps maps the applications to names. // From: https://fw-download.ubnt.com/data/usg-dpi/1628-debian-v1.442.0-05f5a57eaef344358bd5a8e84a184c18.tar -var DPIApps = DPIMap{ +var DPIApps = DPIMap{ // nolint: gochecknoglobals 1: "MSN", 2: "Yahoo Messenger", 3: "AIM/ICQ/iIM", diff --git a/core/unifi/go.mod b/core/unifi/go.mod index f72667b3..9e2e4827 100644 --- a/core/unifi/go.mod +++ b/core/unifi/go.mod @@ -1,10 +1,11 @@ module github.com/unifi-poller/unifi -go 1.13 +go 1.14 require ( github.com/davecgh/go-spew v1.1.1 + github.com/pkg/errors v0.9.1 github.com/pmezard/go-difflib v1.0.0 github.com/stretchr/testify v1.4.0 - golang.org/x/net v0.0.0-20200202094626-16171245cfb2 + golang.org/x/net v0.0.0-20200602114024-627f9648deb9 ) diff --git a/core/unifi/go.sum b/core/unifi/go.sum index 35df3bcb..c8eb7c3d 100644 --- a/core/unifi/go.sum +++ b/core/unifi/go.sum @@ -1,6 +1,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -9,7 +11,10 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 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/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= diff --git a/core/unifi/ids.go b/core/unifi/ids.go index 6af0c8ab..1fc707aa 100644 --- a/core/unifi/ids.go +++ b/core/unifi/ids.go @@ -6,6 +6,8 @@ import ( "io/ioutil" "net/http" "time" + + "github.com/pkg/errors" ) // IDSList contains a list that contains all of the IDS Events on a controller. @@ -135,7 +137,7 @@ func (u *Unifi) GetSiteIDS(site *Site, from, to time.Time) ([]*IDS, error) { } if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("invalid status code from server %s", resp.Status) + return nil, errors.Wrap(errInvalidStatusCode, resp.Status) } if err := json.Unmarshal(body, &response); err != nil { diff --git a/core/unifi/site.go b/core/unifi/site.go index 03207ae1..f521a77e 100644 --- a/core/unifi/site.go +++ b/core/unifi/site.go @@ -5,8 +5,9 @@ import ( "strings" ) -// Satisfy gomnd -const oneItem = 1 +var ( + errDPIDataBug = fmt.Errorf("dpi data table contains more than 1 item; please open a bug report") +) // GetSites returns a list of configured sites on the UniFi controller. func (u *Unifi) GetSites() (Sites, error) { @@ -24,7 +25,7 @@ func (u *Unifi) GetSites() (Sites, error) { // Add special SourceName value. response.Data[i].SourceName = u.URL // If the human name is missing (description), set it to the cryptic name. - response.Data[i].Desc = pick(d.Desc, d.Name) + response.Data[i].Desc = strings.TrimSpace(pick(d.Desc, d.Name)) // Add the custom site name to each site. used as a Grafana filter somewhere. response.Data[i].SiteName = d.Desc + " (" + d.Name + ")" sites = append(sites, d.Name) // used for debug log only @@ -51,9 +52,9 @@ func (u *Unifi) GetSiteDPI(sites Sites) ([]*DPITable, error) { return nil, err } - if l := len(response.Data); l > oneItem { - return nil, fmt.Errorf("dpi data table contains more than 1 item; please open a bug report") - } else if l != oneItem { + if l := len(response.Data); l > 1 { + return nil, errDPIDataBug + } else if l != 1 { continue } diff --git a/core/unifi/types.go b/core/unifi/types.go index d8c56a76..a5a5c504 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -6,6 +6,12 @@ import ( "net/http" "strconv" "strings" + + "github.com/pkg/errors" +) + +var ( + errCannotUnmarshalFlexInt = fmt.Errorf("cannot unmarshal to FlexInt") ) // This is a list of unifi API paths. @@ -124,7 +130,7 @@ func (f *FlexInt) UnmarshalJSON(b []byte) error { f.Txt = "0" f.Val = 0 default: - return fmt.Errorf("cannot unmarshal to FlexInt: %s", b) + return errors.Wrapf(errCannotUnmarshalFlexInt, "%v", b) } return nil diff --git a/core/unifi/types_test.go b/core/unifi/types_test.go index a7eeef06..118662e1 100644 --- a/core/unifi/types_test.go +++ b/core/unifi/types_test.go @@ -1,4 +1,4 @@ -package unifi +package unifi // nolint: testpackage import ( "encoding/json" diff --git a/core/unifi/uap.go b/core/unifi/uap.go index 23f20c29..0d3b3172 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -399,7 +399,7 @@ type RadioTable []struct { WlangroupID string `json:"wlangroup_id"` } -// RadioTableStats is part of the data shared between UAP and UDM +// RadioTableStats is part of the data shared between UAP and UDM. type RadioTableStats []struct { Name string `json:"name"` Channel FlexInt `json:"channel"` diff --git a/core/unifi/uap_test.go b/core/unifi/uap_test.go index 155b3539..3c6c28a1 100644 --- a/core/unifi/uap_test.go +++ b/core/unifi/uap_test.go @@ -1,4 +1,4 @@ -package unifi +package unifi // nolint: testpackage import ( "testing" diff --git a/core/unifi/udm.go b/core/unifi/udm.go index 16842809..49727256 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -175,7 +175,7 @@ type NetworkTable []struct { } // UDMStat holds the "stat" data for a dream machine. -// A dream machine is a USG + USW + Controller +// A dream machine is a USG + USW + Controller. type UDMStat struct { *Gw `json:"gw"` *Sw `json:"sw"` diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 7614ce5e..5b3ddd5d 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -18,9 +18,15 @@ import ( "strings" "time" + "github.com/pkg/errors" "golang.org/x/net/publicsuffix" ) +var ( + errAuthenticationFailed = fmt.Errorf("authentication failed") + errInvalidStatusCode = fmt.Errorf("invalid status code from server") +) + // NewUnifi creates a http.Client with authenticated cookies. // Used to make additional, authenticated requests to the APIs. // Start here. @@ -44,7 +50,7 @@ func NewUnifi(config *Config) (*Unifi, error) { Client: &http.Client{ Jar: jar, Transport: &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: !config.VerifySSL}, + TLSClientConfig: &tls.Config{InsecureSkipVerify: !config.VerifySSL}, // nolint: gosec }, }, } @@ -58,7 +64,7 @@ func NewUnifi(config *Config) (*Unifi, error) { } if err := u.GetServerData(); err != nil { - return u, fmt.Errorf("unable to get server version: %v", err) + return u, errors.Wrap(err, "unable to get server version") } return u, nil @@ -85,7 +91,7 @@ func (u *Unifi) Login() error { req.URL, time.Since(start).Round(time.Millisecond), resp.ContentLength) if resp.StatusCode != http.StatusOK { - return fmt.Errorf("authentication failed (user: %s): %s (status: %s)", + return errors.Wrapf(errAuthenticationFailed, "(user: %s): %s (status: %s)", u.User, req.URL, resp.Status) } @@ -111,7 +117,7 @@ func (u *Unifi) checkNewStyleAPI() error { return http.ErrUseLastResponse }, Transport: &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: !u.VerifySSL}, + TLSClientConfig: &tls.Config{InsecureSkipVerify: !u.VerifySSL}, // nolint: gosec }, } @@ -216,7 +222,7 @@ func (u *Unifi) GetJSON(apiPath string, params ...string) ([]byte, error) { } if resp.StatusCode != http.StatusOK { - err = fmt.Errorf("invalid status code from server for %s: %s", req.URL, resp.Status) + err = errors.Wrapf(errInvalidStatusCode, "%s: %s", req.URL, resp.Status) } return body, err diff --git a/core/unifi/unifi_test.go b/core/unifi/unifi_test.go index 9c9015fb..28204201 100644 --- a/core/unifi/unifi_test.go +++ b/core/unifi/unifi_test.go @@ -1,4 +1,4 @@ -package unifi +package unifi // nolint: testpackage import ( "io/ioutil" diff --git a/core/unifi/usg_test.go b/core/unifi/usg_test.go index 16bb6a18..2905d066 100644 --- a/core/unifi/usg_test.go +++ b/core/unifi/usg_test.go @@ -1,4 +1,4 @@ -package unifi +package unifi // nolint: testpackage import ( "testing" diff --git a/core/unifi/usw_test.go b/core/unifi/usw_test.go index 66bfac63..4ba1eb5e 100644 --- a/core/unifi/usw_test.go +++ b/core/unifi/usw_test.go @@ -1,4 +1,4 @@ -package unifi +package unifi // nolint: testpackage import ( "testing" From 115bb5d7f617dd443120b546c39e8a9e2e37ef85 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sat, 13 Jun 2020 20:14:31 -0700 Subject: [PATCH 140/194] add udm temp sensors --- core/unifi/udm.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/unifi/udm.go b/core/unifi/udm.go index 49727256..1b406e54 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -69,8 +69,12 @@ type UDM struct { MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` } `json:"switch_caps"` - HasFan FlexBool `json:"has_fan"` - HasTemperature FlexBool `json:"has_temperature"` + HasFan FlexBool `json:"has_fan"` + Temperatures []struct { + Name string `json:"name"` + Type string `json:"type"` + Value float64 `json:"value"` + } `json:"temperatures"` RulesetInterfaces interface{} `json:"ruleset_interfaces"` /* struct { Br0 string `json:"br0"` From 8fa5c73c51dacd6c8de2ebc631eec18248d58036 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sat, 13 Jun 2020 20:37:08 -0700 Subject: [PATCH 141/194] Split temperatures out --- core/unifi/udm.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/core/unifi/udm.go b/core/unifi/udm.go index 1b406e54..aba1231c 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -69,13 +69,9 @@ type UDM struct { MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` } `json:"switch_caps"` - HasFan FlexBool `json:"has_fan"` - Temperatures []struct { - Name string `json:"name"` - Type string `json:"type"` - Value float64 `json:"value"` - } `json:"temperatures"` - RulesetInterfaces interface{} `json:"ruleset_interfaces"` + HasFan FlexBool `json:"has_fan"` + Temperatures Temperatures `json:"temperatures"` + RulesetInterfaces interface{} `json:"ruleset_interfaces"` /* struct { Br0 string `json:"br0"` Eth0 string `json:"eth0"` @@ -135,6 +131,12 @@ type UDM struct { NumHandheld FlexInt `json:"num_handheld"` // USG } +type Temperatures []struct { + Name string `json:"name"` + Type string `json:"type"` + Value float64 `json:"value"` +} + // NetworkTable is the list of networks on a gateway. type NetworkTable []struct { ID string `json:"_id"` From 9f84cbc4b2692a17c7c9f9ba78ca78485049907a Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sat, 13 Jun 2020 20:44:49 -0700 Subject: [PATCH 142/194] make temperaturesd a pointer --- core/unifi/udm.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/core/unifi/udm.go b/core/unifi/udm.go index aba1231c..aa2173dd 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -69,9 +69,9 @@ type UDM struct { MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` } `json:"switch_caps"` - HasFan FlexBool `json:"has_fan"` - Temperatures Temperatures `json:"temperatures"` - RulesetInterfaces interface{} `json:"ruleset_interfaces"` + HasFan FlexBool `json:"has_fan"` + Temperatures *Temperatures `json:"temperatures,omitempty"` + RulesetInterfaces interface{} `json:"ruleset_interfaces"` /* struct { Br0 string `json:"br0"` Eth0 string `json:"eth0"` @@ -131,12 +131,6 @@ type UDM struct { NumHandheld FlexInt `json:"num_handheld"` // USG } -type Temperatures []struct { - Name string `json:"name"` - Type string `json:"type"` - Value float64 `json:"value"` -} - // NetworkTable is the list of networks on a gateway. type NetworkTable []struct { ID string `json:"_id"` @@ -180,6 +174,12 @@ type NetworkTable []struct { TxPackets FlexInt `json:"tx_packets"` } +type Temperatures []struct { + Name string `json:"name"` + Type string `json:"type"` + Value float64 `json:"value"` +} + // UDMStat holds the "stat" data for a dream machine. // A dream machine is a USG + USW + Controller. type UDMStat struct { From b83d1251ed1296cc4ae5e6110d8798a9313e2add Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sat, 13 Jun 2020 20:46:23 -0700 Subject: [PATCH 143/194] better --- core/unifi/udm.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/unifi/udm.go b/core/unifi/udm.go index aa2173dd..041eb2b5 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -70,7 +70,7 @@ type UDM struct { MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` } `json:"switch_caps"` HasFan FlexBool `json:"has_fan"` - Temperatures *Temperatures `json:"temperatures,omitempty"` + Temperatures []Temperature `json:"temperatures,omitempty"` RulesetInterfaces interface{} `json:"ruleset_interfaces"` /* struct { Br0 string `json:"br0"` @@ -174,7 +174,7 @@ type NetworkTable []struct { TxPackets FlexInt `json:"tx_packets"` } -type Temperatures []struct { +type Temperature struct { Name string `json:"name"` Type string `json:"type"` Value float64 `json:"value"` From f7da5c68a8de972b9fa5e086a770c2b924159144 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Fri, 19 Jun 2020 02:20:06 -0700 Subject: [PATCH 144/194] Updates for Events --- core/unifi/clients.go | 7 +- core/unifi/devices.go | 2 +- core/unifi/events.go | 175 +++++++++++++++++++++++++++++++++++++++++ core/unifi/ids.go | 179 +++++++++++++++--------------------------- core/unifi/site.go | 7 +- core/unifi/types.go | 6 +- 6 files changed, 249 insertions(+), 127 deletions(-) create mode 100644 core/unifi/events.go diff --git a/core/unifi/clients.go b/core/unifi/clients.go index a5a76019..193e502a 100644 --- a/core/unifi/clients.go +++ b/core/unifi/clients.go @@ -6,7 +6,7 @@ import ( ) // GetClients returns a response full of clients' data from the UniFi Controller. -func (u *Unifi) GetClients(sites Sites) (Clients, error) { +func (u *Unifi) GetClients(sites []*Site) ([]*Client, error) { data := make([]*Client, 0) for _, site := range sites { @@ -38,7 +38,7 @@ func (u *Unifi) GetClients(sites Sites) (Clients, error) { } // GetClientsDPI garners dpi data for clients. -func (u *Unifi) GetClientsDPI(sites Sites) ([]*DPITable, error) { +func (u *Unifi) GetClientsDPI(sites []*Site) ([]*DPITable, error) { var data []*DPITable for _, site := range sites { @@ -63,9 +63,6 @@ func (u *Unifi) GetClientsDPI(sites Sites) ([]*DPITable, error) { return data, nil } -// Clients contains a list that contains all of the unifi clients from a controller. -type Clients []*Client - // Client defines all the data a connected-network client contains. type Client struct { SourceName string `json:"-"` diff --git a/core/unifi/devices.go b/core/unifi/devices.go index 9ddfefe6..045e43d7 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -7,7 +7,7 @@ import ( ) // GetDevices returns a response full of devices' data from the UniFi Controller. -func (u *Unifi) GetDevices(sites Sites) (*Devices, error) { +func (u *Unifi) GetDevices(sites []*Site) (*Devices, error) { devices := new(Devices) for _, site := range sites { diff --git a/core/unifi/events.go b/core/unifi/events.go new file mode 100644 index 00000000..d1982e38 --- /dev/null +++ b/core/unifi/events.go @@ -0,0 +1,175 @@ +package unifi + +import ( + "encoding/json" + "fmt" + "time" +) + +var ( + errNoSiteProvided = fmt.Errorf("site must not be nil or empty") + errInvalidTimeRange = fmt.Errorf("only 0, 1 or 2 times may be provided to timeRange") +) + +const ( + eventLimit = 50000 +) + +// GetEvents returns a response full of UniFi Events from multiple sites. +// timeRange may have a length of 0, 1 or 2. The first time is Start, the second is End. +// Events between start and end are returned. End defaults to time.Now(). +func (u *Unifi) GetEvents(sites []*Site, timeRange ...time.Time) ([]*Event, error) { + data := make([]*Event, 0) + + for _, site := range sites { + response, err := u.GetSiteEvents(site, timeRange...) + if err != nil { + return data, err + } + + data = append(data, response...) + } + + return data, nil +} + +// GetSiteEvents retreives the events from a single site. +// timeRange may have a length of 0, 1 or 2. The first time is Start, the second is End. +// Events between start and end are returned. End defaults to time.Now(). +func (u *Unifi) GetSiteEvents(site *Site, timeRange ...time.Time) ([]*Event, error) { // nolint: dupl + if site == nil || site.Name == "" { + return nil, errNoSiteProvided + } + + u.DebugLog("Polling Controller, retreiving UniFi Events, site %s (%s)", site.Name, site.Desc) + + var ( + path = fmt.Sprintf(APIEventPath, site.Name) + event struct { + Data []*Event `json:"data"` + } + ) + + if params, err := makeEventParams(timeRange...); err != nil { + return event.Data, err + } else if err = u.GetData(path, &event, params); err != nil { + return event.Data, err + } + + for i := range event.Data { + // Add special SourceName value. + event.Data[i].SourceName = u.URL + // Add the special "Site Name" to each event. This becomes a Grafana filter somewhere. + event.Data[i].SiteName = site.Desc + " (" + site.Name + ")" + } + + return event.Data, nil +} + +func makeEventParams(timeRange ...time.Time) (string, error) { + type eventReq struct { + Start int64 `json:"start,omitempty"` + End int64 `json:"end,omitempty"` + Limit int `json:"_limit,omitempty"` + } + + rp := eventReq{Limit: eventLimit} + + switch len(timeRange) { + case 0: + rp.End = time.Now().Unix() * int64(time.Microsecond) + case 1: + rp.Start = timeRange[0].Unix() * int64(time.Microsecond) + rp.End = time.Now().Unix() * int64(time.Microsecond) + case 2: // nolint: gomnd + rp.Start = timeRange[0].Unix() * int64(time.Microsecond) + rp.End = timeRange[1].Unix() * int64(time.Microsecond) + default: + return "", errInvalidTimeRange + } + + params, err := json.Marshal(&rp) + + return string(params), err +} + +// Event describes a UniFi Event. +// API Path: /api/s/default/stat/event. +type Event struct { + IsAdmin FlexBool `json:"is_admin"` + DestPort int `json:"dest_port"` + SrcPort int `json:"src_port"` + Bytes int64 `json:"bytes"` + Duration int64 `json:"duration"` + FlowID int64 `json:"flow_id"` + InnerAlertGID int64 `json:"inner_alert_gid"` + InnerAlertRev int64 `json:"inner_alert_rev"` + InnerAlertSeverity int64 `json:"inner_alert_severity"` + InnerAlertSignatureID int64 `json:"inner_alert_signature_id"` + Time int64 `json:"time"` + Timestamp int64 `json:"timestamp"` + Datetime time.Time `json:"datetime"` + Admin string `json:"admin"` + Ap string `json:"ap"` + ApFrom string `json:"ap_from"` + ApName string `json:"ap_name"` + ApTo string `json:"ap_to"` + AppProto string `json:"app_proto"` + Catname string `json:"catname"` + Channel string `json:"channel"` + ChannelFrom string `json:"channel_from"` + ChannelTo string `json:"channel_to"` + DestIP string `json:"dest_ip"` + DstMac string `json:"dst_mac"` + EventType string `json:"event_type"` + Guest string `json:"guest"` + Gw string `json:"gw"` + GwName string `json:"gw_name"` + Host string `json:"host"` + Hostname string `json:"hostname"` + ID string `json:"_id"` + IP string `json:"ip"` + InIface string `json:"in_iface"` + InnerAlertAction string `json:"inner_alert_action"` + InnerAlertCategory string `json:"inner_alert_category"` + InnerAlertSignature string `json:"inner_alert_signature"` + Key string `json:"key"` + Msg string `json:"msg"` + Network string `json:"network"` + Proto string `json:"proto"` + Radio string `json:"radio"` + RadioFrom string `json:"radio_from"` + RadioTo string `json:"radio_to"` + SiteID string `json:"site_id"` + SiteName string `json:"-"` + SourceName string `json:"-"` + SrcIP string `json:"src_ip"` + SrcMac string `json:"src_mac"` + SrcipASN string `json:"srcipASN"` + SrcipCountry string `json:"srcipCountry"` + Ssid string `json:"ssid"` + Subsystem string `json:"subsystem"` + Sw string `json:"sw"` + SwName string `json:"sw_name"` + UniqueAlertID string `json:"unique_alertid"` + User string `json:"user"` + Usgip string `json:"usgip"` + UsgipASN string `json:"usgipASN"` + UsgipCountry string `json:"usgipCountry"` + DestIPGeo IPGeo `json:"dstipGeo"` + SourceIPGeo IPGeo `json:"srcipGeo"` + USGIPGeo IPGeo `json:"usgipGeo"` +} + +// IPGeo is part of the UniFi Event data. Each event may have up to three of these. +// One for source, one for dest and one for the USG location. +type IPGeo struct { + Asn int64 `json:"asn"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + City string `json:"city"` + ContinentCode string `json:"continent_code"` + CountryCode string `json:"country_code"` + CountryName string `json:"country_name"` + Organization string `json:"organization"` +} diff --git a/core/unifi/ids.go b/core/unifi/ids.go index 1fc707aa..1946a69e 100644 --- a/core/unifi/ids.go +++ b/core/unifi/ids.go @@ -1,152 +1,103 @@ package unifi import ( - "encoding/json" "fmt" - "io/ioutil" - "net/http" "time" - - "github.com/pkg/errors" ) -// IDSList contains a list that contains all of the IDS Events on a controller. -type IDSList []*IDS - // IDS holds an Intrusion Prevention System Event. type IDS struct { - SourceName string `json:"-"` - ID string `json:"_id"` - Archived FlexBool `json:"archived"` - Timestamp int64 `json:"timestamp"` - FlowID int64 `json:"flow_id"` - InIface string `json:"in_iface"` - EventType string `json:"event_type"` - SrcIP string `json:"src_ip"` - SrcMac string `json:"src_mac"` - SrcPort int `json:"src_port,omitempty"` - DestIP string `json:"dest_ip"` - DstMac string `json:"dst_mac"` - DestPort int `json:"dest_port,omitempty"` - Proto string `json:"proto"` - AppProto string `json:"app_proto,omitempty"` - Host string `json:"host"` - Usgip string `json:"usgip"` - UniqueAlertid string `json:"unique_alertid"` - SrcipCountry string `json:"srcipCountry"` - DstipCountry FlexBool `json:"dstipCountry"` - UsgipCountry string `json:"usgipCountry"` - SrcipGeo struct { - ContinentCode string `json:"continent_code"` - CountryCode string `json:"country_code"` - CountryCode3 string `json:"country_code3"` - CountryName string `json:"country_name"` - Region string `json:"region"` - City string `json:"city"` - PostalCode string `json:"postal_code"` - Latitude float64 `json:"latitude"` - Longitude float64 `json:"longitude"` - DmaCode int64 `json:"dma_code"` - AreaCode int64 `json:"area_code"` - } `json:"srcipGeo"` - DstipGeo bool `json:"dstipGeo"` - UsgipGeo struct { - ContinentCode string `json:"continent_code"` - CountryCode string `json:"country_code"` - CountryCode3 string `json:"country_code3"` - CountryName string `json:"country_name"` - Region string `json:"region"` - City string `json:"city"` - PostalCode string `json:"postal_code"` - Latitude float64 `json:"latitude"` - Longitude float64 `json:"longitude"` - DmaCode int64 `json:"dma_code"` - AreaCode int64 `json:"area_code"` - } `json:"usgipGeo"` - SrcipASN string `json:"srcipASN"` - DstipASN string `json:"dstipASN"` - UsgipASN string `json:"usgipASN"` - Catname string `json:"catname"` - InnerAlertAction string `json:"inner_alert_action"` + Archived FlexBool `json:"archived"` + DstipCountry FlexBool `json:"dstipCountry"` + DestPort int `json:"dest_port,omitempty"` + SrcPort int `json:"src_port,omitempty"` + InnerAlertRev int64 `json:"inner_alert_rev"` + InnerAlertSeverity int64 `json:"inner_alert_severity"` InnerAlertGID int64 `json:"inner_alert_gid"` InnerAlertSignatureID int64 `json:"inner_alert_signature_id"` - InnerAlertRev int64 `json:"inner_alert_rev"` - InnerAlertSignature string `json:"inner_alert_signature"` + FlowID int64 `json:"flow_id"` + Time int64 `json:"time"` + Timestamp int64 `json:"timestamp"` + Datetime time.Time `json:"datetime"` + AppProto string `json:"app_proto,omitempty"` + Catname string `json:"catname"` + DestIP string `json:"dest_ip"` + DstMac string `json:"dst_mac"` + DstipASN string `json:"dstipASN"` + EventType string `json:"event_type"` + Host string `json:"host"` + ID string `json:"_id"` + InIface string `json:"in_iface"` + InnerAlertAction string `json:"inner_alert_action"` InnerAlertCategory string `json:"inner_alert_category"` - InnerAlertSeverity int64 `json:"inner_alert_severity"` + InnerAlertSignature string `json:"inner_alert_signature"` Key string `json:"key"` - Subsystem string `json:"subsystem"` + Msg string `json:"msg"` + Proto string `json:"proto"` SiteID string `json:"site_id"` SiteName string `json:"-"` - Time int64 `json:"time"` - Datetime time.Time `json:"datetime"` - Msg string `json:"msg"` - IcmpType int64 `json:"icmp_type,omitempty"` - IcmpCode int64 `json:"icmp_code,omitempty"` + SourceName string `json:"-"` + SrcIP string `json:"src_ip"` + SrcMac string `json:"src_mac"` + SrcipASN string `json:"srcipASN"` + SrcipCountry string `json:"srcipCountry"` + Subsystem string `json:"subsystem"` + UniqueAlertID string `json:"unique_alertid"` + Usgip string `json:"usgip"` + UsgipASN string `json:"usgipASN"` + UsgipCountry string `json:"usgipCountry"` + DestIPGeo IPGeo `json:"dstipGeo"` + SourceIPGeo IPGeo `json:"srcipGeo"` + USGIPGeo IPGeo `json:"usgipGeo"` } -// GetIDS returns Intrusion Detection Systems events. -// Returns all events that happened in site between from and to. -func (u *Unifi) GetIDS(sites Sites, from, to time.Time) ([]*IDS, error) { +// GetIDS returns Intrusion Detection Systems events for a list of Sites. +// timeRange may have a length of 0, 1 or 2. The first time is Start, the second is End. +// Events between start and end are returned. End defaults to time.Now(). +func (u *Unifi) GetIDS(sites []*Site, timeRange ...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) + response, err := u.GetIDSSite(site, timeRange...) if err != nil { return data, err } - for i := range ids { - ids[i].SourceName = u.URL - } - - data = append(data, ids...) + data = append(data, response...) } return data, nil } -// 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) { - var response struct { - Data []*IDS `json:"data"` +// GetIDSSite retreives the Intrusion Detection System Data for a single Site. +// timeRange may have a length of 0, 1 or 2. The first time is Start, the second is End. +// Events between start and end are returned. End defaults to time.Now(). +func (u *Unifi) GetIDSSite(site *Site, timeRange ...time.Time) ([]*IDS, error) { // nolint: dupl + if site == nil || site.Name == "" { + return nil, errNoSiteProvided } - URIpath := fmt.Sprintf(APIIPSEvents, site.Name) + u.DebugLog("Polling Controller for IDS Events, site %s (%s)", site.Name, site.Desc) - params := fmt.Sprintf(`{"start":"%v000","end":"%v000","_limit":50000}`, from.Unix(), to.Unix()) + var ( + path = fmt.Sprintf(APIEventPathIDS, site.Name) + ids struct { + Data []*IDS `json:"data"` + } + ) - req, err := u.UniReq(URIpath, params) - if err != nil { - return nil, err + if params, err := makeEventParams(timeRange...); err != nil { + return ids.Data, err + } else if err = u.GetData(path, &ids, params); err != nil { + return ids.Data, err } - resp, err := u.Do(req) - if err != nil { - return nil, err + for i := range ids.Data { + // Add special SourceName value. + ids.Data[i].SourceName = u.URL + // Add the special "Site Name" to each event. This becomes a Grafana filter somewhere. + ids.Data[i].SiteName = site.Desc + " (" + site.Name + ")" } - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - if resp.StatusCode != http.StatusOK { - return nil, errors.Wrap(errInvalidStatusCode, resp.Status) - } - - if err := json.Unmarshal(body, &response); err != nil { - return nil, err - } - - for i := range response.Data { - response.Data[i].SiteName = site.SiteName - } - - return response.Data, nil + return ids.Data, nil } diff --git a/core/unifi/site.go b/core/unifi/site.go index f521a77e..bfcd46f2 100644 --- a/core/unifi/site.go +++ b/core/unifi/site.go @@ -10,7 +10,7 @@ var ( ) // GetSites returns a list of configured sites on the UniFi controller. -func (u *Unifi) GetSites() (Sites, error) { +func (u *Unifi) GetSites() ([]*Site, error) { var response struct { Data []*Site `json:"data"` } @@ -37,7 +37,7 @@ func (u *Unifi) GetSites() (Sites, error) { } // GetSiteDPI garners dpi data for sites. -func (u *Unifi) GetSiteDPI(sites Sites) ([]*DPITable, error) { +func (u *Unifi) GetSiteDPI(sites []*Site) ([]*DPITable, error) { data := []*DPITable{} for _, site := range sites { @@ -66,9 +66,6 @@ func (u *Unifi) GetSiteDPI(sites Sites) ([]*DPITable, error) { return data, nil } -// Sites is a struct to match Devices and Clients. -type Sites []*Site - // Site represents a site's data. type Site struct { SourceName string `json:"-"` diff --git a/core/unifi/types.go b/core/unifi/types.go index a5a5c504..cd126982 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -19,6 +19,8 @@ var ( const ( // APIStatusPath shows Controller version. APIStatusPath string = "/status" + // APIEventPath contains UniFi Event data. + APIEventPath string = "/api/s/%s/stat/event" // APISiteList is the path to the api site list. APISiteList string = "/api/stat/sites" // APISiteDPI is site DPI data. @@ -33,8 +35,8 @@ const ( APILoginPath string = "/api/login" // APILoginPathNew is how we log into UDM 5.12.55+ APILoginPathNew string = "/api/auth/login" - // APIIPSEvents returns Intrusion Detection Systems Events - APIIPSEvents string = "/api/s/%s/stat/ips/event" + // APIEventPathIDS returns Intrusion Detection/Prevention Systems Events + APIEventPathIDS string = "/api/s/%s/stat/ips/event" // APIPrefixNew is the prefix added to the new API paths; except login. duh. APIPrefixNew string = "/proxy/network" ) From 725a644ea292963f6b0691abd50ca5db2205987b Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sat, 20 Jun 2020 03:38:01 -0700 Subject: [PATCH 145/194] Fix member names --- core/unifi/events.go | 16 ++++++++-------- core/unifi/ids.go | 18 +++++++++--------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/core/unifi/events.go b/core/unifi/events.go index d1982e38..6b9622cc 100644 --- a/core/unifi/events.go +++ b/core/unifi/events.go @@ -120,7 +120,7 @@ type Event struct { ChannelFrom string `json:"channel_from"` ChannelTo string `json:"channel_to"` DestIP string `json:"dest_ip"` - DstMac string `json:"dst_mac"` + DstMAC string `json:"dst_mac"` EventType string `json:"event_type"` Guest string `json:"guest"` Gw string `json:"gw"` @@ -144,18 +144,18 @@ type Event struct { SiteName string `json:"-"` SourceName string `json:"-"` SrcIP string `json:"src_ip"` - SrcMac string `json:"src_mac"` - SrcipASN string `json:"srcipASN"` - SrcipCountry string `json:"srcipCountry"` - Ssid string `json:"ssid"` + SrcMAC string `json:"src_mac"` + SrcIPASN string `json:"srcipASN"` + SrcIPCountry string `json:"srcipCountry"` + SSID string `json:"ssid"` Subsystem string `json:"subsystem"` Sw string `json:"sw"` SwName string `json:"sw_name"` UniqueAlertID string `json:"unique_alertid"` User string `json:"user"` - Usgip string `json:"usgip"` - UsgipASN string `json:"usgipASN"` - UsgipCountry string `json:"usgipCountry"` + USGIP string `json:"usgip"` + USGIPASN string `json:"usgipASN"` + USGIPCountry string `json:"usgipCountry"` DestIPGeo IPGeo `json:"dstipGeo"` SourceIPGeo IPGeo `json:"srcipGeo"` USGIPGeo IPGeo `json:"usgipGeo"` diff --git a/core/unifi/ids.go b/core/unifi/ids.go index 1946a69e..869d3da2 100644 --- a/core/unifi/ids.go +++ b/core/unifi/ids.go @@ -8,7 +8,7 @@ import ( // IDS holds an Intrusion Prevention System Event. type IDS struct { Archived FlexBool `json:"archived"` - DstipCountry FlexBool `json:"dstipCountry"` + DstIPCountry FlexBool `json:"dstipCountry"` DestPort int `json:"dest_port,omitempty"` SrcPort int `json:"src_port,omitempty"` InnerAlertRev int64 `json:"inner_alert_rev"` @@ -22,8 +22,8 @@ type IDS struct { AppProto string `json:"app_proto,omitempty"` Catname string `json:"catname"` DestIP string `json:"dest_ip"` - DstMac string `json:"dst_mac"` - DstipASN string `json:"dstipASN"` + DstMAC string `json:"dst_mac"` + DstIPASN string `json:"dstipASN"` EventType string `json:"event_type"` Host string `json:"host"` ID string `json:"_id"` @@ -38,14 +38,14 @@ type IDS struct { SiteName string `json:"-"` SourceName string `json:"-"` SrcIP string `json:"src_ip"` - SrcMac string `json:"src_mac"` - SrcipASN string `json:"srcipASN"` - SrcipCountry string `json:"srcipCountry"` + SrcMAC string `json:"src_mac"` + SrcIPASN string `json:"srcipASN"` + SrcIPCountry string `json:"srcipCountry"` Subsystem string `json:"subsystem"` UniqueAlertID string `json:"unique_alertid"` - Usgip string `json:"usgip"` - UsgipASN string `json:"usgipASN"` - UsgipCountry string `json:"usgipCountry"` + USGIP string `json:"usgip"` + USGIPASN string `json:"usgipASN"` + USGIPCountry string `json:"usgipCountry"` DestIPGeo IPGeo `json:"dstipGeo"` SourceIPGeo IPGeo `json:"srcipGeo"` USGIPGeo IPGeo `json:"usgipGeo"` From dfb514c27812cdc424086253347f386a4dd86f0f Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sat, 20 Jun 2020 19:30:10 -0700 Subject: [PATCH 146/194] flexint some things --- core/unifi/events.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/unifi/events.go b/core/unifi/events.go index 6b9622cc..d960136b 100644 --- a/core/unifi/events.go +++ b/core/unifi/events.go @@ -99,13 +99,16 @@ type Event struct { IsAdmin FlexBool `json:"is_admin"` DestPort int `json:"dest_port"` SrcPort int `json:"src_port"` - Bytes int64 `json:"bytes"` - Duration int64 `json:"duration"` - FlowID int64 `json:"flow_id"` - InnerAlertGID int64 `json:"inner_alert_gid"` - InnerAlertRev int64 `json:"inner_alert_rev"` - InnerAlertSeverity int64 `json:"inner_alert_severity"` - InnerAlertSignatureID int64 `json:"inner_alert_signature_id"` + Bytes FlexInt `json:"bytes"` + Duration FlexInt `json:"duration"` + FlowID FlexInt `json:"flow_id"` + InnerAlertGID FlexInt `json:"inner_alert_gid"` + InnerAlertRev FlexInt `json:"inner_alert_rev"` + InnerAlertSeverity FlexInt `json:"inner_alert_severity"` + InnerAlertSignatureID FlexInt `json:"inner_alert_signature_id"` + Channel FlexInt `json:"channel"` + ChannelFrom FlexInt `json:"channel_from"` + ChannelTo FlexInt `json:"channel_to"` Time int64 `json:"time"` Timestamp int64 `json:"timestamp"` Datetime time.Time `json:"datetime"` @@ -116,9 +119,6 @@ type Event struct { ApTo string `json:"ap_to"` AppProto string `json:"app_proto"` Catname string `json:"catname"` - Channel string `json:"channel"` - ChannelFrom string `json:"channel_from"` - ChannelTo string `json:"channel_to"` DestIP string `json:"dest_ip"` DstMAC string `json:"dst_mac"` EventType string `json:"event_type"` From 8e20a5038df9d1f4b403f49c4e143d4001c63bd3 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 21 Jun 2020 00:57:46 -0700 Subject: [PATCH 147/194] add example --- core/unifi/examples/events.json | 86 +++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 core/unifi/examples/events.json diff --git a/core/unifi/examples/events.json b/core/unifi/examples/events.json new file mode 100644 index 00000000..1fec2a99 --- /dev/null +++ b/core/unifi/examples/events.json @@ -0,0 +1,86 @@ +{ + "_id": "5ee9e572453d4e00f3c04a7c", + "user": "d8:4c:90:9f:82:5a", + "ssid": "Extra Fast", + "ap": "b4:fb:e4:d2:74:39", + "radio": "na", + "channel": "36", + "key": "EVT_WU_Connected", + "subsystem": "wlan", + "site_id": "574e86994566ffb914a2683c", + "time": 1592386923851, + "datetime": "2020-06-17T09:42:03Z", + "msg": "User[d8:4c:90:9f:82:5a] has connected to AP[b4:fb:e4:d2:74:39] with SSID \"Extra Fast\" on \"channel 36(na)\"" +}, +{ + "_id": "5ee9e56b453d4e00f3c04a7a", + "user": "d8:4c:90:9f:82:5a", + "ssid": "Extra Fast", + "hostname": "dns-ipp", + "ap": "74:83:c2:d4:11:3d", + "duration": 1084, + "bytes": 846171, + "key": "EVT_WU_Disconnected", + "subsystem": "wlan", + "site_id": "574e86994566ffb914a2683c", + "time": 1592386923000, + "datetime": "2020-06-17T09:42:03Z", + "msg": "User[d8:4c:90:9f:82:5a] disconnected from \"Extra Fast\" (18m 4s connected, 826.34K bytes, last AP[74:83:c2:d4:11:3d])" +}, +{ + "_id": "5ee9f7ca453d4e00f3c04b57", + "timestamp": 1592391625, + "flow_id": 1510453960799559, + "in_iface": "eth0", + "event_type": "alert", + "src_ip": "192.168.1.199", + "src_mac": "00:50:b6:96:76:6e", + "src_port": 50447, + "dest_ip": "54.36.xxx.xxx", + "dst_mac": "74:83:c2:1a:35:39", + "dest_port": 80, + "proto": "TCP", + "tx_id": 0, + "app_proto": "http", + "host": "usg-sensor", + "usgip": "67.181.75.120", + "unique_alertid": "1603112333-2020-06-17T04:00:25.225809-0700", + "srcipGeo": [], + "dstipGeo": { + "continent_code": "EU", + "country_code": "FR", + "country_name": "France", + "latitude": 48.8582, + "longitude": 2.3387, + "asn": 16276, + "organization": "OVH SAS" + }, + "dstipCountry": "FR", + "dstipASN": "16276 OVH SAS", + "usgipGeo": { + "continent_code": "NA", + "country_code": "US", + "country_name": "United States", + "city": "Lodi", + "latitude": 38.1228, + "longitude": -121.2543, + "asn": 7922, + "organization": "COMCAST-7922" + }, + "usgipCountry": "US", + "usgipASN": "7922 COMCAST-7922", + "catname": "emerging-malware", + "inner_alert_action": "allowed", + "inner_alert_gid": 1, + "inner_alert_signature_id": 2003337, + "inner_alert_rev": 21, + "inner_alert_signature": "ET MALWARE Suspicious User Agent (Autoupdate)", + "inner_alert_category": "A Network Trojan was Detected", + "inner_alert_severity": 1, + "key": "EVT_IPS_IpsAlert", + "subsystem": "www", + "site_id": "574e86994566ffb914a2683c", + "time": 1592391625000, + "datetime": "2020-06-17T11:00:25Z", + "msg": "IPS Alert 1: A Network Trojan was Detected. Signature ET MALWARE Suspicious User Agent (Autoupdate). From: 192.168.1.199:50447, to: 54.36.xxx.xxx:80, protocol: TCP" +}, From f5b2023207c949b6c74163a3f8453638e738289a Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 21 Jun 2020 23:21:10 -0700 Subject: [PATCH 148/194] deal with empty array --- core/unifi/events.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/core/unifi/events.go b/core/unifi/events.go index d960136b..af2a15fd 100644 --- a/core/unifi/events.go +++ b/core/unifi/events.go @@ -164,6 +164,11 @@ type Event struct { // IPGeo is part of the UniFi Event data. Each event may have up to three of these. // One for source, one for dest and one for the USG location. type IPGeo struct { + GeoIP +} + +// GeoIP is a struct in a struct to deal with weird UniFi output. +type GeoIP struct { Asn int64 `json:"asn"` Latitude float64 `json:"latitude"` Longitude float64 `json:"longitude"` @@ -173,3 +178,13 @@ type IPGeo struct { CountryName string `json:"country_name"` Organization string `json:"organization"` } + +// UnmarshalJSON is required because sometimes the unifi api returns +// an empty array instead of a struct filled with data. +func (v *IPGeo) UnmarshalJSON(data []byte) error { + if string(data) == "[]" { + return nil // it's empty + } + + return json.Unmarshal(data, &v.GeoIP) +} From 90c35a3acc31abd1b4f384a8ef6c0e904e2c1139 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 21 Jun 2020 23:37:39 -0700 Subject: [PATCH 149/194] test --- core/unifi/events.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/unifi/events.go b/core/unifi/events.go index af2a15fd..1c426bdf 100644 --- a/core/unifi/events.go +++ b/core/unifi/events.go @@ -3,6 +3,7 @@ package unifi import ( "encoding/json" "fmt" + "log" "time" ) @@ -90,6 +91,8 @@ func makeEventParams(timeRange ...time.Time) (string, error) { params, err := json.Marshal(&rp) + log.Println(string(params)) + return string(params), err } From 5ab3b447b82c71476316420e269b5a4fed92a886 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 21 Jun 2020 23:59:04 -0700 Subject: [PATCH 150/194] try more? --- core/unifi/events.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/unifi/events.go b/core/unifi/events.go index 1c426bdf..53adad84 100644 --- a/core/unifi/events.go +++ b/core/unifi/events.go @@ -69,12 +69,14 @@ func (u *Unifi) GetSiteEvents(site *Site, timeRange ...time.Time) ([]*Event, err func makeEventParams(timeRange ...time.Time) (string, error) { type eventReq struct { - Start int64 `json:"start,omitempty"` - End int64 `json:"end,omitempty"` - Limit int `json:"_limit,omitempty"` + Start int64 `json:"start,omitempty"` + End int64 `json:"end,omitempty"` + Limit int `json:"_limit,omitempty"` + Within int `json:"within"` + Sort string `json:"_sort"` } - rp := eventReq{Limit: eventLimit} + rp := eventReq{Limit: eventLimit, Sort: "-time", Within: 1} switch len(timeRange) { case 0: From c05f22a3adf781d28a611bf797745ae59c6032bc Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Mon, 22 Jun 2020 00:19:55 -0700 Subject: [PATCH 151/194] seems partially working --- core/unifi/events.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/unifi/events.go b/core/unifi/events.go index 53adad84..42304cde 100644 --- a/core/unifi/events.go +++ b/core/unifi/events.go @@ -3,7 +3,6 @@ package unifi import ( "encoding/json" "fmt" - "log" "time" ) @@ -93,8 +92,6 @@ func makeEventParams(timeRange ...time.Time) (string, error) { params, err := json.Marshal(&rp) - log.Println(string(params)) - return string(params), err } From 822f6d23d3b011b9ee3f5f030ab8c310b1cf3af4 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Mon, 22 Jun 2020 00:38:24 -0700 Subject: [PATCH 152/194] correct the interface --- core/unifi/events.go | 55 +++++++++++--------------------------------- core/unifi/ids.go | 31 ++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/core/unifi/events.go b/core/unifi/events.go index 42304cde..26d9f089 100644 --- a/core/unifi/events.go +++ b/core/unifi/events.go @@ -15,14 +15,12 @@ const ( eventLimit = 50000 ) -// GetEvents returns a response full of UniFi Events from multiple sites. -// timeRange may have a length of 0, 1 or 2. The first time is Start, the second is End. -// Events between start and end are returned. End defaults to time.Now(). -func (u *Unifi) GetEvents(sites []*Site, timeRange ...time.Time) ([]*Event, error) { +// GetEvents returns a response full of UniFi Events for the last 1 hour from multiple sites. +func (u *Unifi) GetEvents(sites []*Site, hours time.Duration) ([]*Event, error) { data := make([]*Event, 0) for _, site := range sites { - response, err := u.GetSiteEvents(site, timeRange...) + response, err := u.GetSiteEvents(site, hours) if err != nil { return data, err } @@ -33,26 +31,28 @@ func (u *Unifi) GetEvents(sites []*Site, timeRange ...time.Time) ([]*Event, erro return data, nil } -// GetSiteEvents retreives the events from a single site. -// timeRange may have a length of 0, 1 or 2. The first time is Start, the second is End. -// Events between start and end are returned. End defaults to time.Now(). -func (u *Unifi) GetSiteEvents(site *Site, timeRange ...time.Time) ([]*Event, error) { // nolint: dupl +// GetSiteEvents retrieves the last 1 hour's worth of events from a single site. +func (u *Unifi) GetSiteEvents(site *Site, hours time.Duration) ([]*Event, error) { if site == nil || site.Name == "" { return nil, errNoSiteProvided } + if hours < time.Hour { + hours = time.Hour + } + u.DebugLog("Polling Controller, retreiving UniFi Events, site %s (%s)", site.Name, site.Desc) var ( - path = fmt.Sprintf(APIEventPath, site.Name) + path = fmt.Sprintf(APIEventPath, site.Name) + params = fmt.Sprintf(`{"_limit":%d,"within":%d,"_sort":"-time"}}`, + eventLimit, int(hours.Round(time.Hour).Hours())) event struct { Data []*Event `json:"data"` } ) - if params, err := makeEventParams(timeRange...); err != nil { - return event.Data, err - } else if err = u.GetData(path, &event, params); err != nil { + if err := u.GetData(path, &event, params); err != nil { return event.Data, err } @@ -66,35 +66,6 @@ func (u *Unifi) GetSiteEvents(site *Site, timeRange ...time.Time) ([]*Event, err return event.Data, nil } -func makeEventParams(timeRange ...time.Time) (string, error) { - type eventReq struct { - Start int64 `json:"start,omitempty"` - End int64 `json:"end,omitempty"` - Limit int `json:"_limit,omitempty"` - Within int `json:"within"` - Sort string `json:"_sort"` - } - - rp := eventReq{Limit: eventLimit, Sort: "-time", Within: 1} - - switch len(timeRange) { - case 0: - rp.End = time.Now().Unix() * int64(time.Microsecond) - case 1: - rp.Start = timeRange[0].Unix() * int64(time.Microsecond) - rp.End = time.Now().Unix() * int64(time.Microsecond) - case 2: // nolint: gomnd - rp.Start = timeRange[0].Unix() * int64(time.Microsecond) - rp.End = timeRange[1].Unix() * int64(time.Microsecond) - default: - return "", errInvalidTimeRange - } - - params, err := json.Marshal(&rp) - - return string(params), err -} - // Event describes a UniFi Event. // API Path: /api/s/default/stat/event. type Event struct { diff --git a/core/unifi/ids.go b/core/unifi/ids.go index 869d3da2..9b75c655 100644 --- a/core/unifi/ids.go +++ b/core/unifi/ids.go @@ -1,6 +1,7 @@ package unifi import ( + "encoding/json" "fmt" "time" ) @@ -72,7 +73,7 @@ func (u *Unifi) GetIDS(sites []*Site, timeRange ...time.Time) ([]*IDS, error) { // GetIDSSite retreives the Intrusion Detection System Data for a single Site. // timeRange may have a length of 0, 1 or 2. The first time is Start, the second is End. // Events between start and end are returned. End defaults to time.Now(). -func (u *Unifi) GetIDSSite(site *Site, timeRange ...time.Time) ([]*IDS, error) { // nolint: dupl +func (u *Unifi) GetIDSSite(site *Site, timeRange ...time.Time) ([]*IDS, error) { if site == nil || site.Name == "" { return nil, errNoSiteProvided } @@ -101,3 +102,31 @@ func (u *Unifi) GetIDSSite(site *Site, timeRange ...time.Time) ([]*IDS, error) { return ids.Data, nil } + +func makeEventParams(timeRange ...time.Time) (string, error) { + type eventReq struct { + Start int64 `json:"start,omitempty"` + End int64 `json:"end,omitempty"` + Limit int `json:"_limit,omitempty"` + Sort string `json:"_sort"` + } + + rp := eventReq{Limit: eventLimit, Sort: "-time"} + + switch len(timeRange) { + case 0: + rp.End = time.Now().Unix() * int64(time.Microsecond) + case 1: + rp.Start = timeRange[0].Unix() * int64(time.Microsecond) + rp.End = time.Now().Unix() * int64(time.Microsecond) + case 2: // nolint: gomnd + rp.Start = timeRange[0].Unix() * int64(time.Microsecond) + rp.End = timeRange[1].Unix() * int64(time.Microsecond) + default: + return "", errInvalidTimeRange + } + + params, err := json.Marshal(&rp) + + return string(params), err +} From 20310d81bf9bd6cc476a474b8d34704f74844934 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Mon, 22 Jun 2020 01:39:19 -0700 Subject: [PATCH 153/194] add small test --- core/unifi/events_test.go | 20 ++++++++++++++++++++ core/unifi/types_test.go | 13 +++++++------ 2 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 core/unifi/events_test.go diff --git a/core/unifi/events_test.go b/core/unifi/events_test.go new file mode 100644 index 00000000..ea3f337a --- /dev/null +++ b/core/unifi/events_test.go @@ -0,0 +1,20 @@ +package unifi_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/unifi-poller/unifi" +) + +func TestIPGeoUnmarshalJSON(t *testing.T) { + t.Parallel() + + a := assert.New(t) + i := &unifi.IPGeo{} + + a.Nil(i.UnmarshalJSON([]byte(`[]`))) + a.EqualValues(0, i.Asn) + a.Nil(i.UnmarshalJSON([]byte(`{"asn": 123}`))) + a.EqualValues(123, i.Asn) +} diff --git a/core/unifi/types_test.go b/core/unifi/types_test.go index 118662e1..bbf13a13 100644 --- a/core/unifi/types_test.go +++ b/core/unifi/types_test.go @@ -1,10 +1,11 @@ -package unifi // nolint: testpackage +package unifi_test import ( "encoding/json" "testing" "github.com/stretchr/testify/assert" + "github.com/unifi-poller/unifi" ) func TestFlexInt(t *testing.T) { @@ -13,11 +14,11 @@ func TestFlexInt(t *testing.T) { five, seven := 5, 7 var r struct { - Five FlexInt `json:"five"` - Seven FlexInt `json:"seven"` - Auto FlexInt `json:"auto"` - Channel FlexInt `json:"channel"` - Nil FlexInt `json:"nil"` + Five unifi.FlexInt `json:"five"` + Seven unifi.FlexInt `json:"seven"` + Auto unifi.FlexInt `json:"auto"` + Channel unifi.FlexInt `json:"channel"` + Nil unifi.FlexInt `json:"nil"` } // test unmarshalling the custom type three times with different values. From 724cc6fdfd1432fd5c86de1433fb4e77defcba6e Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Tue, 23 Jun 2020 01:08:00 -0700 Subject: [PATCH 154/194] add debug message --- core/unifi/site.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/unifi/site.go b/core/unifi/site.go index bfcd46f2..7939cb06 100644 --- a/core/unifi/site.go +++ b/core/unifi/site.go @@ -54,7 +54,8 @@ func (u *Unifi) GetSiteDPI(sites []*Site) ([]*DPITable, error) { if l := len(response.Data); l > 1 { return nil, errDPIDataBug - } else if l != 1 { + } else if l == 0 { + u.DebugLog("Site DPI data missing! Is DPI enabled in UniFi controller? Site %s (%s) ", site.Name, site.Desc) continue } From f32bebec6123c13cc9fc6f0689e1fde4091991a4 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Wed, 24 Jun 2020 03:11:33 -0700 Subject: [PATCH 155/194] Sort events by date --- core/unifi/events.go | 23 ++++++++++++++++++++++- core/unifi/ids.go | 22 +++++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/core/unifi/events.go b/core/unifi/events.go index 26d9f089..8b7da4da 100644 --- a/core/unifi/events.go +++ b/core/unifi/events.go @@ -3,6 +3,7 @@ package unifi import ( "encoding/json" "fmt" + "sort" "time" ) @@ -48,7 +49,7 @@ func (u *Unifi) GetSiteEvents(site *Site, hours time.Duration) ([]*Event, error) params = fmt.Sprintf(`{"_limit":%d,"within":%d,"_sort":"-time"}}`, eventLimit, int(hours.Round(time.Hour).Hours())) event struct { - Data []*Event `json:"data"` + Data events `json:"data"` } ) @@ -63,9 +64,14 @@ func (u *Unifi) GetSiteEvents(site *Site, hours time.Duration) ([]*Event, error) event.Data[i].SiteName = site.Desc + " (" + site.Name + ")" } + sort.Sort(event.Data) + return event.Data, nil } +// Events satisfied the sort.Interface. +type events []*Event + // Event describes a UniFi Event. // API Path: /api/s/default/stat/event. type Event struct { @@ -152,6 +158,21 @@ type GeoIP struct { Organization string `json:"organization"` } +// Len satisfies sort.Interface. +func (e events) Len() int { + return len(e) +} + +// Swap satisfies sort.Interface. +func (e events) Swap(i, j int) { + e[i], e[j] = e[j], e[i] +} + +// Less satisfies sort.Interface. Sort our list by date/time. +func (e events) Less(i, j int) bool { + return e[i].Datetime.Before(e[j].Datetime) +} + // UnmarshalJSON is required because sometimes the unifi api returns // an empty array instead of a struct filled with data. func (v *IPGeo) UnmarshalJSON(data []byte) error { diff --git a/core/unifi/ids.go b/core/unifi/ids.go index 9b75c655..359d7744 100644 --- a/core/unifi/ids.go +++ b/core/unifi/ids.go @@ -3,9 +3,12 @@ package unifi import ( "encoding/json" "fmt" + "sort" "time" ) +type idsList []*IDS + // IDS holds an Intrusion Prevention System Event. type IDS struct { Archived FlexBool `json:"archived"` @@ -52,6 +55,21 @@ type IDS struct { USGIPGeo IPGeo `json:"usgipGeo"` } +// Len satisfies sort.Interface. +func (e idsList) Len() int { + return len(e) +} + +// Swap satisfies sort.Interface. +func (e idsList) Swap(i, j int) { + e[i], e[j] = e[j], e[i] +} + +// Less satisfies sort.Interface. Sort our list by Datetime. +func (e idsList) Less(i, j int) bool { + return e[i].Datetime.Before(e[j].Datetime) +} + // GetIDS returns Intrusion Detection Systems events for a list of Sites. // timeRange may have a length of 0, 1 or 2. The first time is Start, the second is End. // Events between start and end are returned. End defaults to time.Now(). @@ -83,7 +101,7 @@ func (u *Unifi) GetIDSSite(site *Site, timeRange ...time.Time) ([]*IDS, error) { var ( path = fmt.Sprintf(APIEventPathIDS, site.Name) ids struct { - Data []*IDS `json:"data"` + Data idsList `json:"data"` } ) @@ -100,6 +118,8 @@ func (u *Unifi) GetIDSSite(site *Site, timeRange ...time.Time) ([]*IDS, error) { ids.Data[i].SiteName = site.Desc + " (" + site.Name + ")" } + sort.Sort(ids.Data) + return ids.Data, nil } From 8be479e69ef56ce9ffefe1cf82bdb8a286ca50f4 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Thu, 25 Jun 2020 02:04:27 -0700 Subject: [PATCH 156/194] A bit of cleanup --- core/unifi/events.go | 34 +++++++++++++++++++++++++--------- core/unifi/ids.go | 40 ++++++++++++++++++++-------------------- core/unifi/types.go | 4 ++++ 3 files changed, 49 insertions(+), 29 deletions(-) diff --git a/core/unifi/events.go b/core/unifi/events.go index 8b7da4da..1f5f8458 100644 --- a/core/unifi/events.go +++ b/core/unifi/events.go @@ -69,9 +69,6 @@ func (u *Unifi) GetSiteEvents(site *Site, hours time.Duration) ([]*Event, error) return event.Data, nil } -// Events satisfied the sort.Interface. -type events []*Event - // Event describes a UniFi Event. // API Path: /api/s/default/stat/event. type Event struct { @@ -143,11 +140,6 @@ type Event struct { // IPGeo is part of the UniFi Event data. Each event may have up to three of these. // One for source, one for dest and one for the USG location. type IPGeo struct { - GeoIP -} - -// GeoIP is a struct in a struct to deal with weird UniFi output. -type GeoIP struct { Asn int64 `json:"asn"` Latitude float64 `json:"latitude"` Longitude float64 `json:"longitude"` @@ -158,6 +150,9 @@ type GeoIP struct { Organization string `json:"organization"` } +// Events satisfied the sort.Interface. +type events []*Event + // Len satisfies sort.Interface. func (e events) Len() int { return len(e) @@ -180,5 +175,26 @@ func (v *IPGeo) UnmarshalJSON(data []byte) error { return nil // it's empty } - return json.Unmarshal(data, &v.GeoIP) + g := struct { + Asn int64 `json:"asn"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + City string `json:"city"` + ContinentCode string `json:"continent_code"` + CountryCode string `json:"country_code"` + CountryName string `json:"country_name"` + Organization string `json:"organization"` + }{} + + err := json.Unmarshal(data, &g) + v.Asn = g.Asn + v.Latitude = g.Latitude + v.Longitude = g.Longitude + v.City = g.City + v.ContinentCode = g.ContinentCode + v.CountryCode = g.CountryCode + v.CountryName = g.CountryName + v.Organization = g.Organization + + return err } diff --git a/core/unifi/ids.go b/core/unifi/ids.go index 359d7744..0140e157 100644 --- a/core/unifi/ids.go +++ b/core/unifi/ids.go @@ -7,19 +7,16 @@ import ( "time" ) -type idsList []*IDS - // IDS holds an Intrusion Prevention System Event. type IDS struct { Archived FlexBool `json:"archived"` - DstIPCountry FlexBool `json:"dstipCountry"` DestPort int `json:"dest_port,omitempty"` SrcPort int `json:"src_port,omitempty"` + FlowID int64 `json:"flow_id"` InnerAlertRev int64 `json:"inner_alert_rev"` InnerAlertSeverity int64 `json:"inner_alert_severity"` InnerAlertGID int64 `json:"inner_alert_gid"` InnerAlertSignatureID int64 `json:"inner_alert_signature_id"` - FlowID int64 `json:"flow_id"` Time int64 `json:"time"` Timestamp int64 `json:"timestamp"` Datetime time.Time `json:"datetime"` @@ -28,6 +25,7 @@ type IDS struct { DestIP string `json:"dest_ip"` DstMAC string `json:"dst_mac"` DstIPASN string `json:"dstipASN"` + DstIPCountry string `json:"dstipCountry"` EventType string `json:"event_type"` Host string `json:"host"` ID string `json:"_id"` @@ -42,9 +40,9 @@ type IDS struct { SiteName string `json:"-"` SourceName string `json:"-"` SrcIP string `json:"src_ip"` - SrcMAC string `json:"src_mac"` SrcIPASN string `json:"srcipASN"` SrcIPCountry string `json:"srcipCountry"` + SrcMAC string `json:"src_mac"` Subsystem string `json:"subsystem"` UniqueAlertID string `json:"unique_alertid"` USGIP string `json:"usgip"` @@ -55,21 +53,6 @@ type IDS struct { USGIPGeo IPGeo `json:"usgipGeo"` } -// Len satisfies sort.Interface. -func (e idsList) Len() int { - return len(e) -} - -// Swap satisfies sort.Interface. -func (e idsList) Swap(i, j int) { - e[i], e[j] = e[j], e[i] -} - -// Less satisfies sort.Interface. Sort our list by Datetime. -func (e idsList) Less(i, j int) bool { - return e[i].Datetime.Before(e[j].Datetime) -} - // GetIDS returns Intrusion Detection Systems events for a list of Sites. // timeRange may have a length of 0, 1 or 2. The first time is Start, the second is End. // Events between start and end are returned. End defaults to time.Now(). @@ -150,3 +133,20 @@ func makeEventParams(timeRange ...time.Time) (string, error) { return string(params), err } + +type idsList []*IDS + +// Len satisfies sort.Interface. +func (e idsList) Len() int { + return len(e) +} + +// Swap satisfies sort.Interface. +func (e idsList) Swap(i, j int) { + e[i], e[j] = e[j], e[i] +} + +// Less satisfies sort.Interface. Sort our list by Datetime. +func (e idsList) Less(i, j int) bool { + return e[i].Datetime.Before(e[j].Datetime) +} diff --git a/core/unifi/types.go b/core/unifi/types.go index cd126982..77c46b15 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -37,8 +37,12 @@ const ( APILoginPathNew string = "/api/auth/login" // APIEventPathIDS returns Intrusion Detection/Prevention Systems Events APIEventPathIDS string = "/api/s/%s/stat/ips/event" + // APIEventPathAlarms contains the site alarms. + APIEventPathAlarms string = "/api/s/%s/list/alarm" // APIPrefixNew is the prefix added to the new API paths; except login. duh. APIPrefixNew string = "/proxy/network" + // APIAnomaliesPath returns site anomalies. + APIAnomaliesPath string = "/api/s/%s/stat/anomalies" ) // path returns the correct api path based on the new variable. From 0412e7ebcde871923678d952a77fa7e31c616d55 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Thu, 25 Jun 2020 02:04:39 -0700 Subject: [PATCH 157/194] add alarms and anomalies --- core/unifi/alarms.go | 120 +++++++++++++++++++++++++++++++++++++ core/unifi/anomalies.go | 130 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 250 insertions(+) create mode 100644 core/unifi/alarms.go create mode 100644 core/unifi/anomalies.go diff --git a/core/unifi/alarms.go b/core/unifi/alarms.go new file mode 100644 index 00000000..63c558e9 --- /dev/null +++ b/core/unifi/alarms.go @@ -0,0 +1,120 @@ +package unifi + +import ( + "fmt" + "sort" + "time" +) + +type Alarm struct { + Archived FlexBool `json:"archived"` + DestPort int `json:"dest_port"` + SrcPort int `json:"src_port"` + FlowID int64 `json:"flow_id"` + InnerAlertGID int64 `json:"inner_alert_gid"` + InnerAlertRev int64 `json:"inner_alert_rev"` + InnerAlertSeverity int64 `json:"inner_alert_severity"` + InnerAlertSignatureID int64 `json:"inner_alert_signature_id"` + Time int64 `json:"time"` + Timestamp int64 `json:"timestamp"` + Datetime time.Time `json:"datetime"` + HandledTime time.Time `json:"handled_time,omitempty"` + AppProto string `json:"app_proto,omitempty"` + Catname string `json:"catname"` + DestIP string `json:"dest_ip"` + DstMAC string `json:"dst_mac"` + DstIPASN string `json:"dstipASN,omitempty"` + DstIPCountry string `json:"dstipCountry,omitempty"` + EventType string `json:"event_type"` + HandledAdminID string `json:"handled_admin_id,omitempty"` + Host string `json:"host"` + ID string `json:"_id"` + InIface string `json:"in_iface"` + InnerAlertAction string `json:"inner_alert_action"` + InnerAlertCategory string `json:"inner_alert_category"` + InnerAlertSignature string `json:"inner_alert_signature"` + Key string `json:"key"` + Msg string `json:"msg"` + Proto string `json:"proto"` + SiteID string `json:"site_id"` + SiteName string `json:"-"` + SourceName string `json:"-"` + SrcIP string `json:"src_ip"` + SrcIPASN string `json:"srcipASN,omitempty"` + SrcIPCountry string `json:"srcipCountry,omitempty"` + SrcMAC string `json:"src_mac"` + Subsystem string `json:"subsystem"` + UniqueAlertID string `json:"unique_alertid"` + USGIP string `json:"usgip"` + USGIPASN string `json:"usgipASN"` + USGIPCountry string `json:"usgipCountry"` + TxID FlexInt `json:"tx_id,omitempty"` + DestIPGeo IPGeo `json:"dstipGeo"` + SourceIPGeo IPGeo `json:"usgipGeo"` + USGIPGeo IPGeo `json:"srcipGeo,omitempty"` +} + +// GetAlarms returns Alarms for a list of Sites. +func (u *Unifi) GetAlarms(sites []*Site) ([]*Alarm, error) { + data := []*Alarm{} + + for _, site := range sites { + response, err := u.GetAlarmsSite(site) + if err != nil { + return data, err + } + + data = append(data, response...) + } + + return data, nil +} + +// GetAlarmsSite retreives the Alarms for a single Site. +func (u *Unifi) GetAlarmsSite(site *Site) ([]*Alarm, error) { + if site == nil || site.Name == "" { + return nil, errNoSiteProvided + } + + u.DebugLog("Polling Controller for Alarms, site %s (%s)", site.Name, site.Desc) + + var ( + path = fmt.Sprintf(APIEventPathAlarms, site.Name) + alarms struct { + Data alarms `json:"data"` + } + ) + + if err := u.GetData(path, &alarms, ""); err != nil { + return alarms.Data, err + } + + for i := range alarms.Data { + // Add special SourceName value. + alarms.Data[i].SourceName = u.URL + // Add the special "Site Name" to each event. This becomes a Grafana filter somewhere. + alarms.Data[i].SiteName = site.Desc + " (" + site.Name + ")" + } + + sort.Sort(alarms.Data) + + return alarms.Data, nil +} + +// alarms satisfies the sort.Sort Interface. +type alarms []*Alarm + +// Len satisfies sort.Interface. +func (a alarms) Len() int { + return len(a) +} + +// Swap satisfies sort.Interface. +func (a alarms) Swap(i, j int) { + a[i], a[j] = a[j], a[i] +} + +// Less satisfies sort.Interface. Sort our list by Datetime. +func (a alarms) Less(i, j int) bool { + return a[i].Datetime.Before(a[j].Datetime) +} diff --git a/core/unifi/anomalies.go b/core/unifi/anomalies.go new file mode 100644 index 00000000..9f7de0e2 --- /dev/null +++ b/core/unifi/anomalies.go @@ -0,0 +1,130 @@ +package unifi + +import ( + "fmt" + "sort" + "strconv" + "strings" + "time" +) + +// anomaly is the type UniFi returns, but not the type this library returns. +type anomaly struct { + Anomaly string `json:"anomaly"` + MAC string `json:"mac"` + Timestamps []int64 `json:"timestamps"` +} + +// Anomaly is the reformatted data type that this library returns. +type Anomaly struct { + Datetime time.Time + SourceName string + SiteName string + Anomaly string + DeviceMAC string + // DeviceName string // we do not have this.... +} + +// GetAnomalies returns Anomalies for a list of Sites. +func (u *Unifi) GetAnomalies(sites []*Site, timeRange ...time.Time) ([]*Anomaly, error) { + data := []*Anomaly{} + + for _, site := range sites { + response, err := u.GetAnomaliesSite(site, timeRange...) + if err != nil { + return data, err + } + + data = append(data, response...) + } + + return data, nil +} + +// GetAnomaliesSite retreives the Anomalies for a single Site. +func (u *Unifi) GetAnomaliesSite(site *Site, timeRange ...time.Time) ([]*Anomaly, error) { + if site == nil || site.Name == "" { + return nil, errNoSiteProvided + } + + u.DebugLog("Polling Controller for Anomalies, site %s (%s)", site.Name, site.Desc) + + var ( + path = fmt.Sprintf(APIAnomaliesPath, site.Name) + anomalies = anomalies{} + data struct { + Data []*anomaly `json:"data"` + } + ) + + if params, err := makeAnomalyParams("hourly", timeRange...); err != nil { + return anomalies, err + } else if err := u.GetData(path+params, &data, ""); err != nil { + return anomalies, err + } + + for _, d := range data.Data { + for _, ts := range d.Timestamps { + anomalies = append(anomalies, &Anomaly{ + Datetime: time.Unix(ts/int64(time.Microsecond), 0), + SourceName: u.URL, + SiteName: site.Desc + " (" + site.Name + ")", + Anomaly: d.Anomaly, + DeviceMAC: d.MAC, + // DeviceName: d.Anomaly, + }) + } + } + + sort.Sort(anomalies) + + return anomalies, nil +} + +// anomalies satisfies the sort.Sort interface. +type anomalies []*Anomaly + +// Len satisfies sort.Interface. +func (a anomalies) Len() int { + return len(a) +} + +// Swap satisfies sort.Interface. +func (a anomalies) Swap(i, j int) { + a[i], a[j] = a[j], a[i] +} + +// Less satisfies sort.Interface. Sort our list by Datetime. +func (a anomalies) Less(i, j int) bool { + return a[i].Datetime.Before(a[j].Datetime) +} + +func makeAnomalyParams(scale string, timeRange ...time.Time) (string, error) { + out := []string{} + + if scale != "" { + out = append(out, "scale="+scale) + } + + switch len(timeRange) { + case 0: + end := time.Now().Unix() * int64(time.Microsecond) + out = append(out, "end="+strconv.FormatInt(end, 10)) + case 1: + start := timeRange[0].Unix() * int64(time.Microsecond) + end := time.Now().Unix() * int64(time.Microsecond) + out = append(out, "end="+strconv.FormatInt(end, 10), "start="+strconv.FormatInt(start, 10)) + case 2: // nolint: gomnd + start := timeRange[0].Unix() * int64(time.Microsecond) + end := timeRange[1].Unix() * int64(time.Microsecond) + out = append(out, "end="+strconv.FormatInt(end, 10), "start="+strconv.FormatInt(start, 10)) + default: + return "", errInvalidTimeRange + } + + if len(out) == 0 { + return "", nil + } + + return "?" + strings.Join(out, "&"), nil +} From ff145d9f3f59fe8875080091b7d13265d2196311 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 28 Jun 2020 04:43:38 -0700 Subject: [PATCH 158/194] go get -u --- core/unifi/go.mod | 4 ++ core/unifi/go.sum | 159 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) diff --git a/core/unifi/go.mod b/core/unifi/go.mod index 9e2e4827..d25c6c8f 100644 --- a/core/unifi/go.mod +++ b/core/unifi/go.mod @@ -6,6 +6,10 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/pkg/errors v0.9.1 github.com/pmezard/go-difflib v1.0.0 + github.com/prometheus/client_golang v1.7.1 // indirect github.com/stretchr/testify v1.4.0 + github.com/unifi-poller/webserver v0.0.0-20200627075455-333ea2dcdb1a // indirect golang.org/x/net v0.0.0-20200602114024-627f9648deb9 + golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae // indirect + google.golang.org/protobuf v1.25.0 // indirect ) diff --git a/core/unifi/go.sum b/core/unifi/go.sum index c8eb7c3d..dbb6e5c9 100644 --- a/core/unifi/go.sum +++ b/core/unifi/go.sum @@ -1,21 +1,180 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A= +github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= +github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.1.1 h1:/ZKcW+ixpq2dOl4yeH4qvACNXnkiDCp5e/F5Tq07X7o= +github.com/prometheus/procfs v0.1.1/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/unifi-poller/poller v0.0.8-0.20200626082958-a9a7092a5684 h1:r1B8GoI47czgGnQ7WY89qlSKqSE1d1pQmcLfdXVW/+Y= +github.com/unifi-poller/poller v0.0.8-0.20200626082958-a9a7092a5684/go.mod h1:pJ/MeYaakLOOpbyc7s4zeZ92UzNK/rir5jkA7t5jIjo= +github.com/unifi-poller/webserver v0.0.0-20200627075455-333ea2dcdb1a h1:8dEktb8K6EpCEXzrduudEfWsdesmUXGaXPCVFyCxzoo= +github.com/unifi-poller/webserver v0.0.0-20200627075455-333ea2dcdb1a/go.mod h1:0kv/xON8tow9YE0ZmODW0Migxx2Q7vZZ+c5OVTW/kfU= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-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/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200610111108-226ff32320da h1:bGb80FudwxpeucJUjPYJXuJ8Hk91vNtfvrymzwiei38= +golang.org/x/sys v0.0.0-20200610111108-226ff32320da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golift.io/cnfg v0.0.5 h1:HnMU8Z9C/igKvir1dqaHx5BPuNGZrp99FCtdJyP2Z4I= +golift.io/cnfg v0.0.5/go.mod h1:ScFDIJg/rJGHbRaed/i7g1lBhywEjB0JiP2uZr3xC3A= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From b9e59e9eb958075d0189b46388ca7c55ed91ff88 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 28 Jun 2020 06:19:46 -0700 Subject: [PATCH 159/194] fix --- core/unifi/go.mod | 1 - core/unifi/go.sum | 4 ---- 2 files changed, 5 deletions(-) diff --git a/core/unifi/go.mod b/core/unifi/go.mod index d25c6c8f..d6569d63 100644 --- a/core/unifi/go.mod +++ b/core/unifi/go.mod @@ -8,7 +8,6 @@ require ( github.com/pmezard/go-difflib v1.0.0 github.com/prometheus/client_golang v1.7.1 // indirect github.com/stretchr/testify v1.4.0 - github.com/unifi-poller/webserver v0.0.0-20200627075455-333ea2dcdb1a // indirect golang.org/x/net v0.0.0-20200602114024-627f9648deb9 golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae // indirect google.golang.org/protobuf v1.25.0 // indirect diff --git a/core/unifi/go.sum b/core/unifi/go.sum index dbb6e5c9..ce3eb646 100644 --- a/core/unifi/go.sum +++ b/core/unifi/go.sum @@ -99,10 +99,6 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/unifi-poller/poller v0.0.8-0.20200626082958-a9a7092a5684 h1:r1B8GoI47czgGnQ7WY89qlSKqSE1d1pQmcLfdXVW/+Y= -github.com/unifi-poller/poller v0.0.8-0.20200626082958-a9a7092a5684/go.mod h1:pJ/MeYaakLOOpbyc7s4zeZ92UzNK/rir5jkA7t5jIjo= -github.com/unifi-poller/webserver v0.0.0-20200627075455-333ea2dcdb1a h1:8dEktb8K6EpCEXzrduudEfWsdesmUXGaXPCVFyCxzoo= -github.com/unifi-poller/webserver v0.0.0-20200627075455-333ea2dcdb1a/go.mod h1:0kv/xON8tow9YE0ZmODW0Migxx2Q7vZZ+c5OVTW/kfU= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= From 566b14005f9798c6500e67a19326510c135731e0 Mon Sep 17 00:00:00 2001 From: davidnewhall2 Date: Sun, 28 Jun 2020 14:33:09 -0700 Subject: [PATCH 160/194] update mod --- core/unifi/go.mod | 5 +- core/unifi/go.sum | 168 ++-------------------------------------------- 2 files changed, 6 insertions(+), 167 deletions(-) diff --git a/core/unifi/go.mod b/core/unifi/go.mod index d6569d63..83d311fb 100644 --- a/core/unifi/go.mod +++ b/core/unifi/go.mod @@ -6,9 +6,6 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/pkg/errors v0.9.1 github.com/pmezard/go-difflib v1.0.0 - github.com/prometheus/client_golang v1.7.1 // indirect github.com/stretchr/testify v1.4.0 - golang.org/x/net v0.0.0-20200602114024-627f9648deb9 - golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae // indirect - google.golang.org/protobuf v1.25.0 // indirect + golang.org/x/net v0.0.0-20200625001655-4c5254603344 ) diff --git a/core/unifi/go.sum b/core/unifi/go.sum index ce3eb646..d8a6dd57 100644 --- a/core/unifi/go.sum +++ b/core/unifi/go.sum @@ -1,176 +1,18 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= -github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A= -github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= -github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.1.1 h1:/ZKcW+ixpq2dOl4yeH4qvACNXnkiDCp5e/F5Tq07X7o= -github.com/prometheus/procfs v0.1.1/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-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/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200610111108-226ff32320da h1:bGb80FudwxpeucJUjPYJXuJ8Hk91vNtfvrymzwiei38= -golang.org/x/sys v0.0.0-20200610111108-226ff32320da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golift.io/cnfg v0.0.5 h1:HnMU8Z9C/igKvir1dqaHx5BPuNGZrp99FCtdJyP2Z4I= -golift.io/cnfg v0.0.5/go.mod h1:ScFDIJg/rJGHbRaed/i7g1lBhywEjB0JiP2uZr3xC3A= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From b7f8e3a98e71384fddddce7cd0efab5b25ce113b Mon Sep 17 00:00:00 2001 From: Andrew Regner Date: Tue, 8 Sep 2020 00:16:26 -0700 Subject: [PATCH 161/194] add networks --- core/unifi/.gitignore | 1 + core/unifi/networks.go | 74 ++++++++++++++++++++++++++++++++++++++++++ core/unifi/types.go | 2 ++ 3 files changed, 77 insertions(+) create mode 100644 core/unifi/networks.go diff --git a/core/unifi/.gitignore b/core/unifi/.gitignore index 61ead866..6d292b19 100644 --- a/core/unifi/.gitignore +++ b/core/unifi/.gitignore @@ -1 +1,2 @@ /vendor +*.swp diff --git a/core/unifi/networks.go b/core/unifi/networks.go new file mode 100644 index 00000000..23237c19 --- /dev/null +++ b/core/unifi/networks.go @@ -0,0 +1,74 @@ +package unifi + +import ( + "encoding/json" + "fmt" +) + +// GetNetworks returns a response full of network data from the UniFi Controller. +func (u *Unifi) GetNetworks(sites []*Site) ([]Network, error) { + networks := make([]Network, 0) + + for _, site := range sites { + var response struct { + Data []json.RawMessage `json:"data"` + } + + networkPath := fmt.Sprintf(APINetworkPath, site.Name) + if err := u.GetData(networkPath, &response); err != nil { + return nil, err + } + + for _, data := range response.Data { + network := u.parseNetwork(data, site.SiteName) + networks = append(networks, *network) + } + } + + return networks, nil +} + +// parseNetwork parses the raw JSON from the Unifi Controller into network structures. +func (u *Unifi) parseNetwork(data json.RawMessage, siteName string) *Network { + network := new(Network) + u.unmarshalNetwork(data, &network) + return network +} + +// unmarshalNetwork handles logging for the unmarshal operations in parseNetwork(). +func (u *Unifi) unmarshalNetwork(data json.RawMessage, v interface{}) (err error) { + if err = json.Unmarshal(data, v); err != nil { + u.ErrorLog("json.Unmarshal(): %v", err) + u.ErrorLog("Enable Debug Logging to output the failed payload.") + + json, err := data.MarshalJSON() + u.DebugLog("Failed Payload: %s (marshal err: %v)", json, err) + u.DebugLog("The above payload can prove useful during torubleshooting when you open an Issue:") + u.DebugLog("==- https://github.com/unifi-poller/unifi/issues/new -==") + } + + return err +} + +// Network is metadata about a network managed by a UniFi controller +type Network struct { + DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"` + DhcpdEnabled FlexBool `json:"dhcpd_enabled"` + DhcpdGatewayEnabled FlexBool `json:"dhcpd_gateway_enabled"` + DhcpdIP1 string `json:"dhcpd_ip_1"` + DhcpdLeasetime FlexInt `json:"dhcpd_leasetime"` + DhcpRelayEnabled FlexBool `json:"dhcp_relay_enabled"` + DhcpdTimeOffsetEnabled FlexBool `json:"dhcpd_time_offset_enabled"` + DhcpGuardEnabled FlexBool `json:"dhcpguard_enabled"` + DomainName string `json:"domain_name"` + Enabled FlexBool `json:"enabled"` + ID string `json:"_id"` + IPSubnet string `json:"ip_subnet"` + IsNat FlexBool `json:"is_nat"` + Name string `json:"name"` + Networkgroup string `json:"networkgroup"` + Purpose string `json:"purpose"` + SiteID string `json:"site_id"` + Vlan FlexInt `json:"vlan"` + VlanEnabled FlexBool `json:"vlan_enabled"` +} diff --git a/core/unifi/types.go b/core/unifi/types.go index 77c46b15..626ce333 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -29,6 +29,8 @@ const ( APIClientDPI string = "/api/s/%s/stat/stadpi" // APIClientPath is Unifi Clients API Path APIClientPath string = "/api/s/%s/stat/sta" + // APINetworkPath is where we get data about Unifi networks. + APINetworkPath string = "/api/s/%s/rest/networkconf" // APIDevicePath is where we get data about Unifi devices. APIDevicePath string = "/api/s/%s/stat/device" // APILoginPath is Unifi Controller Login API Path From 422c3f220fb936ad8c2d7c73e7b953993a084b92 Mon Sep 17 00:00:00 2001 From: Andrew Regner Date: Fri, 11 Sep 2020 14:52:25 -0700 Subject: [PATCH 162/194] Update networks.go Co-authored-by: David Newhall II --- core/unifi/networks.go | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/core/unifi/networks.go b/core/unifi/networks.go index 23237c19..ac392eb3 100644 --- a/core/unifi/networks.go +++ b/core/unifi/networks.go @@ -35,21 +35,6 @@ func (u *Unifi) parseNetwork(data json.RawMessage, siteName string) *Network { return network } -// unmarshalNetwork handles logging for the unmarshal operations in parseNetwork(). -func (u *Unifi) unmarshalNetwork(data json.RawMessage, v interface{}) (err error) { - if err = json.Unmarshal(data, v); err != nil { - u.ErrorLog("json.Unmarshal(): %v", err) - u.ErrorLog("Enable Debug Logging to output the failed payload.") - - json, err := data.MarshalJSON() - u.DebugLog("Failed Payload: %s (marshal err: %v)", json, err) - u.DebugLog("The above payload can prove useful during torubleshooting when you open an Issue:") - u.DebugLog("==- https://github.com/unifi-poller/unifi/issues/new -==") - } - - return err -} - // Network is metadata about a network managed by a UniFi controller type Network struct { DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"` From 95f017cae6d7ce7a72a99a76a7ee31983d46ac27 Mon Sep 17 00:00:00 2001 From: Andrew Regner Date: Fri, 11 Sep 2020 14:52:40 -0700 Subject: [PATCH 163/194] Update networks.go Co-authored-by: David Newhall II --- core/unifi/networks.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/unifi/networks.go b/core/unifi/networks.go index ac392eb3..3a8b7560 100644 --- a/core/unifi/networks.go +++ b/core/unifi/networks.go @@ -29,10 +29,9 @@ func (u *Unifi) GetNetworks(sites []*Site) ([]Network, error) { } // parseNetwork parses the raw JSON from the Unifi Controller into network structures. -func (u *Unifi) parseNetwork(data json.RawMessage, siteName string) *Network { +func (u *Unifi) parseNetwork(data json.RawMessage, siteName string) (*Network, error) { network := new(Network) - u.unmarshalNetwork(data, &network) - return network + return network, u.unmarshalDevice(data, network) } // Network is metadata about a network managed by a UniFi controller From 23dc92dbfa446ac6f72219cbac11bbfc024a696f Mon Sep 17 00:00:00 2001 From: Andrew Regner Date: Fri, 11 Sep 2020 14:52:46 -0700 Subject: [PATCH 164/194] Update networks.go Co-authored-by: David Newhall II --- core/unifi/networks.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/unifi/networks.go b/core/unifi/networks.go index 3a8b7560..ec64efcd 100644 --- a/core/unifi/networks.go +++ b/core/unifi/networks.go @@ -20,7 +20,11 @@ func (u *Unifi) GetNetworks(sites []*Site) ([]Network, error) { } for _, data := range response.Data { - network := u.parseNetwork(data, site.SiteName) + network, err := u.parseNetwork(data, site.SiteName) + if err != nil { + return networks, err + } + networks = append(networks, *network) } } From e88c293e1c6ccdfbc779daaa70594e85a768e585 Mon Sep 17 00:00:00 2001 From: Andrew Regner Date: Thu, 8 Oct 2020 17:59:23 -0700 Subject: [PATCH 165/194] Fix argument bug in networks.go --- core/unifi/networks.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/networks.go b/core/unifi/networks.go index ec64efcd..05915432 100644 --- a/core/unifi/networks.go +++ b/core/unifi/networks.go @@ -35,7 +35,7 @@ func (u *Unifi) GetNetworks(sites []*Site) ([]Network, error) { // parseNetwork parses the raw JSON from the Unifi Controller into network structures. func (u *Unifi) parseNetwork(data json.RawMessage, siteName string) (*Network, error) { network := new(Network) - return network, u.unmarshalDevice(data, network) + return network, u.unmarshalDevice(siteName, data, network) } // Network is metadata about a network managed by a UniFi controller From 993210793f64b981d123a16ab1af9fc31a2dada6 Mon Sep 17 00:00:00 2001 From: it-bluefish Date: Mon, 12 Oct 2020 12:03:50 +0100 Subject: [PATCH 166/194] Support PUT calls for REST API --- core/unifi/go.mod | 3 +- core/unifi/go.sum | 5 +++ core/unifi/unifi.go | 70 ++++++++++++++++++++++++++++++++++------ core/unifi/unifi_test.go | 26 +++++++++++++++ 4 files changed, 93 insertions(+), 11 deletions(-) diff --git a/core/unifi/go.mod b/core/unifi/go.mod index 83d311fb..219ef9dc 100644 --- a/core/unifi/go.mod +++ b/core/unifi/go.mod @@ -3,9 +3,8 @@ module github.com/unifi-poller/unifi go 1.14 require ( - github.com/davecgh/go-spew v1.1.1 + github.com/davecgh/go-spew v1.1.1 // indirect github.com/pkg/errors v0.9.1 - github.com/pmezard/go-difflib v1.0.0 github.com/stretchr/testify v1.4.0 golang.org/x/net v0.0.0-20200625001655-4c5254603344 ) diff --git a/core/unifi/go.sum b/core/unifi/go.sum index d8a6dd57..52fd963e 100644 --- a/core/unifi/go.sum +++ b/core/unifi/go.sum @@ -1,9 +1,12 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -14,5 +17,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 5b3ddd5d..79e0c6a4 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -166,6 +166,21 @@ func (u *Unifi) GetData(apiPath string, v interface{}, params ...string) error { return json.Unmarshal(body, v) } +// PutData makes a unifi request and unmarshals the response into a provided pointer. +func (u *Unifi) PutData(apiPath string, v interface{}, params ...string) error { + start := time.Now() + + body, err := u.PutJSON(apiPath, params...) + if err != nil { + return err + } + + u.DebugLog("Requested %s: elapsed %v, returned %d bytes", + u.URL+u.path(apiPath), time.Since(start).Round(time.Millisecond), len(body)) + + return json.Unmarshal(body, v) +} + // UniReq is a small helper function that adds an Accept header. // Use this if you're unmarshalling UniFi data into custom types. // And if you're doing that... sumbut a pull request with your new struct. :) @@ -182,18 +197,26 @@ func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err er return } - // Add the saved CSRF header. - req.Header.Set("X-CSRF-Token", u.csrf) - req.Header.Add("Accept", "application/json") - req.Header.Add("Content-Type", "application/json; charset=utf-8") + u.setHeaders(req, params) - if u.Client.Jar != nil { - parsedURL, _ := url.Parse(req.URL.String()) - u.DebugLog("Requesting %s, with params: %v, cookies: %d", req.URL, params != "", len(u.Client.Jar.Cookies(parsedURL))) - } else { - u.DebugLog("Requesting %s, with params: %v,", req.URL, params != "") + return +} + +// UniReqPut is the Put call equivalent to UniReq +func (u *Unifi) UniReqPut(apiPath string, params string) (req *http.Request, err error) { + switch apiPath = u.path(apiPath); params { + case "": + err = fmt.Errorf("Put with no parameters. Use UniReq()") + default: + req, err = http.NewRequest("PUT", u.URL+apiPath, bytes.NewBufferString(params)) } + if err != nil { + return + } + + u.setHeaders(req, params) + return } @@ -204,6 +227,21 @@ func (u *Unifi) GetJSON(apiPath string, params ...string) ([]byte, error) { return []byte{}, err } + return u.do(req) +} + +// PutJSON uses a PUT call and returns the raw JSON in the same way as GetData +// Use this if you want to change data via the REST API +func (u *Unifi) PutJSON(apiPath string, params ...string) ([]byte, error) { + req, err := u.UniReqPut(apiPath, strings.Join(params, " ")) + if err != nil { + return []byte{}, err + } + + return u.do(req) +} + +func (u *Unifi) do(req *http.Request) ([]byte, error) { resp, err := u.Do(req) if err != nil { return []byte{}, err @@ -227,3 +265,17 @@ func (u *Unifi) GetJSON(apiPath string, params ...string) ([]byte, error) { return body, err } + +func (u *Unifi) setHeaders(req *http.Request, params string) { + // Add the saved CSRF header. + req.Header.Set("X-CSRF-Token", u.csrf) + req.Header.Add("Accept", "application/json") + req.Header.Add("Content-Type", "application/json; charset=utf-8") + + if u.Client.Jar != nil { + parsedURL, _ := url.Parse(req.URL.String()) + u.DebugLog("Requesting %s, with params: %v, cookies: %d", req.URL, params != "", len(u.Client.Jar.Cookies(parsedURL))) + } else { + u.DebugLog("Requesting %s, with params: %v,", req.URL, params != "") + } +} diff --git a/core/unifi/unifi_test.go b/core/unifi/unifi_test.go index 28204201..1ef3725f 100644 --- a/core/unifi/unifi_test.go +++ b/core/unifi/unifi_test.go @@ -56,6 +56,32 @@ func TestUniReq(t *testing.T) { a.EqualValues(k, string(d), "POST parameters improperly encoded") } +func TestUniReqPut(t *testing.T) { + t.Parallel() + a := assert.New(t) + p := "/test/path" + u := "http://some.url:8443" + // Test empty parameters. + authReq := &Unifi{Client: &http.Client{}, Config: &Config{URL: u, DebugLog: discardLogs}} + r, err := authReq.UniReqPut(p, "") + a.NotNil(err, "empty params must produce an error") + + // Test with parameters + k := "key1=value9&key2=value7" + authReq = &Unifi{Client: &http.Client{}, Config: &Config{URL: "http://some.url:8443", DebugLog: discardLogs}} + r, err = authReq.UniReqPut(p, k) + a.Nil(err, "newrequest must not produce an error") + a.EqualValues(p, r.URL.Path, + "the provided apiPath was not added to http request") + a.EqualValues(u, r.URL.Scheme+"://"+r.URL.Host, "URL improperly encoded") + a.EqualValues("PUT", r.Method, "with parameters the method must be POST") + a.EqualValues("application/json", r.Header.Get("Accept"), "Accept header must be set to application/json") + // Check the parameters. + d, err := ioutil.ReadAll(r.Body) + a.Nil(err, "problem reading request body, PUT parameters may be malformed") + a.EqualValues(k, string(d), "PUT parameters improperly encoded") +} + /* NOT DONE: OPEN web server, check parameters posted, more. This test is incomplete. a.EqualValues(`{"username": "user1","password": "pass2"}`, string(post_params), "user/pass json parameters improperly encoded") From e1be3246f1afa5f31a6c0fade3c7196004703f0e Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 7 Mar 2021 17:23:31 -0800 Subject: [PATCH 167/194] Add UXG, UDM storage, minor lint fixups. --- core/unifi/alarms.go | 2 +- core/unifi/anomalies.go | 4 +- core/unifi/devices.go | 6 + core/unifi/dpi.go | 23 +++- core/unifi/events.go | 6 +- core/unifi/ids.go | 9 +- core/unifi/site.go | 6 +- core/unifi/types.go | 3 + core/unifi/udm.go | 262 +++++++++++++++++++++------------------- core/unifi/unifi.go | 64 ++++++---- core/unifi/usg.go | 149 +++++++++++++---------- core/unifi/usw.go | 103 +++++++++------- 12 files changed, 362 insertions(+), 275 deletions(-) diff --git a/core/unifi/alarms.go b/core/unifi/alarms.go index 63c558e9..863e27ca 100644 --- a/core/unifi/alarms.go +++ b/core/unifi/alarms.go @@ -73,7 +73,7 @@ func (u *Unifi) GetAlarms(sites []*Site) ([]*Alarm, error) { // GetAlarmsSite retreives the Alarms for a single Site. func (u *Unifi) GetAlarmsSite(site *Site) ([]*Alarm, error) { if site == nil || site.Name == "" { - return nil, errNoSiteProvided + return nil, ErrNoSiteProvided } u.DebugLog("Polling Controller for Alarms, site %s (%s)", site.Name, site.Desc) diff --git a/core/unifi/anomalies.go b/core/unifi/anomalies.go index 9f7de0e2..2dfb5238 100644 --- a/core/unifi/anomalies.go +++ b/core/unifi/anomalies.go @@ -44,7 +44,7 @@ func (u *Unifi) GetAnomalies(sites []*Site, timeRange ...time.Time) ([]*Anomaly, // GetAnomaliesSite retreives the Anomalies for a single Site. func (u *Unifi) GetAnomaliesSite(site *Site, timeRange ...time.Time) ([]*Anomaly, error) { if site == nil || site.Name == "" { - return nil, errNoSiteProvided + return nil, ErrNoSiteProvided } u.DebugLog("Polling Controller for Anomalies, site %s (%s)", site.Name, site.Desc) @@ -119,7 +119,7 @@ func makeAnomalyParams(scale string, timeRange ...time.Time) (string, error) { end := timeRange[1].Unix() * int64(time.Microsecond) out = append(out, "end="+strconv.FormatInt(end, 10), "start="+strconv.FormatInt(start, 10)) default: - return "", errInvalidTimeRange + return "", ErrInvalidTimeRange } if len(out) == 0 { diff --git a/core/unifi/devices.go b/core/unifi/devices.go index 045e43d7..505d2743 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -72,6 +72,12 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) devices.UDMs = append(devices.UDMs, dev) } + case "uxg": + dev := &UXG{SiteName: siteName, SourceName: u.URL} + if u.unmarshalDevice(assetType, r, dev) == nil { + dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) + devices.UXGs = append(devices.UXGs, dev) + } default: u.ErrorLog("unknown asset type - %v - skipping", assetType) } diff --git a/core/unifi/dpi.go b/core/unifi/dpi.go index 6dc3d843..f487c877 100644 --- a/core/unifi/dpi.go +++ b/core/unifi/dpi.go @@ -15,12 +15,23 @@ type DPITable struct { // DPIData is the DPI data in the DPI table. type DPIData struct { - Cat int `json:"cat"` - App int `json:"app"` - RxBytes int64 `json:"rx_bytes"` - TxBytes int64 `json:"tx_bytes"` - RxPackets int64 `json:"rx_packets"` - TxPackets int64 `json:"tx_packets"` + Cat int `json:"cat"` + App int `json:"app"` + RxBytes int64 `json:"rx_bytes"` + TxBytes int64 `json:"tx_bytes"` + RxPackets int64 `json:"rx_packets"` + TxPackets int64 `json:"tx_packets"` + Clients []*DPIClient `json:"clients,omitempty"` + KnownClients FlexInt `json:"known_clients,omitempty"` +} + +// DPIClient data is sometimes included in ByApp output. +type DPIClient struct { + Mac string `json:"mac"` + RxBytes FlexInt `json:"rx_bytes"` + TxBytes FlexInt `json:"tx_bytes"` + RxPackets FlexInt `json:"rx_packets"` + TxPackets FlexInt `json:"tx_packets"` } // DPIMap allows binding methods to the DPICat and DPIApps variables. diff --git a/core/unifi/events.go b/core/unifi/events.go index 1f5f8458..d716daee 100644 --- a/core/unifi/events.go +++ b/core/unifi/events.go @@ -8,8 +8,8 @@ import ( ) var ( - errNoSiteProvided = fmt.Errorf("site must not be nil or empty") - errInvalidTimeRange = fmt.Errorf("only 0, 1 or 2 times may be provided to timeRange") + ErrNoSiteProvided = fmt.Errorf("site must not be nil or empty") + ErrInvalidTimeRange = fmt.Errorf("only 0, 1 or 2 times may be provided to timeRange") ) const ( @@ -35,7 +35,7 @@ func (u *Unifi) GetEvents(sites []*Site, hours time.Duration) ([]*Event, error) // GetSiteEvents retrieves the last 1 hour's worth of events from a single site. func (u *Unifi) GetSiteEvents(site *Site, hours time.Duration) ([]*Event, error) { if site == nil || site.Name == "" { - return nil, errNoSiteProvided + return nil, ErrNoSiteProvided } if hours < time.Hour { diff --git a/core/unifi/ids.go b/core/unifi/ids.go index 0140e157..c290cbe2 100644 --- a/core/unifi/ids.go +++ b/core/unifi/ids.go @@ -76,7 +76,7 @@ func (u *Unifi) GetIDS(sites []*Site, timeRange ...time.Time) ([]*IDS, error) { // Events between start and end are returned. End defaults to time.Now(). func (u *Unifi) GetIDSSite(site *Site, timeRange ...time.Time) ([]*IDS, error) { if site == nil || site.Name == "" { - return nil, errNoSiteProvided + return nil, ErrNoSiteProvided } u.DebugLog("Polling Controller for IDS Events, site %s (%s)", site.Name, site.Desc) @@ -126,12 +126,15 @@ func makeEventParams(timeRange ...time.Time) (string, error) { rp.Start = timeRange[0].Unix() * int64(time.Microsecond) rp.End = timeRange[1].Unix() * int64(time.Microsecond) default: - return "", errInvalidTimeRange + return "", ErrInvalidTimeRange } params, err := json.Marshal(&rp) + if err != nil { + return "", fmt.Errorf("json marshal: %w", err) + } - return string(params), err + return string(params), nil } type idsList []*IDS diff --git a/core/unifi/site.go b/core/unifi/site.go index 7939cb06..0d3826a1 100644 --- a/core/unifi/site.go +++ b/core/unifi/site.go @@ -5,9 +5,7 @@ import ( "strings" ) -var ( - errDPIDataBug = fmt.Errorf("dpi data table contains more than 1 item; please open a bug report") -) +var ErrDPIDataBug = fmt.Errorf("dpi data table contains more than 1 item; please open a bug report") // GetSites returns a list of configured sites on the UniFi controller. func (u *Unifi) GetSites() ([]*Site, error) { @@ -53,7 +51,7 @@ func (u *Unifi) GetSiteDPI(sites []*Site) ([]*DPITable, error) { } if l := len(response.Data); l > 1 { - return nil, errDPIDataBug + return nil, ErrDPIDataBug } else if l == 0 { u.DebugLog("Site DPI data missing! Is DPI enabled in UniFi controller? Site %s (%s) ", site.Name, site.Desc) continue diff --git a/core/unifi/types.go b/core/unifi/types.go index 626ce333..b3ce54a8 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -6,6 +6,7 @@ import ( "net/http" "strconv" "strings" + "time" "github.com/pkg/errors" ) @@ -79,6 +80,7 @@ type Devices struct { USGs []*USG USWs []*USW UDMs []*UDM + UXGs []*UXG } // Config is the data passed into our library. This configures things and allows @@ -91,6 +93,7 @@ type Config struct { New bool ErrorLog Logger DebugLog Logger + Timeout time.Duration // how long to wait for replies, default: forever. } // Unifi is what you get in return for providing a password! Unifi represents diff --git a/core/unifi/udm.go b/core/unifi/udm.go index 041eb2b5..49053539 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -3,69 +3,59 @@ package unifi // UDM represents all the data from the Ubiquiti Controller for a Unifi Dream Machine. // The UDM shares several structs/type-data with USW and USG. type UDM struct { - SourceName string `json:"-"` - SiteID string `json:"site_id"` - SiteName string `json:"-"` - Mac string `json:"mac"` - Adopted FlexBool `json:"adopted"` - Serial string `json:"serial"` - IP string `json:"ip"` - Uptime FlexInt `json:"uptime"` - Model string `json:"model"` - Version string `json:"version"` - Name string `json:"name"` - Default FlexBool `json:"default"` - Locating FlexBool `json:"locating"` - Type string `json:"type"` - Unsupported FlexBool `json:"unsupported"` - UnsupportedReason FlexInt `json:"unsupported_reason"` - DiscoveredVia string `json:"discovered_via"` - AdoptIP string `json:"adopt_ip"` - AdoptURL string `json:"adopt_url"` - State FlexInt `json:"state"` - AdoptStatus FlexInt `json:"adopt_status"` - UpgradeState FlexInt `json:"upgrade_state"` - LastSeen FlexInt `json:"last_seen"` - AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` - Cfgversion string `json:"cfgversion"` - ConfigNetwork struct { - Type string `json:"type"` - IP string `json:"ip"` - } `json:"config_network"` - VwireTable []interface{} `json:"vwire_table"` - Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"` - JumboframeEnabled FlexBool `json:"jumboframe_enabled"` - FlowctrlEnabled FlexBool `json:"flowctrl_enabled"` - StpVersion string `json:"stp_version"` - StpPriority FlexInt `json:"stp_priority"` - PowerSourceCtrlEnabled FlexBool `json:"power_source_ctrl_enabled"` - LicenseState string `json:"license_state"` - ID string `json:"_id"` - DeviceID string `json:"device_id"` - AdoptState FlexInt `json:"adopt_state"` - AdoptTries FlexInt `json:"adopt_tries"` - AdoptManual FlexBool `json:"adopt_manual"` - InformURL string `json:"inform_url"` - InformIP string `json:"inform_ip"` - RequiredVersion string `json:"required_version"` - BoardRev FlexInt `json:"board_rev"` - EthernetTable []struct { - Mac string `json:"mac"` - NumPort FlexInt `json:"num_port"` - Name string `json:"name"` - } `json:"ethernet_table"` - PortTable []Port `json:"port_table"` - EthernetOverrides []struct { - Ifname string `json:"ifname"` - Networkgroup string `json:"networkgroup"` - } `json:"ethernet_overrides"` - UsgCaps FlexInt `json:"usg_caps"` - HasSpeaker FlexBool `json:"has_speaker"` - HasEth1 FlexBool `json:"has_eth1"` - FwCaps FlexInt `json:"fw_caps"` - HwCaps FlexInt `json:"hw_caps"` - WifiCaps FlexInt `json:"wifi_caps"` - SwitchCaps struct { + SourceName string `json:"-"` + SiteID string `json:"site_id"` + SiteName string `json:"-"` + Mac string `json:"mac"` + Adopted FlexBool `json:"adopted"` + Serial string `json:"serial"` + IP string `json:"ip"` + Uptime FlexInt `json:"uptime"` + Model string `json:"model"` + Version string `json:"version"` + Name string `json:"name"` + Default FlexBool `json:"default"` + Locating FlexBool `json:"locating"` + Type string `json:"type"` + Unsupported FlexBool `json:"unsupported"` + UnsupportedReason FlexInt `json:"unsupported_reason"` + DiscoveredVia string `json:"discovered_via"` + AdoptIP string `json:"adopt_ip"` + AdoptURL string `json:"adopt_url"` + State FlexInt `json:"state"` + AdoptStatus FlexInt `json:"adopt_status"` + UpgradeState FlexInt `json:"upgrade_state"` + LastSeen FlexInt `json:"last_seen"` + AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` + Cfgversion string `json:"cfgversion"` + ConfigNetwork *ConfigNetwork `json:"config_network"` + VwireTable []interface{} `json:"vwire_table"` + Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"` + JumboframeEnabled FlexBool `json:"jumboframe_enabled"` + FlowctrlEnabled FlexBool `json:"flowctrl_enabled"` + StpVersion string `json:"stp_version"` + StpPriority FlexInt `json:"stp_priority"` + PowerSourceCtrlEnabled FlexBool `json:"power_source_ctrl_enabled"` + LicenseState string `json:"license_state"` + ID string `json:"_id"` + DeviceID string `json:"device_id"` + AdoptState FlexInt `json:"adopt_state"` + AdoptTries FlexInt `json:"adopt_tries"` + AdoptManual FlexBool `json:"adopt_manual"` + InformURL string `json:"inform_url"` + InformIP string `json:"inform_ip"` + RequiredVersion string `json:"required_version"` + BoardRev FlexInt `json:"board_rev"` + EthernetTable []*EthernetTable `json:"ethernet_table"` + PortTable []Port `json:"port_table"` + EthernetOverrides []*EthernetOverrides `json:"ethernet_overrides"` + UsgCaps FlexInt `json:"usg_caps"` + HasSpeaker FlexBool `json:"has_speaker"` + HasEth1 FlexBool `json:"has_eth1"` + FwCaps FlexInt `json:"fw_caps"` + HwCaps FlexInt `json:"hw_caps"` + WifiCaps FlexInt `json:"wifi_caps"` + SwitchCaps struct { MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` } `json:"switch_caps"` @@ -96,7 +86,7 @@ type UDM struct { Uplink Uplink `json:"uplink"` ConnectRequestIP string `json:"connect_request_ip"` ConnectRequestPort string `json:"connect_request_port"` - DownlinkTable []interface{} `json:"downlink_table"` + DownlinkTable []*DownlinkTable `json:"downlink_table"` WlangroupIDNa string `json:"wlangroup_id_na"` WlangroupIDNg string `json:"wlangroup_id_ng"` BandsteeringMode string `json:"bandsteering_mode"` @@ -109,69 +99,95 @@ type UDM struct { PortIdx FlexInt `json:"port_idx"` PortconfID string `json:"portconf_id"` } `json:"port_overrides"` - Stat UDMStat `json:"stat"` - TxBytes FlexInt `json:"tx_bytes"` - RxBytes FlexInt `json:"rx_bytes"` - Bytes FlexInt `json:"bytes"` - BytesD FlexInt `json:"bytes-d"` - TxBytesD FlexInt `json:"tx_bytes-d"` - RxBytesD FlexInt `json:"rx_bytes-d"` - BytesR FlexInt `json:"bytes-r"` - NumSta FlexInt `json:"num_sta"` // USG - WlanNumSta FlexInt `json:"wlan-num_sta"` // UAP - LanNumSta FlexInt `json:"lan-num_sta"` // USW - UserWlanNumSta FlexInt `json:"user-wlan-num_sta"` // UAP - UserLanNumSta FlexInt `json:"user-lan-num_sta"` // USW - UserNumSta FlexInt `json:"user-num_sta"` // USG - GuestWlanNumSta FlexInt `json:"guest-wlan-num_sta"` // UAP - GuestLanNumSta FlexInt `json:"guest-lan-num_sta"` // USW - GuestNumSta FlexInt `json:"guest-num_sta"` // USG - NumDesktop FlexInt `json:"num_desktop"` // USG - NumMobile FlexInt `json:"num_mobile"` // USG - NumHandheld FlexInt `json:"num_handheld"` // USG + Stat UDMStat `json:"stat"` + Storage []*Storage `json:"storage"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + BytesD FlexInt `json:"bytes-d"` + TxBytesD FlexInt `json:"tx_bytes-d"` + RxBytesD FlexInt `json:"rx_bytes-d"` + BytesR FlexInt `json:"bytes-r"` + NumSta FlexInt `json:"num_sta"` // USG + WlanNumSta FlexInt `json:"wlan-num_sta"` // UAP + LanNumSta FlexInt `json:"lan-num_sta"` // USW + UserWlanNumSta FlexInt `json:"user-wlan-num_sta"` // UAP + UserLanNumSta FlexInt `json:"user-lan-num_sta"` // USW + UserNumSta FlexInt `json:"user-num_sta"` // USG + GuestWlanNumSta FlexInt `json:"guest-wlan-num_sta"` // UAP + GuestLanNumSta FlexInt `json:"guest-lan-num_sta"` // USW + GuestNumSta FlexInt `json:"guest-num_sta"` // USG + NumDesktop FlexInt `json:"num_desktop"` // USG + NumMobile FlexInt `json:"num_mobile"` // USG + NumHandheld FlexInt `json:"num_handheld"` // USG +} + +type EthernetOverrides struct { + Ifname string `json:"ifname"` + Networkgroup string `json:"networkgroup"` +} + +type EthernetTable struct { + Mac string `json:"mac"` + NumPort FlexInt `json:"num_port"` + Name string `json:"name"` } // NetworkTable is the list of networks on a gateway. +// Not all gateways have all features. type NetworkTable []struct { - ID string `json:"_id"` - AttrNoDelete FlexBool `json:"attr_no_delete"` - AttrHiddenID string `json:"attr_hidden_id"` - Name string `json:"name"` - SiteID string `json:"site_id"` - VlanEnabled FlexBool `json:"vlan_enabled"` - Purpose string `json:"purpose"` - IPSubnet string `json:"ip_subnet"` - Ipv6InterfaceType string `json:"ipv6_interface_type"` - DomainName string `json:"domain_name"` - IsNat FlexBool `json:"is_nat"` - DhcpdEnabled FlexBool `json:"dhcpd_enabled"` - DhcpdStart string `json:"dhcpd_start"` - DhcpdStop string `json:"dhcpd_stop"` - Dhcpdv6Enabled FlexBool `json:"dhcpdv6_enabled"` - Ipv6RaEnabled FlexBool `json:"ipv6_ra_enabled"` - LteLanEnabled FlexBool `json:"lte_lan_enabled"` - Networkgroup string `json:"networkgroup"` - DhcpdLeasetime FlexInt `json:"dhcpd_leasetime"` - DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"` - DhcpdGatewayEnabled FlexBool `json:"dhcpd_gateway_enabled"` - DhcpdTimeOffsetEnabled FlexBool `json:"dhcpd_time_offset_enabled"` - Ipv6PdStart string `json:"ipv6_pd_start"` - Ipv6PdStop string `json:"ipv6_pd_stop"` - DhcpdDNS1 string `json:"dhcpd_dns_1"` - DhcpdDNS2 string `json:"dhcpd_dns_2"` - DhcpdDNS3 string `json:"dhcpd_dns_3"` - DhcpdDNS4 string `json:"dhcpd_dns_4"` - Enabled FlexBool `json:"enabled"` - DhcpRelayEnabled FlexBool `json:"dhcp_relay_enabled"` - Mac string `json:"mac"` - IsGuest FlexBool `json:"is_guest"` - IP string `json:"ip"` - Up FlexBool `json:"up"` - NumSta FlexInt `json:"num_sta"` - RxBytes FlexInt `json:"rx_bytes"` - RxPackets FlexInt `json:"rx_packets"` - TxBytes FlexInt `json:"tx_bytes"` - TxPackets FlexInt `json:"tx_packets"` + ID string `json:"_id"` + AttrNoDelete FlexBool `json:"attr_no_delete"` + AttrHiddenID string `json:"attr_hidden_id"` + Name string `json:"name"` + SiteID string `json:"site_id"` + VlanEnabled FlexBool `json:"vlan_enabled"` + Purpose string `json:"purpose"` + IPSubnet string `json:"ip_subnet"` + Ipv6InterfaceType string `json:"ipv6_interface_type"` + DomainName string `json:"domain_name"` + IsNat FlexBool `json:"is_nat"` + DhcpdEnabled FlexBool `json:"dhcpd_enabled"` + DhcpdStart string `json:"dhcpd_start"` + DhcpdStop string `json:"dhcpd_stop"` + Dhcpdv6Enabled FlexBool `json:"dhcpdv6_enabled"` + Ipv6RaEnabled FlexBool `json:"ipv6_ra_enabled"` + LteLanEnabled FlexBool `json:"lte_lan_enabled"` + AutoScaleEnabled FlexBool `json:"auto_scale_enabled"` + Networkgroup string `json:"networkgroup"` + DhcpdLeasetime FlexInt `json:"dhcpd_leasetime"` + DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"` + DhcpdGatewayEnabled FlexBool `json:"dhcpd_gateway_enabled"` + DhcpdTimeOffsetEnabled FlexBool `json:"dhcpd_time_offset_enabled"` + Ipv6PdStart string `json:"ipv6_pd_start"` + Ipv6PdStop string `json:"ipv6_pd_stop"` + DhcpdDNS1 string `json:"dhcpd_dns_1"` + DhcpdDNS2 string `json:"dhcpd_dns_2"` + DhcpdDNS3 string `json:"dhcpd_dns_3"` + DhcpdDNS4 string `json:"dhcpd_dns_4"` + Enabled FlexBool `json:"enabled"` + DhcpRelayEnabled FlexBool `json:"dhcp_relay_enabled"` + Mac string `json:"mac"` + IsGuest FlexBool `json:"is_guest"` + IP string `json:"ip"` + Up FlexBool `json:"up"` + ActiveDhcpLeaseCount int `json:"active_dhcp_lease_count"` + GatewayInterfaceName string `json:"gateway_interface_name"` + DPIStatsTable *DPITable `json:"dpistats_table"` + NumSta FlexInt `json:"num_sta"` + RxBytes FlexInt `json:"rx_bytes"` + RxPackets FlexInt `json:"rx_packets"` + TxBytes FlexInt `json:"tx_bytes"` + TxPackets FlexInt `json:"tx_packets"` +} + +// Storage is hard drive into for a device with storage. +type Storage struct { + MountPoint string `json:"mount_point"` + Name string `json:"name"` + Size FlexInt `json:"size"` + Type string `json:"type"` + Used FlexInt `json:"used"` } type Temperature struct { diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 79e0c6a4..b5e8aa21 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -7,6 +7,7 @@ package unifi import ( "bytes" + "context" "crypto/tls" "encoding/json" "fmt" @@ -18,13 +19,13 @@ import ( "strings" "time" - "github.com/pkg/errors" "golang.org/x/net/publicsuffix" ) var ( - errAuthenticationFailed = fmt.Errorf("authentication failed") - errInvalidStatusCode = fmt.Errorf("invalid status code from server") + ErrAuthenticationFailed = fmt.Errorf("authentication failed") + ErrInvalidStatusCode = fmt.Errorf("invalid status code from server") + ErrNoParams = fmt.Errorf("requedted PUT with no parameters") ) // NewUnifi creates a http.Client with authenticated cookies. @@ -46,9 +47,11 @@ func NewUnifi(config *Config) (*Unifi, error) { config.DebugLog = discardLogs } - u := &Unifi{Config: config, + u := &Unifi{ + Config: config, Client: &http.Client{ - Jar: jar, + Timeout: config.Timeout, + Jar: jar, Transport: &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: !config.VerifySSL}, // nolint: gosec }, @@ -64,7 +67,7 @@ func NewUnifi(config *Config) (*Unifi, error) { } if err := u.GetServerData(); err != nil { - return u, errors.Wrap(err, "unable to get server version") + return u, fmt.Errorf("unable to get server version: %w", err) } return u, nil @@ -91,8 +94,8 @@ func (u *Unifi) Login() error { req.URL, time.Since(start).Round(time.Millisecond), resp.ContentLength) if resp.StatusCode != http.StatusOK { - return errors.Wrapf(errAuthenticationFailed, "(user: %s): %s (status: %s)", - u.User, req.URL, resp.Status) + return fmt.Errorf("(user: %s): %s (status: %s): %w", + u.User, req.URL, resp.Status, ErrAuthenticationFailed) } return nil @@ -185,39 +188,44 @@ func (u *Unifi) PutData(apiPath string, v interface{}, params ...string) error { // Use this if you're unmarshalling UniFi data into custom types. // And if you're doing that... sumbut a pull request with your new struct. :) // This is a helper method that is exposed for convenience. -func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err error) { +func (u *Unifi) UniReq(apiPath string, params string) (*http.Request, error) { + var ( + req *http.Request + err error + ) + switch apiPath = u.path(apiPath); params { case "": - req, err = http.NewRequest("GET", u.URL+apiPath, nil) + req, err = http.NewRequest(http.MethodGet, u.URL+apiPath, nil) default: - req, err = http.NewRequest("POST", u.URL+apiPath, bytes.NewBufferString(params)) + req, err = http.NewRequest(http.MethodPost, u.URL+apiPath, bytes.NewBufferString(params)) } if err != nil { - return + return nil, fmt.Errorf("creating request: %w", err) } u.setHeaders(req, params) - return + return req, nil } // UniReqPut is the Put call equivalent to UniReq -func (u *Unifi) UniReqPut(apiPath string, params string) (req *http.Request, err error) { - switch apiPath = u.path(apiPath); params { - case "": - err = fmt.Errorf("Put with no parameters. Use UniReq()") - default: - req, err = http.NewRequest("PUT", u.URL+apiPath, bytes.NewBufferString(params)) +func (u *Unifi) UniReqPut(apiPath string, params string) (*http.Request, error) { + if params == "" { + return nil, ErrNoParams } + apiPath = u.path(apiPath) + + req, err := http.NewRequest(http.MethodPut, u.URL+apiPath, bytes.NewBufferString(params)) //nolint:noctx if err != nil { - return + return nil, fmt.Errorf("creating request: %w", err) } u.setHeaders(req, params) - return + return req, nil } // GetJSON returns the raw JSON from a path. This is useful for debugging. @@ -242,7 +250,17 @@ func (u *Unifi) PutJSON(apiPath string, params ...string) ([]byte, error) { } func (u *Unifi) do(req *http.Request) ([]byte, error) { - resp, err := u.Do(req) + var ( + cancel func() + ctx = context.Background() + ) + + if u.Config.Timeout != 0 { + ctx, cancel = context.WithTimeout(ctx, u.Config.Timeout) + defer cancel() + } + + resp, err := u.Do(req.WithContext(ctx)) if err != nil { return []byte{}, err } @@ -260,7 +278,7 @@ func (u *Unifi) do(req *http.Request) ([]byte, error) { } if resp.StatusCode != http.StatusOK { - err = errors.Wrapf(errInvalidStatusCode, "%s: %s", req.URL, resp.Status) + err = fmt.Errorf("%s: %s: %w", req.URL, resp.Status, ErrInvalidStatusCode) } return body, err diff --git a/core/unifi/usg.go b/core/unifi/usg.go index d7aff5a1..60815209 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg.go @@ -7,62 +7,52 @@ import ( // USG represents all the data from the Ubiquiti Controller for a Unifi Security Gateway. type USG struct { - SourceName string `json:"-"` - ID string `json:"_id"` - Adopted FlexBool `json:"adopted"` - Cfgversion string `json:"cfgversion"` - ConfigNetwork struct { - Type string `json:"type"` - IP string `json:"ip"` - } `json:"config_network"` - EthernetTable []struct { - Mac string `json:"mac"` - NumPort FlexInt `json:"num_port"` - Name string `json:"name"` - } `json:"ethernet_table"` - FwCaps FlexInt `json:"fw_caps"` - InformIP string `json:"inform_ip"` - InformURL string `json:"inform_url"` - IP string `json:"ip"` - LedOverride string `json:"led_override"` - LicenseState string `json:"license_state"` - Mac string `json:"mac"` - Model string `json:"model"` - Name string `json:"name"` - OutdoorModeOverride string `json:"outdoor_mode_override"` - Serial string `json:"serial"` - SiteID string `json:"site_id"` - SiteName string `json:"-"` - Type string `json:"type"` - UsgCaps FlexInt `json:"usg_caps"` - Version string `json:"version"` - RequiredVersion string `json:"required_version"` - EthernetOverrides []struct { - Ifname string `json:"ifname"` - Networkgroup string `json:"networkgroup"` - } `json:"ethernet_overrides"` - HwCaps FlexInt `json:"hw_caps"` - BoardRev FlexInt `json:"board_rev"` - Unsupported FlexBool `json:"unsupported"` - UnsupportedReason FlexInt `json:"unsupported_reason"` - DeviceID string `json:"device_id"` - State FlexInt `json:"state"` - LastSeen FlexInt `json:"last_seen"` - Upgradable FlexBool `json:"upgradable"` - AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` - Rollupgrade FlexBool `json:"rollupgrade"` - KnownCfgversion string `json:"known_cfgversion"` - Uptime FlexInt `json:"uptime"` - Locating FlexBool `json:"locating"` - ConnectRequestIP string `json:"connect_request_ip"` - ConnectRequestPort string `json:"connect_request_port"` - SysStats SysStats `json:"sys_stats"` - SystemStats SystemStats `json:"system-stats"` - GuestToken string `json:"guest_token"` - SpeedtestStatus SpeedtestStatus `json:"speedtest-status"` - SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"` - Wan1 Wan `json:"wan1"` - Wan2 Wan `json:"wan2"` + SourceName string `json:"-"` + ID string `json:"_id"` + Adopted FlexBool `json:"adopted"` + Cfgversion string `json:"cfgversion"` + ConfigNetwork *ConfigNetwork `json:"config_network"` + EthernetTable []*EthernetTable `json:"ethernet_table"` + FwCaps FlexInt `json:"fw_caps"` + InformIP string `json:"inform_ip"` + InformURL string `json:"inform_url"` + IP string `json:"ip"` + LedOverride string `json:"led_override"` + LicenseState string `json:"license_state"` + Mac string `json:"mac"` + Model string `json:"model"` + Name string `json:"name"` + OutdoorModeOverride string `json:"outdoor_mode_override"` + Serial string `json:"serial"` + SiteID string `json:"site_id"` + SiteName string `json:"-"` + Type string `json:"type"` + UsgCaps FlexInt `json:"usg_caps"` + Version string `json:"version"` + RequiredVersion string `json:"required_version"` + EthernetOverrides []*EthernetOverrides `json:"ethernet_overrides"` + HwCaps FlexInt `json:"hw_caps"` + BoardRev FlexInt `json:"board_rev"` + Unsupported FlexBool `json:"unsupported"` + UnsupportedReason FlexInt `json:"unsupported_reason"` + DeviceID string `json:"device_id"` + State FlexInt `json:"state"` + LastSeen FlexInt `json:"last_seen"` + Upgradable FlexBool `json:"upgradable"` + AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"` + Rollupgrade FlexBool `json:"rollupgrade"` + KnownCfgversion string `json:"known_cfgversion"` + Uptime FlexInt `json:"uptime"` + Locating FlexBool `json:"locating"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + SysStats SysStats `json:"sys_stats"` + SystemStats SystemStats `json:"system-stats"` + GuestToken string `json:"guest_token"` + SpeedtestStatus SpeedtestStatus `json:"speedtest-status"` + SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"` + Wan1 Wan `json:"wan1"` + Wan2 Wan `json:"wan2"` PortTable []struct { Name string `json:"name"` Ifname string `json:"ifname"` @@ -114,12 +104,15 @@ type Uplink struct { Nameservers []string `json:"nameservers"` Netmask string `json:"netmask"` NumPort FlexInt `json:"num_port"` + Media string `json:"media"` + PortIdx FlexInt `json:"port_idx"` RxBytes FlexInt `json:"rx_bytes"` RxBytesR FlexInt `json:"rx_bytes-r"` RxDropped FlexInt `json:"rx_dropped"` RxErrors FlexInt `json:"rx_errors"` RxMulticast FlexInt `json:"rx_multicast"` RxPackets FlexInt `json:"rx_packets"` + RxRate FlexInt `json:"rx_rate"` Speed FlexInt `json:"speed"` SpeedtestLastrun FlexInt `json:"speedtest_lastrun,omitempty"` SpeedtestPing FlexInt `json:"speedtest_ping,omitempty"` @@ -129,6 +122,7 @@ type Uplink struct { TxDropped FlexInt `json:"tx_dropped"` TxErrors FlexInt `json:"tx_errors"` TxPackets FlexInt `json:"tx_packets"` + TxRate FlexInt `json:"tx_rate"` Type string `json:"type"` Up FlexBool `json:"up"` Uptime FlexInt `json:"uptime"` @@ -140,7 +134,7 @@ type Uplink struct { type Wan struct { Autoneg FlexBool `json:"autoneg"` BytesR FlexInt `json:"bytes-r"` - DNS []string `json:"dns"` + DNS []string `json:"dns"` // may be deprecated Enable FlexBool `json:"enable"` FlowctrlRx FlexBool `json:"flowctrl_rx"` FlowctrlTx FlexBool `json:"flowctrl_tx"` @@ -164,7 +158,9 @@ type Wan struct { RxErrors FlexInt `json:"rx_errors"` RxMulticast FlexInt `json:"rx_multicast"` RxPackets FlexInt `json:"rx_packets"` + RxRate FlexInt `json:"rx_rate"` Speed FlexInt `json:"speed"` + SpeedCaps FlexInt `json:"speed_caps"` TxBroadcast FlexInt `json:"tx_broadcast"` TxBytes FlexInt `json:"tx_bytes"` TxBytesR FlexInt `json:"tx_bytes-r"` @@ -172,22 +168,40 @@ type Wan struct { TxErrors FlexInt `json:"tx_errors"` TxMulticast FlexInt `json:"tx_multicast"` TxPackets FlexInt `json:"tx_packets"` + TxRate FlexInt `json:"tx_rate"` Type string `json:"type"` Up FlexBool `json:"up"` } // SpeedtestStatus is the speed test info on a USG or UDM. type SpeedtestStatus struct { - Latency FlexInt `json:"latency"` - Rundate FlexInt `json:"rundate"` - Runtime FlexInt `json:"runtime"` - ServerDesc string `json:"server_desc,omitempty"` - StatusDownload FlexInt `json:"status_download"` - StatusPing FlexInt `json:"status_ping"` - StatusSummary FlexInt `json:"status_summary"` - StatusUpload FlexInt `json:"status_upload"` - XputDownload FlexInt `json:"xput_download"` - XputUpload FlexInt `json:"xput_upload"` + Latency FlexInt `json:"latency"` + Rundate FlexInt `json:"rundate"` + Runtime FlexInt `json:"runtime"` + ServerDesc string `json:"server_desc,omitempty"` + Server *SpeedtestServer `json:"server"` + StatusDownload FlexInt `json:"status_download"` + StatusPing FlexInt `json:"status_ping"` + StatusSummary FlexInt `json:"status_summary"` + StatusUpload FlexInt `json:"status_upload"` + XputDownload FlexInt `json:"xput_download"` + XputUpload FlexInt `json:"xput_upload"` +} + +type SpeedtestServer struct { + Cc string `json:"cc"` + City string `json:"city"` + Country string `json:"country"` + Lat FlexInt `json:"lat"` + Lon FlexInt `json:"lon"` + Provider string `json:"provider"` + ProviderURL string `json:"provider_url"` +} + +// ConfigNetwork comes from gateways. +type ConfigNetwork struct { + Type string `json:"type"` + IP string `json:"ip"` } // SystemStats is system info for a UDM, USG, USW. @@ -233,6 +247,7 @@ type Gw struct { LanTxBytes FlexInt `json:"lan-tx_bytes"` LanRxDropped FlexInt `json:"lan-rx_dropped"` WanRxErrors FlexInt `json:"wan-rx_errors,omitempty"` + LanRxErrors FlexInt `json:"lan-rx_errors,omitempty"` } // UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Gateway Stat data. diff --git a/core/unifi/usw.go b/core/unifi/usw.go index 242b2053..fcd75c9c 100644 --- a/core/unifi/usw.go +++ b/core/unifi/usw.go @@ -43,19 +43,15 @@ type USW struct { PortIdx FlexInt `json:"port_idx"` PortconfID string `json:"portconf_id"` } `json:"port_overrides"` - PortTable []Port `json:"port_table"` - Serial string `json:"serial"` - SiteID string `json:"site_id"` - StpPriority FlexInt `json:"stp_priority"` - StpVersion string `json:"stp_version"` - Type string `json:"type"` - Version string `json:"version"` - RequiredVersion string `json:"required_version"` - SwitchCaps struct { - FeatureCaps FlexInt `json:"feature_caps"` - MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` - MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` - } `json:"switch_caps"` + PortTable []Port `json:"port_table"` + Serial string `json:"serial"` + SiteID string `json:"site_id"` + StpPriority FlexInt `json:"stp_priority"` + StpVersion string `json:"stp_version"` + Type string `json:"type"` + Version string `json:"version"` + RequiredVersion string `json:"required_version"` + SwitchCaps *SwitchCaps `json:"switch_caps"` HwCaps FlexInt `json:"hw_caps"` Unsupported FlexBool `json:"unsupported"` UnsupportedReason FlexInt `json:"unsupported_reason"` @@ -97,39 +93,58 @@ type USW struct { GuestNumSta FlexInt `json:"guest-num_sta"` } +type SwitchCaps struct { + FeatureCaps FlexInt `json:"feature_caps"` + MaxMirrorSessions FlexInt `json:"max_mirror_sessions"` + MaxAggregateSessions FlexInt `json:"max_aggregate_sessions"` +} + +// MacTable is a newer feature on some switched ports. +type MacTable struct { + Age int64 `json:"age"` + Authorized FlexBool `json:"authorized"` + Hostname string `json:"hostname"` + IP string `json:"ip"` + LastReachable int64 `json:"lastReachable"` + Mac string `json:"mac"` +} + // Port is a physical connection on a USW or UDM. type Port struct { - AggregatedBy FlexBool `json:"aggregated_by"` - Autoneg FlexBool `json:"autoneg,omitempty"` - BytesR FlexInt `json:"bytes-r"` - DNS []string `json:"dns,omitempty"` - Dot1XMode string `json:"dot1x_mode"` - Dot1XStatus string `json:"dot1x_status"` - Enable FlexBool `json:"enable"` - FlowctrlRx FlexBool `json:"flowctrl_rx"` - FlowctrlTx FlexBool `json:"flowctrl_tx"` - FullDuplex FlexBool `json:"full_duplex"` - IP string `json:"ip,omitempty"` - Ifname string `json:"ifname,omitempty"` - IsUplink FlexBool `json:"is_uplink"` - Mac string `json:"mac,omitempty"` - Jumbo FlexBool `json:"jumbo,omitempty"` - Masked FlexBool `json:"masked"` - Media string `json:"media"` - Name string `json:"name"` - NetworkName string `json:"network_name,omitempty"` - NumPort int `json:"num_port,omitempty"` - OpMode string `json:"op_mode"` - PoeCaps FlexInt `json:"poe_caps"` - PoeClass string `json:"poe_class,omitempty"` - PoeCurrent FlexInt `json:"poe_current,omitempty"` - PoeEnable FlexBool `json:"poe_enable,omitempty"` - PoeGood FlexBool `json:"poe_good,omitempty"` - PoeMode string `json:"poe_mode,omitempty"` - PoePower FlexInt `json:"poe_power,omitempty"` - PoeVoltage FlexInt `json:"poe_voltage,omitempty"` + AggregatedBy FlexBool `json:"aggregated_by"` + Autoneg FlexBool `json:"autoneg,omitempty"` + BytesR FlexInt `json:"bytes-r"` + DNS []string `json:"dns,omitempty"` + Dot1XMode string `json:"dot1x_mode"` + Dot1XStatus string `json:"dot1x_status"` + Enable FlexBool `json:"enable"` + FlowctrlRx FlexBool `json:"flowctrl_rx"` + FlowctrlTx FlexBool `json:"flowctrl_tx"` + FullDuplex FlexBool `json:"full_duplex"` + IP string `json:"ip,omitempty"` + Ifname string `json:"ifname,omitempty"` + IsUplink FlexBool `json:"is_uplink"` + Mac string `json:"mac,omitempty"` + MacTable []MacTable `json:"mac_table,omitempty"` + Jumbo FlexBool `json:"jumbo,omitempty"` + Masked FlexBool `json:"masked"` + Media string `json:"media"` + Name string `json:"name"` + NetworkName string `json:"network_name,omitempty"` + Netmask string `json:"netmask,omitempty"` + NumPort int `json:"num_port,omitempty"` + OpMode string `json:"op_mode"` + PoeCaps FlexInt `json:"poe_caps"` + PoeClass string `json:"poe_class,omitempty"` + PoeCurrent FlexInt `json:"poe_current,omitempty"` + PoeEnable FlexBool `json:"poe_enable,omitempty"` + PoeGood FlexBool `json:"poe_good,omitempty"` + PoeMode string `json:"poe_mode,omitempty"` + PoePower FlexInt `json:"poe_power,omitempty"` + PoeVoltage FlexInt `json:"poe_voltage,omitempty"` PortDelta struct { - TimeDelta int64 `json:"time_delta"` + TimeDelta int64 `json:"time_delta"` + TimeDeltaActivity int64 `json:"time_delta_activity"` } `json:"port_delta,omitempty"` PortIdx FlexInt `json:"port_idx"` PortPoe FlexBool `json:"port_poe"` @@ -141,6 +156,7 @@ type Port struct { RxErrors FlexInt `json:"rx_errors"` RxMulticast FlexInt `json:"rx_multicast"` RxPackets FlexInt `json:"rx_packets"` + RxRate FlexInt `json:"rx_rate,omitempty"` Satisfaction FlexInt `json:"satisfaction,omitempty"` SfpFound FlexBool `json:"sfp_found,omitempty"` Speed FlexInt `json:"speed"` @@ -154,6 +170,7 @@ type Port struct { TxErrors FlexInt `json:"tx_errors"` TxMulticast FlexInt `json:"tx_multicast"` TxPackets FlexInt `json:"tx_packets"` + TxRate FlexInt `json:"tx_rate,omitempty"` Type string `json:"type,omitempty"` Up FlexBool `json:"up"` } From 068ee31dfa5e8f9e270271b2753b99e25d21e4d9 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 7 Mar 2021 17:23:47 -0800 Subject: [PATCH 168/194] need the uxg file --- core/unifi/uxg.go | 155 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 core/unifi/uxg.go diff --git a/core/unifi/uxg.go b/core/unifi/uxg.go new file mode 100644 index 00000000..41604087 --- /dev/null +++ b/core/unifi/uxg.go @@ -0,0 +1,155 @@ +package unifi + +// UXG represents all the data from the Ubiquiti Controller for a UniFi 10Gb Gateway. +// The UDM shares several structs/type-data with USW and USG. +type UXG struct { + SourceName string `json:"-"` + SiteName string `json:"-"` + ID string `json:"_id"` + IP string `json:"ip"` + Mac string `json:"mac"` + Model string `json:"model"` + ModelInLts bool `json:"model_in_lts"` + ModelInEol bool `json:"model_in_eol"` + Type string `json:"type"` + Version string `json:"version"` + Adopted bool `json:"adopted"` + SiteID string `json:"site_id"` + Cfgversion string `json:"cfgversion"` + SyslogKey string `json:"syslog_key"` + ConfigNetwork ConfigNetwork `json:"config_network"` + SetupID string `json:"setup_id"` + LicenseState string `json:"license_state"` + ConfigNetworkLan *ConfigNetworkLan `json:"config_network_lan"` + InformURL string `json:"inform_url"` + InformIP string `json:"inform_ip"` + RequiredVersion string `json:"required_version"` + KernelVersion string `json:"kernel_version"` + Architecture string `json:"architecture"` + BoardRev FlexInt `json:"board_rev"` + ManufacturerID FlexInt `json:"manufacturer_id"` + Internet bool `json:"internet"` + ModelIncompatible bool `json:"model_incompatible"` + EthernetTable []*EthernetTable `json:"ethernet_table"` + PortTable []*Port `json:"port_table"` + EthernetOverrides []*EthernetOverrides `json:"ethernet_overrides"` + UsgCaps FlexInt `json:"usg_caps"` + HasSpeaker bool `json:"has_speaker"` + HasEth1 bool `json:"has_eth1"` + FwCaps FlexInt `json:"fw_caps"` + HwCaps FlexInt `json:"hw_caps"` + WifiCaps FlexInt `json:"wifi_caps"` + SwitchCaps *SwitchCaps `json:"switch_caps"` + HasFan bool `json:"has_fan"` + HasTemperature bool `json:"has_temperature"` + Temperatures []*Temperature `json:"temperatures"` + Storage []Storage `json:"storage"` + RulesetInterfaces interface{} `json:"ruleset_interfaces"` + ConnectedAt FlexInt `json:"connected_at"` + ProvisionedAt FlexInt `json:"provisioned_at"` + LedOverride string `json:"led_override"` + LedOverrideColor string `json:"led_override_color"` + LedOverrideColorBrightness FlexInt `json:"led_override_color_brightness"` + OutdoorModeOverride string `json:"outdoor_mode_override"` + LcmBrightnessOverride bool `json:"lcm_brightness_override"` + LcmIdleTimeoutOverride bool `json:"lcm_idle_timeout_override"` + Name string `json:"name"` + Unsupported bool `json:"unsupported"` + UnsupportedReason FlexInt `json:"unsupported_reason"` + Serial string `json:"serial"` + HashID string `json:"hash_id"` + TwoPhaseAdopt bool `json:"two_phase_adopt"` + DeviceID string `json:"device_id"` + State FlexInt `json:"state"` + StartDisconnectedMillis int64 `json:"start_disconnected_millis"` + UpgradeState FlexInt `json:"upgrade_state"` + StartConnectedMillis int64 `json:"start_connected_millis"` + LastSeen FlexInt `json:"last_seen"` + Uptime FlexInt `json:"uptime"` + UnderscoreUptime FlexInt `json:"_uptime"` + Locating bool `json:"locating"` + SysStats *SysStats `json:"sys_stats"` + SystemStats *SystemStats `json:"system-stats"` + GuestKicks FlexInt `json:"guest_kicks"` + GuestToken string `json:"guest_token"` + UptimeStats map[string]*UptimeStats `json:"uptime_stats"` + Overheating bool `json:"overheating"` + GeoInfo map[string]*GeoInfo `json:"geo_info"` + LedState *LedState `json:"led_state"` + SpeedtestStatus *SpeedtestStatus `json:"speedtest-status"` + SpeedtestStatusSaved bool `json:"speedtest-status-saved"` + Wan1 *Wan `json:"wan1"` + Wan2 *Wan `json:"wan2"` + Uplink Uplink `json:"uplink"` + DownlinkTable []*DownlinkTable `json:"downlink_table"` + NetworkTable []*NetworkTable `json:"network_table"` + KnownCfgversion string `json:"known_cfgversion"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + NextInterval FlexInt `json:"next_interval"` + NextHeartbeatAt FlexInt `json:"next_heartbeat_at"` + ConsideredLostAt FlexInt `json:"considered_lost_at"` + Stat *UXGStat `json:"stat"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes int64 `json:"rx_bytes"` + Bytes int64 `json:"bytes"` + NumSta FlexInt `json:"num_sta"` + WlanNumSta FlexInt `json:"wlan-num_sta"` + LanNumSta FlexInt `json:"lan-num_sta"` + UserWlanNumSta FlexInt `json:"user-wlan-num_sta"` + UserLanNumSta FlexInt `json:"user-lan-num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` + GuestWlanNumSta FlexInt `json:"guest-wlan-num_sta"` + GuestLanNumSta FlexInt `json:"guest-lan-num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` + NumDesktop FlexInt `json:"num_desktop"` + NumMobile FlexInt `json:"num_mobile"` + NumHandheld FlexInt `json:"num_handheld"` +} + +// ConfigNetworkLan is part of a UXG, maybe others. +type ConfigNetworkLan struct { + DhcpEnabled FlexBool `json:"dhcp_enabled"` + Vlan int `json:"vlan"` +} + +// DownlinkTable is part of a UXG and UDM output. +type DownlinkTable struct { + PortIdx FlexInt `json:"port_idx"` + Speed FlexInt `json:"speed"` + FullDuplex FlexBool `json:"full_duplex"` + Mac string `json:"mac"` +} + +type LedState struct { + Pattern string `json:"pattern"` + Tempo FlexInt `json:"tempo"` +} + +type GeoInfo struct { + Accuracy FlexInt `json:"accuracy"` + Address string `json:"address"` + Asn FlexInt `json:"asn"` + City string `json:"city"` + ContinentCode string `json:"continent_code"` + CountryCode string `json:"country_code"` + CountryName string `json:"country_name"` + IspName string `json:"isp_name"` + IspOrganization string `json:"isp_organization"` + Latitude FlexInt `json:"latitude"` + Longitude FlexInt `json:"longitude"` + Timezone string `json:"timezone"` +} + +type UptimeStats struct { + Availability FlexInt `json:"availability"` + LatencyAverage FlexInt `json:"latency_average"` + TimePeriod FlexInt `json:"time_period"` +} + +// UDMStat holds the "stat" data for a dream machine. +// A dream machine is a USG + USW + Controller. +type UXGStat struct { + *Gw `json:"gw"` + *Sw `json:"sw"` +} From 8d9af25d472b8309ff0d122b6697ef92b831fb64 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 7 Mar 2021 17:57:16 -0800 Subject: [PATCH 169/194] a fe wmore tweaks to align outputs.a --- core/unifi/unifi_test.go | 13 +++- core/unifi/usg.go | 70 ++++++++------------- core/unifi/usw.go | 129 ++++++++++++++++++--------------------- core/unifi/uxg.go | 52 ++++++++-------- 4 files changed, 121 insertions(+), 143 deletions(-) diff --git a/core/unifi/unifi_test.go b/core/unifi/unifi_test.go index 1ef3725f..f466a950 100644 --- a/core/unifi/unifi_test.go +++ b/core/unifi/unifi_test.go @@ -30,9 +30,11 @@ func TestUniReq(t *testing.T) { a := assert.New(t) p := "/test/path" u := "http://some.url:8443" + // Test empty parameters. authReq := &Unifi{Client: &http.Client{}, Config: &Config{URL: u, DebugLog: discardLogs}} r, err := authReq.UniReq(p, "") + a.Nil(err, "newrequest must not produce an error") a.EqualValues(p, r.URL.Path, "the provided apiPath was not added to http request") @@ -45,11 +47,13 @@ func TestUniReq(t *testing.T) { authReq = &Unifi{Client: &http.Client{}, Config: &Config{URL: "http://some.url:8443", DebugLog: discardLogs}} r, err = authReq.UniReq(p, k) a.Nil(err, "newrequest must not produce an error") + a.EqualValues(p, r.URL.Path, "the provided apiPath was not added to http request") a.EqualValues(u, r.URL.Scheme+"://"+r.URL.Host, "URL improperly encoded") a.EqualValues("POST", r.Method, "with parameters the method must be POST") a.EqualValues("application/json", r.Header.Get("Accept"), "Accept header must be set to application/json") + // Check the parameters. d, err := ioutil.ReadAll(r.Body) a.Nil(err, "problem reading request body, POST parameters may be malformed") @@ -61,28 +65,31 @@ func TestUniReqPut(t *testing.T) { a := assert.New(t) p := "/test/path" u := "http://some.url:8443" + // Test empty parameters. authReq := &Unifi{Client: &http.Client{}, Config: &Config{URL: u, DebugLog: discardLogs}} - r, err := authReq.UniReqPut(p, "") + _, err := authReq.UniReqPut(p, "") a.NotNil(err, "empty params must produce an error") // Test with parameters k := "key1=value9&key2=value7" authReq = &Unifi{Client: &http.Client{}, Config: &Config{URL: "http://some.url:8443", DebugLog: discardLogs}} - r, err = authReq.UniReqPut(p, k) + r, err := authReq.UniReqPut(p, k) a.Nil(err, "newrequest must not produce an error") + a.EqualValues(p, r.URL.Path, "the provided apiPath was not added to http request") a.EqualValues(u, r.URL.Scheme+"://"+r.URL.Host, "URL improperly encoded") a.EqualValues("PUT", r.Method, "with parameters the method must be POST") a.EqualValues("application/json", r.Header.Get("Accept"), "Accept header must be set to application/json") + // Check the parameters. d, err := ioutil.ReadAll(r.Body) a.Nil(err, "problem reading request body, PUT parameters may be malformed") a.EqualValues(k, string(d), "PUT parameters improperly encoded") } -/* NOT DONE: OPEN web server, check parameters posted, more. This test is incomplete. +/* NOT DONE: OPEN web server, check parameters posted, more. These tests are incomplete. a.EqualValues(`{"username": "user1","password": "pass2"}`, string(post_params), "user/pass json parameters improperly encoded") */ diff --git a/core/unifi/usg.go b/core/unifi/usg.go index 60815209..751b76f8 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg.go @@ -53,40 +53,19 @@ type USG struct { SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"` Wan1 Wan `json:"wan1"` Wan2 Wan `json:"wan2"` - PortTable []struct { - Name string `json:"name"` - Ifname string `json:"ifname"` - IP string `json:"ip"` - Netmask string `json:"netmask"` - Mac string `json:"mac"` - Up FlexBool `json:"up"` - Speed FlexInt `json:"speed"` - FullDuplex FlexBool `json:"full_duplex"` - RxBytes FlexInt `json:"rx_bytes"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxPackets FlexInt `json:"rx_packets"` - TxBytes FlexInt `json:"tx_bytes"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxPackets FlexInt `json:"tx_packets"` - RxMulticast FlexInt `json:"rx_multicast"` - Enable FlexBool `json:"enable"` - DNS []string `json:"dns,omitempty"` - Gateway string `json:"gateway,omitempty"` - } `json:"port_table"` - NetworkTable NetworkTable `json:"network_table"` - Uplink Uplink `json:"uplink"` - Stat USGStat `json:"stat"` - TxBytes FlexInt `json:"tx_bytes"` - RxBytes FlexInt `json:"rx_bytes"` - Bytes FlexInt `json:"bytes"` - NumSta FlexInt `json:"num_sta"` - UserNumSta FlexInt `json:"user-num_sta"` - GuestNumSta FlexInt `json:"guest-num_sta"` - NumDesktop FlexInt `json:"num_desktop"` - NumMobile FlexInt `json:"num_mobile"` - NumHandheld FlexInt `json:"num_handheld"` + PortTable []*Port `json:"port_table"` + NetworkTable NetworkTable `json:"network_table"` + Uplink Uplink `json:"uplink"` + Stat USGStat `json:"stat"` + TxBytes FlexInt `json:"tx_bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` + NumSta FlexInt `json:"num_sta"` + UserNumSta FlexInt `json:"user-num_sta"` + GuestNumSta FlexInt `json:"guest-num_sta"` + NumDesktop FlexInt `json:"num_desktop"` + NumMobile FlexInt `json:"num_mobile"` + NumHandheld FlexInt `json:"num_handheld"` } // Uplink is the Internet connection (or uplink) on a UniFi device. @@ -175,17 +154,18 @@ type Wan struct { // SpeedtestStatus is the speed test info on a USG or UDM. type SpeedtestStatus struct { - Latency FlexInt `json:"latency"` - Rundate FlexInt `json:"rundate"` - Runtime FlexInt `json:"runtime"` - ServerDesc string `json:"server_desc,omitempty"` - Server *SpeedtestServer `json:"server"` - StatusDownload FlexInt `json:"status_download"` - StatusPing FlexInt `json:"status_ping"` - StatusSummary FlexInt `json:"status_summary"` - StatusUpload FlexInt `json:"status_upload"` - XputDownload FlexInt `json:"xput_download"` - XputUpload FlexInt `json:"xput_upload"` + Latency FlexInt `json:"latency"` + Rundate FlexInt `json:"rundate"` + Runtime FlexInt `json:"runtime"` + ServerDesc string `json:"server_desc,omitempty"` + Server *SpeedtestServer `json:"server"` + SourceInterface string `json:"source_interface"` + StatusDownload FlexInt `json:"status_download"` + StatusPing FlexInt `json:"status_ping"` + StatusSummary FlexInt `json:"status_summary"` + StatusUpload FlexInt `json:"status_upload"` + XputDownload FlexInt `json:"xput_download"` + XputUpload FlexInt `json:"xput_upload"` } type SpeedtestServer struct { diff --git a/core/unifi/usw.go b/core/unifi/usw.go index fcd75c9c..444577f2 100644 --- a/core/unifi/usw.go +++ b/core/unifi/usw.go @@ -7,80 +7,68 @@ import ( // USW represents all the data from the Ubiquiti Controller for a Unifi Switch. type USW struct { - SourceName string `json:"-"` - SiteName string `json:"-"` - ID string `json:"_id"` - Adopted FlexBool `json:"adopted"` - BoardRev FlexInt `json:"board_rev"` - Cfgversion string `json:"cfgversion"` - ConfigNetwork struct { - Type string `json:"type"` - IP string `json:"ip"` - } `json:"config_network"` - Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"` - EthernetTable []struct { - Mac string `json:"mac"` - NumPort FlexInt `json:"num_port,omitempty"` - Name string `json:"name"` - } `json:"ethernet_table"` - FlowctrlEnabled FlexBool `json:"flowctrl_enabled"` - FwCaps FlexInt `json:"fw_caps"` - HasFan FlexBool `json:"has_fan"` - HasTemperature FlexBool `json:"has_temperature"` - InformIP string `json:"inform_ip"` - InformURL string `json:"inform_url"` - IP string `json:"ip"` - JumboframeEnabled FlexBool `json:"jumboframe_enabled"` - LedOverride string `json:"led_override"` - LicenseState string `json:"license_state"` - Mac string `json:"mac"` - Model string `json:"model"` - Name string `json:"name"` - OutdoorModeOverride string `json:"outdoor_mode_override"` - PortOverrides []struct { + SourceName string `json:"-"` + SiteName string `json:"-"` + ID string `json:"_id"` + Adopted FlexBool `json:"adopted"` + BoardRev FlexInt `json:"board_rev"` + Cfgversion string `json:"cfgversion"` + ConfigNetwork *ConfigNetwork `json:"config_network"` + Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"` + EthernetTable []*EthernetTable `json:"ethernet_table"` + FlowctrlEnabled FlexBool `json:"flowctrl_enabled"` + FwCaps FlexInt `json:"fw_caps"` + HasFan FlexBool `json:"has_fan"` + HasTemperature FlexBool `json:"has_temperature"` + InformIP string `json:"inform_ip"` + InformURL string `json:"inform_url"` + IP string `json:"ip"` + JumboframeEnabled FlexBool `json:"jumboframe_enabled"` + LedOverride string `json:"led_override"` + LicenseState string `json:"license_state"` + Mac string `json:"mac"` + Model string `json:"model"` + Name string `json:"name"` + OutdoorModeOverride string `json:"outdoor_mode_override"` + PortOverrides []struct { Name string `json:"name,omitempty"` PoeMode string `json:"poe_mode,omitempty"` PortIdx FlexInt `json:"port_idx"` PortconfID string `json:"portconf_id"` } `json:"port_overrides"` - PortTable []Port `json:"port_table"` - Serial string `json:"serial"` - SiteID string `json:"site_id"` - StpPriority FlexInt `json:"stp_priority"` - StpVersion string `json:"stp_version"` - Type string `json:"type"` - Version string `json:"version"` - RequiredVersion string `json:"required_version"` - SwitchCaps *SwitchCaps `json:"switch_caps"` - HwCaps FlexInt `json:"hw_caps"` - Unsupported FlexBool `json:"unsupported"` - UnsupportedReason FlexInt `json:"unsupported_reason"` - SysErrorCaps FlexInt `json:"sys_error_caps"` - DeviceID string `json:"device_id"` - State FlexInt `json:"state"` - LastSeen FlexInt `json:"last_seen"` - Upgradable FlexBool `json:"upgradable,omitempty"` - AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded,omitempty"` - Rollupgrade FlexBool `json:"rollupgrade,omitempty"` - KnownCfgversion string `json:"known_cfgversion"` - Uptime FlexInt `json:"uptime"` - Locating FlexBool `json:"locating"` - ConnectRequestIP string `json:"connect_request_ip"` - ConnectRequestPort string `json:"connect_request_port"` - SysStats SysStats `json:"sys_stats"` - SystemStats SystemStats `json:"system-stats"` - FanLevel FlexInt `json:"fan_level"` - GeneralTemperature FlexInt `json:"general_temperature"` - Overheating FlexBool `json:"overheating"` - TotalMaxPower FlexInt `json:"total_max_power"` - DownlinkTable []struct { - PortIdx FlexInt `json:"port_idx"` - Speed FlexInt `json:"speed"` - FullDuplex FlexBool `json:"full_duplex"` - Mac string `json:"mac"` - } `json:"downlink_table"` - Uplink Uplink `json:"uplink"` - LastUplink struct { + PortTable []Port `json:"port_table"` + Serial string `json:"serial"` + SiteID string `json:"site_id"` + StpPriority FlexInt `json:"stp_priority"` + StpVersion string `json:"stp_version"` + Type string `json:"type"` + Version string `json:"version"` + RequiredVersion string `json:"required_version"` + SwitchCaps *SwitchCaps `json:"switch_caps"` + HwCaps FlexInt `json:"hw_caps"` + Unsupported FlexBool `json:"unsupported"` + UnsupportedReason FlexInt `json:"unsupported_reason"` + SysErrorCaps FlexInt `json:"sys_error_caps"` + DeviceID string `json:"device_id"` + State FlexInt `json:"state"` + LastSeen FlexInt `json:"last_seen"` + Upgradable FlexBool `json:"upgradable,omitempty"` + AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded,omitempty"` + Rollupgrade FlexBool `json:"rollupgrade,omitempty"` + KnownCfgversion string `json:"known_cfgversion"` + Uptime FlexInt `json:"uptime"` + Locating FlexBool `json:"locating"` + ConnectRequestIP string `json:"connect_request_ip"` + ConnectRequestPort string `json:"connect_request_port"` + SysStats SysStats `json:"sys_stats"` + SystemStats SystemStats `json:"system-stats"` + FanLevel FlexInt `json:"fan_level"` + GeneralTemperature FlexInt `json:"general_temperature"` + Overheating FlexBool `json:"overheating"` + TotalMaxPower FlexInt `json:"total_max_power"` + DownlinkTable []*DownlinkTable `json:"downlink_table"` + Uplink Uplink `json:"uplink"` + LastUplink struct { UplinkMac string `json:"uplink_mac"` } `json:"last_uplink"` UplinkDepth FlexInt `json:"uplink_depth"` @@ -109,7 +97,8 @@ type MacTable struct { Mac string `json:"mac"` } -// Port is a physical connection on a USW or UDM. +// Port is a physical connection on a USW or Gateway. +// Not every port has the same capabilities. type Port struct { AggregatedBy FlexBool `json:"aggregated_by"` Autoneg FlexBool `json:"autoneg,omitempty"` diff --git a/core/unifi/uxg.go b/core/unifi/uxg.go index 41604087..41ee2046 100644 --- a/core/unifi/uxg.go +++ b/core/unifi/uxg.go @@ -9,15 +9,15 @@ type UXG struct { IP string `json:"ip"` Mac string `json:"mac"` Model string `json:"model"` - ModelInLts bool `json:"model_in_lts"` - ModelInEol bool `json:"model_in_eol"` + ModelInLts FlexBool `json:"model_in_lts"` + ModelInEol FlexBool `json:"model_in_eol"` Type string `json:"type"` Version string `json:"version"` - Adopted bool `json:"adopted"` + Adopted FlexBool `json:"adopted"` SiteID string `json:"site_id"` Cfgversion string `json:"cfgversion"` SyslogKey string `json:"syslog_key"` - ConfigNetwork ConfigNetwork `json:"config_network"` + ConfigNetwork *ConfigNetwork `json:"config_network"` SetupID string `json:"setup_id"` LicenseState string `json:"license_state"` ConfigNetworkLan *ConfigNetworkLan `json:"config_network_lan"` @@ -28,22 +28,22 @@ type UXG struct { Architecture string `json:"architecture"` BoardRev FlexInt `json:"board_rev"` ManufacturerID FlexInt `json:"manufacturer_id"` - Internet bool `json:"internet"` - ModelIncompatible bool `json:"model_incompatible"` + Internet FlexBool `json:"internet"` + ModelIncompatible FlexBool `json:"model_incompatible"` EthernetTable []*EthernetTable `json:"ethernet_table"` PortTable []*Port `json:"port_table"` EthernetOverrides []*EthernetOverrides `json:"ethernet_overrides"` UsgCaps FlexInt `json:"usg_caps"` - HasSpeaker bool `json:"has_speaker"` - HasEth1 bool `json:"has_eth1"` + HasSpeaker FlexBool `json:"has_speaker"` + HasEth1 FlexBool `json:"has_eth1"` FwCaps FlexInt `json:"fw_caps"` HwCaps FlexInt `json:"hw_caps"` WifiCaps FlexInt `json:"wifi_caps"` SwitchCaps *SwitchCaps `json:"switch_caps"` - HasFan bool `json:"has_fan"` - HasTemperature bool `json:"has_temperature"` + HasFan FlexBool `json:"has_fan"` + HasTemperature FlexBool `json:"has_temperature"` Temperatures []*Temperature `json:"temperatures"` - Storage []Storage `json:"storage"` + Storage []*Storage `json:"storage"` RulesetInterfaces interface{} `json:"ruleset_interfaces"` ConnectedAt FlexInt `json:"connected_at"` ProvisionedAt FlexInt `json:"provisioned_at"` @@ -51,36 +51,36 @@ type UXG struct { LedOverrideColor string `json:"led_override_color"` LedOverrideColorBrightness FlexInt `json:"led_override_color_brightness"` OutdoorModeOverride string `json:"outdoor_mode_override"` - LcmBrightnessOverride bool `json:"lcm_brightness_override"` - LcmIdleTimeoutOverride bool `json:"lcm_idle_timeout_override"` + LcmBrightnessOverride FlexBool `json:"lcm_brightness_override"` + LcmIdleTimeoutOverride FlexBool `json:"lcm_idle_timeout_override"` Name string `json:"name"` - Unsupported bool `json:"unsupported"` + Unsupported FlexBool `json:"unsupported"` UnsupportedReason FlexInt `json:"unsupported_reason"` Serial string `json:"serial"` HashID string `json:"hash_id"` - TwoPhaseAdopt bool `json:"two_phase_adopt"` + TwoPhaseAdopt FlexBool `json:"two_phase_adopt"` DeviceID string `json:"device_id"` State FlexInt `json:"state"` - StartDisconnectedMillis int64 `json:"start_disconnected_millis"` + StartDisconnectedMillis FlexInt `json:"start_disconnected_millis"` UpgradeState FlexInt `json:"upgrade_state"` - StartConnectedMillis int64 `json:"start_connected_millis"` + StartConnectedMillis FlexInt `json:"start_connected_millis"` LastSeen FlexInt `json:"last_seen"` Uptime FlexInt `json:"uptime"` UnderscoreUptime FlexInt `json:"_uptime"` - Locating bool `json:"locating"` + Locating FlexBool `json:"locating"` SysStats *SysStats `json:"sys_stats"` SystemStats *SystemStats `json:"system-stats"` GuestKicks FlexInt `json:"guest_kicks"` GuestToken string `json:"guest_token"` UptimeStats map[string]*UptimeStats `json:"uptime_stats"` - Overheating bool `json:"overheating"` + Overheating FlexBool `json:"overheating"` GeoInfo map[string]*GeoInfo `json:"geo_info"` LedState *LedState `json:"led_state"` SpeedtestStatus *SpeedtestStatus `json:"speedtest-status"` - SpeedtestStatusSaved bool `json:"speedtest-status-saved"` + SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"` Wan1 *Wan `json:"wan1"` Wan2 *Wan `json:"wan2"` - Uplink Uplink `json:"uplink"` + Uplink *Uplink `json:"uplink"` DownlinkTable []*DownlinkTable `json:"downlink_table"` NetworkTable []*NetworkTable `json:"network_table"` KnownCfgversion string `json:"known_cfgversion"` @@ -91,8 +91,8 @@ type UXG struct { ConsideredLostAt FlexInt `json:"considered_lost_at"` Stat *UXGStat `json:"stat"` TxBytes FlexInt `json:"tx_bytes"` - RxBytes int64 `json:"rx_bytes"` - Bytes int64 `json:"bytes"` + RxBytes FlexInt `json:"rx_bytes"` + Bytes FlexInt `json:"bytes"` NumSta FlexInt `json:"num_sta"` WlanNumSta FlexInt `json:"wlan-num_sta"` LanNumSta FlexInt `json:"lan-num_sta"` @@ -121,11 +121,13 @@ type DownlinkTable struct { Mac string `json:"mac"` } +// LedState is incuded with newer devices. type LedState struct { Pattern string `json:"pattern"` Tempo FlexInt `json:"tempo"` } +// GeoInfo is incuded with certain devices. type GeoInfo struct { Accuracy FlexInt `json:"accuracy"` Address string `json:"address"` @@ -141,14 +143,14 @@ type GeoInfo struct { Timezone string `json:"timezone"` } +// UptimeStats is incuded with certain devices. type UptimeStats struct { Availability FlexInt `json:"availability"` LatencyAverage FlexInt `json:"latency_average"` TimePeriod FlexInt `json:"time_period"` } -// UDMStat holds the "stat" data for a dream machine. -// A dream machine is a USG + USW + Controller. +// UXGStat holds the "stat" data for a 10Gb gateway. type UXGStat struct { *Gw `json:"gw"` *Sw `json:"sw"` From 77279ea31c5ac4ff7ad30d0c9d68521c5e6fdbea Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 7 Mar 2021 18:23:16 -0800 Subject: [PATCH 170/194] fix all lint --- core/unifi/.travis.yml | 4 +- core/unifi/devices.go | 85 +++++++++++++++++++++++++++--------------- core/unifi/events.go | 6 ++- core/unifi/go.mod | 6 +-- core/unifi/go.sum | 6 +++ core/unifi/networks.go | 2 +- core/unifi/types.go | 18 ++++----- core/unifi/unifi.go | 28 +++++++++----- 8 files changed, 97 insertions(+), 58 deletions(-) diff --git a/core/unifi/.travis.yml b/core/unifi/.travis.yml index 654efb02..b8e3b955 100644 --- a/core/unifi/.travis.yml +++ b/core/unifi/.travis.yml @@ -1,9 +1,9 @@ language: go go: -- 1.14.x +- 1.15.x before_install: # download super-linter: golangci-lint - curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin latest script: -- golangci-lint run --enable-all +- golangci-lint run --enable-all -D exhaustivestruct,nlreturn - go test ./... diff --git a/core/unifi/devices.go b/core/unifi/devices.go index 505d2743..13a5bac0 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -36,48 +36,27 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { for _, r := range data { // Loop each item in the raw JSON message, detect its type and unmarshal it. - assetType := "" - - if o := make(map[string]interface{}); u.unmarshalDevice("map", r, &o) != nil { + o := make(map[string]interface{}) + if u.unmarshalDevice("map", r, &o) != nil { + u.ErrorLog("unknown asset type - cannot find asset type in payload - skipping") continue - } else if t, ok := o["type"].(string); ok { - assetType = t } + assetType, _ := o["type"].(string) u.DebugLog("Unmarshalling Device Type: %v, site %s ", assetType, siteName) // 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, SourceName: u.URL} - if u.unmarshalDevice(assetType, r, dev) == nil { - dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) - devices.UAPs = append(devices.UAPs, dev) - } + u.unmarshallUAP(siteName, r, devices) case "ugw", "usg": // in case they ever fix the name in the api. - dev := &USG{SiteName: siteName, SourceName: u.URL} - if u.unmarshalDevice(assetType, r, dev) == nil { - dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) - devices.USGs = append(devices.USGs, dev) - } + u.unmarshallUSG(siteName, r, devices) case "usw": - dev := &USW{SiteName: siteName, SourceName: u.URL} - if u.unmarshalDevice(assetType, r, dev) == nil { - dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) - devices.USWs = append(devices.USWs, dev) - } + u.unmarshallUSW(siteName, r, devices) case "udm": - dev := &UDM{SiteName: siteName, SourceName: u.URL} - if u.unmarshalDevice(assetType, r, dev) == nil { - dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) - devices.UDMs = append(devices.UDMs, dev) - } + u.unmarshallUDM(siteName, r, devices) case "uxg": - dev := &UXG{SiteName: siteName, SourceName: u.URL} - if u.unmarshalDevice(assetType, r, dev) == nil { - dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) - devices.UXGs = append(devices.UXGs, dev) - } + u.unmarshallUXG(siteName, r, devices) default: u.ErrorLog("unknown asset type - %v - skipping", assetType) } @@ -86,6 +65,46 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { return devices } +func (u *Unifi) unmarshallUAP(siteName string, payload json.RawMessage, devices *Devices) { + dev := &UAP{SiteName: siteName, SourceName: u.URL} + if u.unmarshalDevice("uap", payload, dev) == nil { + dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) + devices.UAPs = append(devices.UAPs, dev) + } +} + +func (u *Unifi) unmarshallUSG(siteName string, payload json.RawMessage, devices *Devices) { + dev := &USG{SiteName: siteName, SourceName: u.URL} + if u.unmarshalDevice("ugw", payload, dev) == nil { + dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) + devices.USGs = append(devices.USGs, dev) + } +} + +func (u *Unifi) unmarshallUSW(siteName string, payload json.RawMessage, devices *Devices) { + dev := &USW{SiteName: siteName, SourceName: u.URL} + if u.unmarshalDevice("usw", payload, dev) == nil { + dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) + devices.USWs = append(devices.USWs, dev) + } +} + +func (u *Unifi) unmarshallUXG(siteName string, payload json.RawMessage, devices *Devices) { + dev := &UXG{SiteName: siteName, SourceName: u.URL} + if u.unmarshalDevice("uxg", payload, dev) == nil { + dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) + devices.UXGs = append(devices.UXGs, dev) + } +} + +func (u *Unifi) unmarshallUDM(siteName string, payload json.RawMessage, devices *Devices) { + dev := &UDM{SiteName: siteName, SourceName: u.URL} + if u.unmarshalDevice("udm", payload, dev) == nil { + dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) + devices.UDMs = append(devices.UDMs, dev) + } +} + // unmarshalDevice handles logging for the unmarshal operations in parseDevices(). func (u *Unifi) unmarshalDevice(dev string, data json.RawMessage, v interface{}) (err error) { if err = json.Unmarshal(data, v); err != nil { @@ -98,7 +117,11 @@ func (u *Unifi) unmarshalDevice(dev string, data json.RawMessage, v interface{}) u.DebugLog("==- https://github.com/unifi-poller/unifi/issues/new -==") } - return err + if err != nil { + return fmt.Errorf("json unmarshal: %w", err) + } + + return nil } // pick returns the first non empty string in a list. diff --git a/core/unifi/events.go b/core/unifi/events.go index d716daee..d43cf4f9 100644 --- a/core/unifi/events.go +++ b/core/unifi/events.go @@ -196,5 +196,9 @@ func (v *IPGeo) UnmarshalJSON(data []byte) error { v.CountryName = g.CountryName v.Organization = g.Organization - return err + if err != nil { + return fmt.Errorf("json unmarshal: %w", err) + } + + return nil } diff --git a/core/unifi/go.mod b/core/unifi/go.mod index 219ef9dc..9aade56e 100644 --- a/core/unifi/go.mod +++ b/core/unifi/go.mod @@ -1,10 +1,10 @@ module github.com/unifi-poller/unifi -go 1.14 +go 1.15 require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.4.0 - golang.org/x/net v0.0.0-20200625001655-4c5254603344 + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect + golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 ) diff --git a/core/unifi/go.sum b/core/unifi/go.sum index 52fd963e..d2c30146 100644 --- a/core/unifi/go.sum +++ b/core/unifi/go.sum @@ -13,10 +13,16 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= diff --git a/core/unifi/networks.go b/core/unifi/networks.go index 05915432..f0e4a876 100644 --- a/core/unifi/networks.go +++ b/core/unifi/networks.go @@ -38,7 +38,7 @@ func (u *Unifi) parseNetwork(data json.RawMessage, siteName string) (*Network, e return network, u.unmarshalDevice(siteName, data, network) } -// Network is metadata about a network managed by a UniFi controller +// Network is metadata about a network managed by a UniFi controller. type Network struct { DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"` DhcpdEnabled FlexBool `json:"dhcpd_enabled"` diff --git a/core/unifi/types.go b/core/unifi/types.go index b3ce54a8..1413402a 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -7,13 +7,9 @@ import ( "strconv" "strings" "time" - - "github.com/pkg/errors" ) -var ( - errCannotUnmarshalFlexInt = fmt.Errorf("cannot unmarshal to FlexInt") -) +var ErrCannotUnmarshalFlexInt = fmt.Errorf("cannot unmarshal to FlexInt") // This is a list of unifi API paths. // The %s in each string must be replaced with a Site.Name. @@ -28,17 +24,17 @@ const ( APISiteDPI string = "/api/s/%s/stat/sitedpi" // APISiteDPI is site DPI data. APIClientDPI string = "/api/s/%s/stat/stadpi" - // APIClientPath is Unifi Clients API Path + // APIClientPath is Unifi Clients API Path. APIClientPath string = "/api/s/%s/stat/sta" // APINetworkPath is where we get data about Unifi networks. APINetworkPath string = "/api/s/%s/rest/networkconf" // APIDevicePath is where we get data about Unifi devices. APIDevicePath string = "/api/s/%s/stat/device" - // APILoginPath is Unifi Controller Login API Path + // APILoginPath is Unifi Controller Login API Path. APILoginPath string = "/api/login" - // APILoginPathNew is how we log into UDM 5.12.55+ + // APILoginPathNew is how we log into UDM 5.12.55+. APILoginPathNew string = "/api/auth/login" - // APIEventPathIDS returns Intrusion Detection/Prevention Systems Events + // APIEventPathIDS returns Intrusion Detection/Prevention Systems Events. APIEventPathIDS string = "/api/s/%s/stat/ips/event" // APIEventPathAlarms contains the site alarms. APIEventPathAlarms string = "/api/s/%s/list/alarm" @@ -127,7 +123,7 @@ func (f *FlexInt) UnmarshalJSON(b []byte) error { var unk interface{} if err := json.Unmarshal(b, &unk); err != nil { - return err + return fmt.Errorf("json unmarshal: %w", err) } switch i := unk.(type) { @@ -141,7 +137,7 @@ func (f *FlexInt) UnmarshalJSON(b []byte) error { f.Txt = "0" f.Val = 0 default: - return errors.Wrapf(errCannotUnmarshalFlexInt, "%v", b) + return fmt.Errorf("%v: %w", b, ErrCannotUnmarshalFlexInt) } return nil diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index b5e8aa21..4f05463b 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -34,7 +34,7 @@ var ( func NewUnifi(config *Config) (*Unifi, error) { jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List}) if err != nil { - return nil, err + return nil, fmt.Errorf("creating cookiejar: %w", err) } config.URL = strings.TrimRight(config.URL, "/") @@ -85,7 +85,7 @@ func (u *Unifi) Login() error { resp, err := u.Do(req) if err != nil { - return err + return fmt.Errorf("making request: %w", err) } defer resp.Body.Close() // we need no data here. @@ -106,11 +106,21 @@ func (u *Unifi) Login() error { // check if this is a newer controller or not. If it is, we set new to true. // Setting new to true makes the path() method return different (new) paths. func (u *Unifi) checkNewStyleAPI() error { + var ( + ctx = context.Background() + cancel func() + ) + + if u.Config.Timeout != 0 { + ctx, cancel = context.WithTimeout(ctx, u.Config.Timeout) + defer cancel() + } + u.DebugLog("Requesting %s/ to determine API paths", u.URL) - req, err := http.NewRequest("GET", u.URL+"/", nil) + req, err := http.NewRequestWithContext(ctx, "GET", u.URL+"/", nil) if err != nil { - return err + return fmt.Errorf("creating request: %w", err) } // We can't share these cookies with other requests, so make a new client. @@ -126,7 +136,7 @@ func (u *Unifi) checkNewStyleAPI() error { resp, err := client.Do(req) if err != nil { - return err + return fmt.Errorf("making request: %w", err) } defer resp.Body.Close() // we need no data here. @@ -210,7 +220,7 @@ func (u *Unifi) UniReq(apiPath string, params string) (*http.Request, error) { return req, nil } -// UniReqPut is the Put call equivalent to UniReq +// UniReqPut is the Put call equivalent to UniReq. func (u *Unifi) UniReqPut(apiPath string, params string) (*http.Request, error) { if params == "" { return nil, ErrNoParams @@ -239,7 +249,7 @@ func (u *Unifi) GetJSON(apiPath string, params ...string) ([]byte, error) { } // PutJSON uses a PUT call and returns the raw JSON in the same way as GetData -// Use this if you want to change data via the REST API +// Use this if you want to change data via the REST API. func (u *Unifi) PutJSON(apiPath string, params ...string) ([]byte, error) { req, err := u.UniReqPut(apiPath, strings.Join(params, " ")) if err != nil { @@ -262,14 +272,14 @@ func (u *Unifi) do(req *http.Request) ([]byte, error) { resp, err := u.Do(req.WithContext(ctx)) if err != nil { - return []byte{}, err + return []byte{}, fmt.Errorf("making request: %w", err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - return body, err + return body, fmt.Errorf("reading response: %w", err) } // Save the returned CSRF header. From adba3633f80e0f447549bc013efea7d621ed7f57 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 7 Mar 2021 18:34:41 -0800 Subject: [PATCH 171/194] add temperature to usg --- core/unifi/usg.go | 1 + 1 file changed, 1 insertion(+) diff --git a/core/unifi/usg.go b/core/unifi/usg.go index 751b76f8..9b265a5a 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg.go @@ -47,6 +47,7 @@ type USG struct { ConnectRequestIP string `json:"connect_request_ip"` ConnectRequestPort string `json:"connect_request_port"` SysStats SysStats `json:"sys_stats"` + Temperatures []Temperature `json:"temperatures,omitempty"` SystemStats SystemStats `json:"system-stats"` GuestToken string `json:"guest_token"` SpeedtestStatus SpeedtestStatus `json:"speedtest-status"` From 8616983696fb7428b34d9b54f445dd3b29b4ab40 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 7 Mar 2021 23:47:27 -0800 Subject: [PATCH 172/194] add ability to power cycle USW port --- core/unifi/devices.go | 76 +++++++++++++++++++++++++++++++++++++++++++ core/unifi/devmgr.go | 38 ++++++++++++++++++++++ core/unifi/types.go | 2 ++ core/unifi/uap.go | 1 + core/unifi/udm.go | 1 + core/unifi/usg.go | 1 + core/unifi/usw.go | 1 + core/unifi/uxg.go | 1 + 8 files changed, 121 insertions(+) create mode 100644 core/unifi/devmgr.go diff --git a/core/unifi/devices.go b/core/unifi/devices.go index 13a5bac0..05765254 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -25,11 +25,82 @@ func (u *Unifi) GetDevices(sites []*Site) (*Devices, error) { devices.USGs = append(devices.USGs, loopDevices.USGs...) devices.USWs = append(devices.USWs, loopDevices.USWs...) devices.UDMs = append(devices.UDMs, loopDevices.UDMs...) + devices.UXGs = append(devices.UXGs, loopDevices.UXGs...) } return devices, nil } +// GetUSWs returns all switches, an error, or nil if there are no switches. +func (u *Unifi) GetUSWs(siteName string) ([]*USW, error) { + var response struct { + Data []json.RawMessage `json:"data"` + } + + err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + if err != nil { + return nil, err + } + + return u.parseDevices(response.Data, siteName).USWs, nil +} + +// GetUSWs returns all access points, an error, or nil if there are no APs. +func (u *Unifi) GetUAPs(siteName string) ([]*UAP, error) { + var response struct { + Data []json.RawMessage `json:"data"` + } + + err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + if err != nil { + return nil, err + } + + return u.parseDevices(response.Data, siteName).UAPs, nil +} + +// GetUSWs returns all dream machines, an error, or nil if there are no UDMs. +func (u *Unifi) GetUDMs(siteName string) ([]*UDM, error) { + var response struct { + Data []json.RawMessage `json:"data"` + } + + err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + if err != nil { + return nil, err + } + + return u.parseDevices(response.Data, siteName).UDMs, nil +} + +// GetUSWs returns all 10Gb gateways, an error, or nil if there are no UXGs. +func (u *Unifi) GetUXGs(siteName string) ([]*UXG, error) { + var response struct { + Data []json.RawMessage `json:"data"` + } + + err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + if err != nil { + return nil, err + } + + return u.parseDevices(response.Data, siteName).UXGs, nil +} + +// GetUSWs returns all 1Gb gateways, an error, or nil if there are no USGs. +func (u *Unifi) GetUSGs(siteName string) ([]*USG, error) { + var response struct { + Data []json.RawMessage `json:"data"` + } + + err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + if err != nil { + return nil, err + } + + return u.parseDevices(response.Data, siteName).USGs, nil +} + // parseDevices parses the raw JSON from the Unifi Controller into device structures. func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { devices := new(Devices) @@ -69,6 +140,7 @@ func (u *Unifi) unmarshallUAP(siteName string, payload json.RawMessage, devices dev := &UAP{SiteName: siteName, SourceName: u.URL} if u.unmarshalDevice("uap", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) + dev.controller = u devices.UAPs = append(devices.UAPs, dev) } } @@ -77,6 +149,7 @@ func (u *Unifi) unmarshallUSG(siteName string, payload json.RawMessage, devices dev := &USG{SiteName: siteName, SourceName: u.URL} if u.unmarshalDevice("ugw", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) + dev.controller = u devices.USGs = append(devices.USGs, dev) } } @@ -85,6 +158,7 @@ func (u *Unifi) unmarshallUSW(siteName string, payload json.RawMessage, devices dev := &USW{SiteName: siteName, SourceName: u.URL} if u.unmarshalDevice("usw", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) + dev.controller = u devices.USWs = append(devices.USWs, dev) } } @@ -93,6 +167,7 @@ func (u *Unifi) unmarshallUXG(siteName string, payload json.RawMessage, devices dev := &UXG{SiteName: siteName, SourceName: u.URL} if u.unmarshalDevice("uxg", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) + dev.controller = u devices.UXGs = append(devices.UXGs, dev) } } @@ -101,6 +176,7 @@ func (u *Unifi) unmarshallUDM(siteName string, payload json.RawMessage, devices dev := &UDM{SiteName: siteName, SourceName: u.URL} if u.unmarshalDevice("udm", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) + dev.controller = u devices.UDMs = append(devices.UDMs, dev) } } diff --git a/core/unifi/devmgr.go b/core/unifi/devmgr.go new file mode 100644 index 00000000..1191e85c --- /dev/null +++ b/core/unifi/devmgr.go @@ -0,0 +1,38 @@ +package unifi + +import ( + "encoding/json" + "fmt" +) + +// Known commands that can be sent to device manager. +const ( + DevMgrPowerCycle = "power-cycle" +) + +// command is the type marshalled and sent to APIDevMgrPath. +type command struct { + Command string `json:"cmd"` + Mac string `json:"mac"` + PortIndex int `json:"port_idx"` +} + +// PowerCycle shuts off the PoE and turns it back on for a specific port. +// Get a USW from the device list to call this. +func (u *USW) PowerCycle(portIndex int) error { + data, err := json.Marshal(&command{ + Command: DevMgrPowerCycle, + Mac: u.Mac, + PortIndex: portIndex, + }) + if err != nil { + return fmt.Errorf("json marshal: %w", err) + } + + _, err = u.controller.GetJSON(APIDevMgrPath, string(data)) + if err != nil { + return fmt.Errorf("controller: %w", err) + } + + return nil +} diff --git a/core/unifi/types.go b/core/unifi/types.go index 1413402a..8ba093cd 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -42,6 +42,8 @@ const ( APIPrefixNew string = "/proxy/network" // APIAnomaliesPath returns site anomalies. APIAnomaliesPath string = "/api/s/%s/stat/anomalies" + APICommandPath string = "/api/s/%s/cmd" + APIDevMgrPath string = APICommandPath + "/devmgr" ) // path returns the correct api path based on the new variable. diff --git a/core/unifi/uap.go b/core/unifi/uap.go index 0d3b3172..35f3e891 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -8,6 +8,7 @@ import ( // UAP represents all the data from the Ubiquiti Controller for a Unifi Access Point. // This was auto generated then edited by hand to get all the data types right. type UAP struct { + controller *Unifi SourceName string `json:"-"` ID string `json:"_id"` Adopted FlexBool `json:"adopted"` diff --git a/core/unifi/udm.go b/core/unifi/udm.go index 49053539..a1f37add 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -3,6 +3,7 @@ package unifi // UDM represents all the data from the Ubiquiti Controller for a Unifi Dream Machine. // The UDM shares several structs/type-data with USW and USG. type UDM struct { + controller *Unifi SourceName string `json:"-"` SiteID string `json:"site_id"` SiteName string `json:"-"` diff --git a/core/unifi/usg.go b/core/unifi/usg.go index 9b265a5a..3815244a 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg.go @@ -7,6 +7,7 @@ import ( // USG represents all the data from the Ubiquiti Controller for a Unifi Security Gateway. type USG struct { + controller *Unifi SourceName string `json:"-"` ID string `json:"_id"` Adopted FlexBool `json:"adopted"` diff --git a/core/unifi/usw.go b/core/unifi/usw.go index 444577f2..bbc6fb03 100644 --- a/core/unifi/usw.go +++ b/core/unifi/usw.go @@ -7,6 +7,7 @@ import ( // USW represents all the data from the Ubiquiti Controller for a Unifi Switch. type USW struct { + controller *Unifi SourceName string `json:"-"` SiteName string `json:"-"` ID string `json:"_id"` diff --git a/core/unifi/uxg.go b/core/unifi/uxg.go index 41ee2046..b2bfb41b 100644 --- a/core/unifi/uxg.go +++ b/core/unifi/uxg.go @@ -3,6 +3,7 @@ package unifi // UXG represents all the data from the Ubiquiti Controller for a UniFi 10Gb Gateway. // The UDM shares several structs/type-data with USW and USG. type UXG struct { + controller *Unifi SourceName string `json:"-"` SiteName string `json:"-"` ID string `json:"_id"` From 49e4cbe228f83812cd4b9e226e5b89bf6d778e97 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Mon, 8 Mar 2021 01:04:12 -0800 Subject: [PATCH 173/194] add ability to pass in pinned certificates. --- core/unifi/types.go | 25 +++++++++++++++---- core/unifi/unifi.go | 59 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 70 insertions(+), 14 deletions(-) diff --git a/core/unifi/types.go b/core/unifi/types.go index 1413402a..8676f85b 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -47,7 +47,7 @@ const ( // path returns the correct api path based on the new variable. // new is based on the unifi-controller output. is it new or old output? func (u *Unifi) path(path string) string { - if u.New { + if u.new { if path == APILoginPath { return APILoginPathNew } @@ -80,16 +80,17 @@ type Devices struct { } // Config is the data passed into our library. This configures things and allows -// us to connect to a controller and write log messages. +// us to connect to a controller and write log messages. Optional SSLCert is used +// for ssl cert pinning; provide the content of a PEM to validate the server's cert. type Config struct { User string Pass string URL string - VerifySSL bool - New bool + SSLCert [][]byte ErrorLog Logger DebugLog Logger Timeout time.Duration // how long to wait for replies, default: forever. + VerifySSL bool } // Unifi is what you get in return for providing a password! Unifi represents @@ -100,7 +101,21 @@ type Unifi struct { *http.Client *Config *server - csrf string + csrf string + fingerprints fingerprints + new bool +} + +type fingerprints []string + +func (f fingerprints) Contains(s string) bool { + for i := range f { + if s == f[i] { + return true + } + } + + return false } // server is the /status endpoint from the Unifi controller. diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 4f05463b..93962065 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -8,8 +8,11 @@ package unifi import ( "bytes" "context" + "crypto/sha256" "crypto/tls" + "crypto/x509" "encoding/json" + "encoding/pem" "fmt" "io" "io/ioutil" @@ -26,6 +29,7 @@ var ( ErrAuthenticationFailed = fmt.Errorf("authentication failed") ErrInvalidStatusCode = fmt.Errorf("invalid status code from server") ErrNoParams = fmt.Errorf("requedted PUT with no parameters") + ErrInvalidSignature = fmt.Errorf("certificate signature does not match") ) // NewUnifi creates a http.Client with authenticated cookies. @@ -37,6 +41,29 @@ func NewUnifi(config *Config) (*Unifi, error) { return nil, fmt.Errorf("creating cookiejar: %w", err) } + u := newUnifi(config, jar) + + for i, cert := range config.SSLCert { + p, _ := pem.Decode(cert) + u.fingerprints[i] = fmt.Sprintf("%x", sha256.Sum256(p.Bytes)) + } + + if err := u.checkNewStyleAPI(); err != nil { + return u, err + } + + if err := u.Login(); err != nil { + return u, err + } + + if err := u.GetServerData(); err != nil { + return u, fmt.Errorf("unable to get server version: %w", err) + } + + return u, nil +} + +func newUnifi(config *Config, jar http.CookieJar) *Unifi { config.URL = strings.TrimRight(config.URL, "/") if config.ErrorLog == nil { @@ -53,24 +80,38 @@ func NewUnifi(config *Config) (*Unifi, error) { Timeout: config.Timeout, Jar: jar, Transport: &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: !config.VerifySSL}, // nolint: gosec + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: !config.VerifySSL, // nolint: gosec + }, }, }, } - if err := u.checkNewStyleAPI(); err != nil { - return u, err + if len(config.SSLCert) > 0 { + u.fingerprints = make(fingerprints, len(config.SSLCert)) + u.Client.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, // nolint: gosec + VerifyPeerCertificate: u.verifyPeerCertificate, + }, + } } - if err := u.Login(); err != nil { - return u, err + return u +} + +func (u *Unifi) verifyPeerCertificate(certs [][]byte, chains [][]*x509.Certificate) error { + if len(u.fingerprints) == 0 { + return nil } - if err := u.GetServerData(); err != nil { - return u, fmt.Errorf("unable to get server version: %w", err) + for _, cert := range certs { + if u.fingerprints.Contains(fmt.Sprintf("%x", sha256.Sum256(cert))) { + return nil + } } - return u, nil + return ErrInvalidSignature } // Login is a helper method. It can be called to grab a new authentication cookie. @@ -144,7 +185,7 @@ func (u *Unifi) checkNewStyleAPI() error { if resp.StatusCode == http.StatusOK { // The new version returns a "200" for a / request. - u.New = true + u.new = true u.DebugLog("Using NEW UniFi controller API paths for %s", req.URL) } From f520681b825134f3f587398bc7de64a5a8b5b6c2 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Mon, 8 Mar 2021 01:06:48 -0800 Subject: [PATCH 174/194] add comment --- core/unifi/types.go | 1 + 1 file changed, 1 insertion(+) diff --git a/core/unifi/types.go b/core/unifi/types.go index 8676f85b..5ae99f88 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -108,6 +108,7 @@ type Unifi struct { type fingerprints []string +// Contains returns true if the fingerprint is in the list. func (f fingerprints) Contains(s string) bool { for i := range f { if s == f[i] { From 01e06b1fd40d329c78116aee26b271a244ef882f Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Mon, 8 Mar 2021 01:32:12 -0800 Subject: [PATCH 175/194] add rogue ap methods --- core/unifi/types.go | 2 ++ core/unifi/uap.go | 77 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/core/unifi/types.go b/core/unifi/types.go index 1413402a..9f28a247 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -14,6 +14,8 @@ var ErrCannotUnmarshalFlexInt = fmt.Errorf("cannot unmarshal to FlexInt") // This is a list of unifi API paths. // The %s in each string must be replaced with a Site.Name. const ( + // APIRogueAP shows your neighbors' wifis. + APIRogueAP string = "/api/s/%s/stat/rogueap" // APIStatusPath shows Controller version. APIStatusPath string = "/status" // APIEventPath contains UniFi Event data. diff --git a/core/unifi/uap.go b/core/unifi/uap.go index 0d3b3172..c11b38eb 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -2,6 +2,7 @@ package unifi import ( "encoding/json" + "fmt" "time" ) @@ -549,6 +550,82 @@ type VapTable []struct { WlanconfID string `json:"wlanconf_id"` } +// RogueAP are your neighbors access points. +type RogueAP struct { + SourceName string `json:"-"` + SiteName string `json:"-"` + ID string `json:"_id"` + ApMac string `json:"ap_mac"` + Bssid string `json:"bssid"` + SiteID string `json:"site_id"` + Age FlexInt `json:"age"` + Band string `json:"band"` + Bw FlexInt `json:"bw"` + CenterFreq FlexInt `json:"center_freq"` + Channel int `json:"channel"` + Essid string `json:"essid"` + Freq FlexInt `json:"freq"` + IsAdhoc FlexBool `json:"is_adhoc"` + IsRogue FlexBool `json:"is_rogue"` + IsUbnt FlexBool `json:"is_ubnt"` + LastSeen FlexInt `json:"last_seen"` + Noise FlexInt `json:"noise"` + Radio string `json:"radio"` + RadioName string `json:"radio_name"` + ReportTime FlexInt `json:"report_time"` + Rssi FlexInt `json:"rssi"` + RssiAge FlexInt `json:"rssi_age"` + Security string `json:"security"` + Signal FlexInt `json:"signal"` + Oui string `json:"oui"` +} + +// GetRogueAPs returns RogueAPs for a list of Sites. +// Use GetRogueAPsSite if you want more control. +func (u *Unifi) GetRogueAPs(sites []*Site) ([]*RogueAP, error) { + data := []*RogueAP{} + + for _, site := range sites { + response, err := u.GetRogueAPsSite(site) + if err != nil { + return data, err + } + + data = append(data, response...) + } + + return data, nil +} + +// GetRogueAPsSite returns RogueAPs for a single Site. +func (u *Unifi) GetRogueAPsSite(site *Site) ([]*RogueAP, error) { + if site == nil || site.Name == "" { + return nil, ErrNoSiteProvided + } + + u.DebugLog("Polling Controller for RogueAPs, site %s (%s)", site.Name, site.Desc) + + var ( + path = fmt.Sprintf(APIRogueAP, site.Name) + rogueaps struct { + Data []*RogueAP `json:"data"` + } + ) + + if err := u.GetData(path, &rogueaps, ""); err != nil { + return rogueaps.Data, err + } + + for i := range rogueaps.Data { + // Add special SourceName value. + rogueaps.Data[i].SourceName = u.URL + // Add the special "Site Name" to each event. This becomes a Grafana filter somewhere. + rogueaps.Data[i].SiteName = site.Desc + " (" + site.Name + ")" + } + + return rogueaps.Data, nil +} + // UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Access Point Stat data. func (v *UAPStat) UnmarshalJSON(data []byte) error { var n struct { From 34672976ae5632df16968096f71017e733b96630 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Mar 2021 13:39:29 -0700 Subject: [PATCH 176/194] fix powercycle, add adopt, restart and scanrf --- core/unifi/devices.go | 71 +++++++++++++------------ core/unifi/devmgr.go | 120 ++++++++++++++++++++++++++++++++++++++++-- core/unifi/site.go | 3 ++ core/unifi/uap.go | 1 + core/unifi/udm.go | 1 + core/unifi/usg.go | 1 + core/unifi/usw.go | 1 + core/unifi/uxg.go | 1 + 8 files changed, 161 insertions(+), 38 deletions(-) diff --git a/core/unifi/devices.go b/core/unifi/devices.go index 05765254..5a3a468f 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -20,7 +20,7 @@ func (u *Unifi) GetDevices(sites []*Site) (*Devices, error) { return nil, err } - loopDevices := u.parseDevices(response.Data, site.SiteName) + loopDevices := u.parseDevices(response.Data, site) devices.UAPs = append(devices.UAPs, loopDevices.UAPs...) devices.USGs = append(devices.USGs, loopDevices.USGs...) devices.USWs = append(devices.USWs, loopDevices.USWs...) @@ -32,77 +32,77 @@ func (u *Unifi) GetDevices(sites []*Site) (*Devices, error) { } // GetUSWs returns all switches, an error, or nil if there are no switches. -func (u *Unifi) GetUSWs(siteName string) ([]*USW, error) { +func (u *Unifi) GetUSWs(site *Site) ([]*USW, error) { var response struct { Data []json.RawMessage `json:"data"` } - err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + err := u.GetData(fmt.Sprintf(APIDevicePath, site.Name), &response) if err != nil { return nil, err } - return u.parseDevices(response.Data, siteName).USWs, nil + return u.parseDevices(response.Data, site).USWs, nil } // GetUSWs returns all access points, an error, or nil if there are no APs. -func (u *Unifi) GetUAPs(siteName string) ([]*UAP, error) { +func (u *Unifi) GetUAPs(site *Site) ([]*UAP, error) { var response struct { Data []json.RawMessage `json:"data"` } - err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + err := u.GetData(fmt.Sprintf(APIDevicePath, site.Name), &response) if err != nil { return nil, err } - return u.parseDevices(response.Data, siteName).UAPs, nil + return u.parseDevices(response.Data, site).UAPs, nil } // GetUSWs returns all dream machines, an error, or nil if there are no UDMs. -func (u *Unifi) GetUDMs(siteName string) ([]*UDM, error) { +func (u *Unifi) GetUDMs(site *Site) ([]*UDM, error) { var response struct { Data []json.RawMessage `json:"data"` } - err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + err := u.GetData(fmt.Sprintf(APIDevicePath, site.Name), &response) if err != nil { return nil, err } - return u.parseDevices(response.Data, siteName).UDMs, nil + return u.parseDevices(response.Data, site).UDMs, nil } // GetUSWs returns all 10Gb gateways, an error, or nil if there are no UXGs. -func (u *Unifi) GetUXGs(siteName string) ([]*UXG, error) { +func (u *Unifi) GetUXGs(site *Site) ([]*UXG, error) { var response struct { Data []json.RawMessage `json:"data"` } - err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + err := u.GetData(fmt.Sprintf(APIDevicePath, site.Name), &response) if err != nil { return nil, err } - return u.parseDevices(response.Data, siteName).UXGs, nil + return u.parseDevices(response.Data, site).UXGs, nil } // GetUSWs returns all 1Gb gateways, an error, or nil if there are no USGs. -func (u *Unifi) GetUSGs(siteName string) ([]*USG, error) { +func (u *Unifi) GetUSGs(site *Site) ([]*USG, error) { var response struct { Data []json.RawMessage `json:"data"` } - err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + err := u.GetData(fmt.Sprintf(APIDevicePath, site.Name), &response) if err != nil { return nil, err } - return u.parseDevices(response.Data, siteName).USGs, nil + return u.parseDevices(response.Data, site).USGs, nil } // parseDevices parses the raw JSON from the Unifi Controller into device structures. -func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { +func (u *Unifi) parseDevices(data []json.RawMessage, site *Site) *Devices { devices := new(Devices) for _, r := range data { @@ -114,20 +114,20 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { } assetType, _ := o["type"].(string) - u.DebugLog("Unmarshalling Device Type: %v, site %s ", assetType, siteName) + u.DebugLog("Unmarshalling Device Type: %v, site %s ", assetType, site.Name) // Choose which type to unmarshal into based on the "type" json key. switch assetType { // Unmarshal again into the correct type.. case "uap": - u.unmarshallUAP(siteName, r, devices) + u.unmarshallUAP(site, r, devices) case "ugw", "usg": // in case they ever fix the name in the api. - u.unmarshallUSG(siteName, r, devices) + u.unmarshallUSG(site, r, devices) case "usw": - u.unmarshallUSW(siteName, r, devices) + u.unmarshallUSW(site, r, devices) case "udm": - u.unmarshallUDM(siteName, r, devices) + u.unmarshallUDM(site, r, devices) case "uxg": - u.unmarshallUXG(siteName, r, devices) + u.unmarshallUXG(site, r, devices) default: u.ErrorLog("unknown asset type - %v - skipping", assetType) } @@ -136,47 +136,52 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { return devices } -func (u *Unifi) unmarshallUAP(siteName string, payload json.RawMessage, devices *Devices) { - dev := &UAP{SiteName: siteName, SourceName: u.URL} +func (u *Unifi) unmarshallUAP(site *Site, payload json.RawMessage, devices *Devices) { + dev := &UAP{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("uap", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) dev.controller = u + dev.site = site devices.UAPs = append(devices.UAPs, dev) } } -func (u *Unifi) unmarshallUSG(siteName string, payload json.RawMessage, devices *Devices) { - dev := &USG{SiteName: siteName, SourceName: u.URL} +func (u *Unifi) unmarshallUSG(site *Site, payload json.RawMessage, devices *Devices) { + dev := &USG{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("ugw", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) dev.controller = u + dev.site = site devices.USGs = append(devices.USGs, dev) } } -func (u *Unifi) unmarshallUSW(siteName string, payload json.RawMessage, devices *Devices) { - dev := &USW{SiteName: siteName, SourceName: u.URL} +func (u *Unifi) unmarshallUSW(site *Site, payload json.RawMessage, devices *Devices) { + dev := &USW{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("usw", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) dev.controller = u + dev.site = site devices.USWs = append(devices.USWs, dev) } } -func (u *Unifi) unmarshallUXG(siteName string, payload json.RawMessage, devices *Devices) { - dev := &UXG{SiteName: siteName, SourceName: u.URL} +func (u *Unifi) unmarshallUXG(site *Site, payload json.RawMessage, devices *Devices) { + dev := &UXG{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("uxg", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) dev.controller = u + dev.site = site devices.UXGs = append(devices.UXGs, dev) } } -func (u *Unifi) unmarshallUDM(siteName string, payload json.RawMessage, devices *Devices) { - dev := &UDM{SiteName: siteName, SourceName: u.URL} +func (u *Unifi) unmarshallUDM(site *Site, payload json.RawMessage, devices *Devices) { + dev := &UDM{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("udm", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) dev.controller = u + dev.site = site devices.UDMs = append(devices.UDMs, dev) } } diff --git a/core/unifi/devmgr.go b/core/unifi/devmgr.go index 1191e85c..76d10a91 100644 --- a/core/unifi/devmgr.go +++ b/core/unifi/devmgr.go @@ -6,21 +6,36 @@ import ( ) // Known commands that can be sent to device manager. +//nolint:lll const ( - DevMgrPowerCycle = "power-cycle" + DevMgrPowerCycle = "power-cycle" // mac = switch mac (required), port_idx = PoE port to cycle (required) + DevMgrAdopt = "adopt" // mac = device mac (required) + DevMgrRestart = "restart" // mac = device mac (required) + DevMgrForceProvision = "force-provision" // mac = device mac (required) + DevMgrSpeedTest = "speedtest" // Start a speed test + DevMgrSpeedTestStatus = "speedtest-status" // Get current state of the speed test + DevMgrSetLocate = "set-locate" // mac = device mac (required): blink unit to locate + DevMgrUnsetLocate = "unset-locate" // mac = device mac (required): led to normal state + DevMgrUpgrade = "upgrade" // mac = device mac (required): upgrade firmware + DevMgrUpgradeExternal = "upgrade-external" // mac = device mac (required), url = firmware URL (required) + DevMgrMigrate = "migrate" // mac = device mac (required), inform_url = New Inform URL for device (required) + DevMgrCancelMigrate = "cancel-migrate" // mac = device mac (required) + DevMgrSpectrumScan = "spectrum-scan" // mac = AP mac (required): trigger RF scan ) // command is the type marshalled and sent to APIDevMgrPath. -type command struct { +type devMgrCommand struct { Command string `json:"cmd"` Mac string `json:"mac"` - PortIndex int `json:"port_idx"` + URL string `json:"url,omitempty"` + InformURL string `json:"inform_url,omitempty"` + PortIndex int `json:"port_idx,omitempty"` } // PowerCycle shuts off the PoE and turns it back on for a specific port. // Get a USW from the device list to call this. func (u *USW) PowerCycle(portIndex int) error { - data, err := json.Marshal(&command{ + data, err := json.Marshal(&devMgrCommand{ Command: DevMgrPowerCycle, Mac: u.Mac, PortIndex: portIndex, @@ -29,10 +44,105 @@ func (u *USW) PowerCycle(portIndex int) error { return fmt.Errorf("json marshal: %w", err) } - _, err = u.controller.GetJSON(APIDevMgrPath, string(data)) + _, err = u.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, u.SiteName), string(data)) if err != nil { return fmt.Errorf("controller: %w", err) } return nil } + +// ScanRF begins a spectrum scan on an access point. +func (u *UAP) ScanRF() error { + data, err := json.Marshal(&devMgrCommand{Command: DevMgrSpectrumScan, Mac: u.Mac}) + if err != nil { + return fmt.Errorf("json marshal: %w", err) + } + + _, err = u.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, u.SiteName), string(data)) + if err != nil { + return fmt.Errorf("controller: %w", err) + } + + return nil +} + +// Restart a device by MAC address on your site. +func (s *Site) Restart(mac string) error { + data, err := json.Marshal(&devMgrCommand{Command: DevMgrRestart, Mac: mac}) + if err != nil { + return fmt.Errorf("json marshal: %w", err) + } + + _, err = s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) + if err != nil { + return fmt.Errorf("controller: %w", err) + } + + return nil +} + +func (u *UAP) Restart() error { + return u.site.Restart(u.Mac) +} + +func (u *USW) Restart() error { + return u.site.Restart(u.Mac) +} + +func (u *USG) Restart() error { + return u.site.Restart(u.Mac) +} + +func (u *UDM) Restart() error { + return u.site.Restart(u.Mac) +} + +func (u *UXG) Restart() error { + return u.site.Restart(u.Mac) +} + +// Adopt a device by MAC address to your site. +func (s *Site) Adopt(mac string) error { + data, err := json.Marshal(&devMgrCommand{Command: DevMgrAdopt, Mac: mac}) + if err != nil { + return fmt.Errorf("json marshal: %w", err) + } + + _, err = s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) + if err != nil { + return fmt.Errorf("controller: %w", err) + } + + return nil +} + +// SpeedTest begins a speed test. +func (s *Site) SpeedTest() error { + data, err := json.Marshal(&devMgrCommand{Command: DevMgrSpeedTest}) + if err != nil { + return fmt.Errorf("json marshal: %w", err) + } + + _, err = s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) + if err != nil { + return fmt.Errorf("controller: %w", err) + } + + return nil +} + +// SpeedTestStatus returns the raw response for the status of a speed test. +func (s *Site) SpeedTestStatus() ([]byte, error) { + data, err := json.Marshal(&devMgrCommand{Command: DevMgrSpeedTestStatus}) + if err != nil { + return nil, fmt.Errorf("json marshal: %w", err) + } + + b, err := s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) + if err != nil { + return nil, fmt.Errorf("controller: %w", err) + } + + return b, nil +} diff --git a/core/unifi/site.go b/core/unifi/site.go index 0d3826a1..25030bfa 100644 --- a/core/unifi/site.go +++ b/core/unifi/site.go @@ -20,6 +20,8 @@ func (u *Unifi) GetSites() ([]*Site, error) { sites := []string{} // used for debug log only for i, d := range response.Data { + // Add the unifi struct to the site. + response.Data[i].controller = u // Add special SourceName value. response.Data[i].SourceName = u.URL // If the human name is missing (description), set it to the cryptic name. @@ -67,6 +69,7 @@ func (u *Unifi) GetSiteDPI(sites []*Site) ([]*DPITable, error) { // Site represents a site's data. type Site struct { + controller *Unifi SourceName string `json:"-"` ID string `json:"_id"` Name string `json:"name"` diff --git a/core/unifi/uap.go b/core/unifi/uap.go index 35f3e891..dcca4ae8 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -8,6 +8,7 @@ import ( // UAP represents all the data from the Ubiquiti Controller for a Unifi Access Point. // This was auto generated then edited by hand to get all the data types right. type UAP struct { + site *Site controller *Unifi SourceName string `json:"-"` ID string `json:"_id"` diff --git a/core/unifi/udm.go b/core/unifi/udm.go index a1f37add..fcc5ef4d 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -3,6 +3,7 @@ package unifi // UDM represents all the data from the Ubiquiti Controller for a Unifi Dream Machine. // The UDM shares several structs/type-data with USW and USG. type UDM struct { + site *Site controller *Unifi SourceName string `json:"-"` SiteID string `json:"site_id"` diff --git a/core/unifi/usg.go b/core/unifi/usg.go index 3815244a..a8c21008 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg.go @@ -7,6 +7,7 @@ import ( // USG represents all the data from the Ubiquiti Controller for a Unifi Security Gateway. type USG struct { + site *Site controller *Unifi SourceName string `json:"-"` ID string `json:"_id"` diff --git a/core/unifi/usw.go b/core/unifi/usw.go index bbc6fb03..b8500005 100644 --- a/core/unifi/usw.go +++ b/core/unifi/usw.go @@ -7,6 +7,7 @@ import ( // USW represents all the data from the Ubiquiti Controller for a Unifi Switch. type USW struct { + site *Site controller *Unifi SourceName string `json:"-"` SiteName string `json:"-"` diff --git a/core/unifi/uxg.go b/core/unifi/uxg.go index b2bfb41b..24ced7e6 100644 --- a/core/unifi/uxg.go +++ b/core/unifi/uxg.go @@ -3,6 +3,7 @@ package unifi // UXG represents all the data from the Ubiquiti Controller for a UniFi 10Gb Gateway. // The UDM shares several structs/type-data with USW and USG. type UXG struct { + site *Site controller *Unifi SourceName string `json:"-"` SiteName string `json:"-"` From c8c775f325c77cfdc9fc6b9a48aa9a59a27f8802 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Mar 2021 13:43:14 -0700 Subject: [PATCH 177/194] add comments --- core/unifi/devmgr.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/unifi/devmgr.go b/core/unifi/devmgr.go index 76d10a91..2a9176fe 100644 --- a/core/unifi/devmgr.go +++ b/core/unifi/devmgr.go @@ -82,22 +82,27 @@ func (s *Site) Restart(mac string) error { return nil } +// Restart an access point. func (u *UAP) Restart() error { return u.site.Restart(u.Mac) } +// Restart a switch. func (u *USW) Restart() error { return u.site.Restart(u.Mac) } +// Restart a security gateway. func (u *USG) Restart() error { return u.site.Restart(u.Mac) } +// Restart a dream machine. func (u *UDM) Restart() error { return u.site.Restart(u.Mac) } +// Restart a 10Gb security gateway. func (u *UXG) Restart() error { return u.site.Restart(u.Mac) } @@ -133,6 +138,7 @@ func (s *Site) SpeedTest() error { } // SpeedTestStatus returns the raw response for the status of a speed test. +// TODO: marshal the response into a data structure. This method will change! func (s *Site) SpeedTestStatus() ([]byte, error) { data, err := json.Marshal(&devMgrCommand{Command: DevMgrSpeedTestStatus}) if err != nil { From 9c923805a3ef63d9d4dec4a7e9dbceb4817e2053 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Mar 2021 14:29:32 -0700 Subject: [PATCH 178/194] add al devmgr commands --- core/unifi/devmgr.go | 295 +++++++++++++++++++++++++++++++------------ 1 file changed, 215 insertions(+), 80 deletions(-) diff --git a/core/unifi/devmgr.go b/core/unifi/devmgr.go index 2a9176fe..9841aac5 100644 --- a/core/unifi/devmgr.go +++ b/core/unifi/devmgr.go @@ -6,7 +6,7 @@ import ( ) // Known commands that can be sent to device manager. -//nolint:lll +//nolint:lll // https://ubntwiki.com/products/software/unifi-controller/api#callable const ( DevMgrPowerCycle = "power-cycle" // mac = switch mac (required), port_idx = PoE port to cycle (required) DevMgrAdopt = "adopt" // mac = device mac (required) @@ -23,63 +23,54 @@ const ( DevMgrSpectrumScan = "spectrum-scan" // mac = AP mac (required): trigger RF scan ) -// command is the type marshalled and sent to APIDevMgrPath. -type devMgrCommand struct { - Command string `json:"cmd"` - Mac string `json:"mac"` - URL string `json:"url,omitempty"` - InformURL string `json:"inform_url,omitempty"` - PortIndex int `json:"port_idx,omitempty"` +// devMgrCmd is the type marshalled and sent to APIDevMgrPath. +type devMgrCmd struct { + Cmd string `json:"cmd"` + Mac string `json:"mac"` + URL string `json:"url,omitempty"` + Inform string `json:"inform_url,omitempty"` + Port int `json:"port_idx,omitempty"` +} + +// devMgrCommandReply is for commands with a return value. +func (s *Site) devMgrCommandReply(cmd *devMgrCmd) ([]byte, error) { + data, err := json.Marshal(cmd) + if err != nil { + return nil, fmt.Errorf("json marshal: %w", err) + } + + b, err := s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) + if err != nil { + return nil, fmt.Errorf("controller: %w", err) + } + + return b, nil +} + +// devMgrCommandSimple is for commands with no return value. +func (s *Site) devMgrCommandSimple(cmd *devMgrCmd) error { + _, err := s.devMgrCommandReply(cmd) + return err } // PowerCycle shuts off the PoE and turns it back on for a specific port. // Get a USW from the device list to call this. func (u *USW) PowerCycle(portIndex int) error { - data, err := json.Marshal(&devMgrCommand{ - Command: DevMgrPowerCycle, - Mac: u.Mac, - PortIndex: portIndex, + return u.site.devMgrCommandSimple(&devMgrCmd{ + Cmd: DevMgrPowerCycle, + Mac: u.Mac, + Port: portIndex, }) - if err != nil { - return fmt.Errorf("json marshal: %w", err) - } - - _, err = u.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, u.SiteName), string(data)) - if err != nil { - return fmt.Errorf("controller: %w", err) - } - - return nil } // ScanRF begins a spectrum scan on an access point. func (u *UAP) ScanRF() error { - data, err := json.Marshal(&devMgrCommand{Command: DevMgrSpectrumScan, Mac: u.Mac}) - if err != nil { - return fmt.Errorf("json marshal: %w", err) - } - - _, err = u.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, u.SiteName), string(data)) - if err != nil { - return fmt.Errorf("controller: %w", err) - } - - return nil + return u.site.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrSpectrumScan, Mac: u.Mac}) } // Restart a device by MAC address on your site. func (s *Site) Restart(mac string) error { - data, err := json.Marshal(&devMgrCommand{Command: DevMgrRestart, Mac: mac}) - if err != nil { - return fmt.Errorf("json marshal: %w", err) - } - - _, err = s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) - if err != nil { - return fmt.Errorf("controller: %w", err) - } - - return nil + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrRestart, Mac: mac}) } // Restart an access point. @@ -107,48 +98,192 @@ func (u *UXG) Restart() error { return u.site.Restart(u.Mac) } -// Adopt a device by MAC address to your site. -func (s *Site) Adopt(mac string) error { - data, err := json.Marshal(&devMgrCommand{Command: DevMgrAdopt, Mac: mac}) - if err != nil { - return fmt.Errorf("json marshal: %w", err) - } - - _, err = s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) - if err != nil { - return fmt.Errorf("controller: %w", err) - } - - return nil +// Locate a device by MAC address on your site. This makes it blink. +func (s *Site) Locate(mac string) error { + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrSetLocate, Mac: mac}) } -// SpeedTest begins a speed test. +// Locate an access point. +func (u *UAP) Locate() error { + return u.site.Locate(u.Mac) +} + +// Locate a switch. +func (u *USW) Locate() error { + return u.site.Locate(u.Mac) +} + +// Locate a security gateway. +func (u *USG) Locate() error { + return u.site.Locate(u.Mac) +} + +// Locate a dream machine. +func (u *UDM) Locate() error { + return u.site.Locate(u.Mac) +} + +// Locate a 10Gb security gateway. +func (u *UXG) Locate() error { + return u.site.Locate(u.Mac) +} + +// Unlocate a device by MAC address on your site. This makes it stop blinking. +func (s *Site) Unlocate(mac string) error { + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrUnsetLocate, Mac: mac}) +} + +// Unlocate an access point (stop blinking). +func (u *UAP) Unlocate() error { + return u.site.Unlocate(u.Mac) +} + +// Unlocate a switch (stop blinking). +func (u *USW) Unlocate() error { + return u.site.Unlocate(u.Mac) +} + +// Unlocate a security gateway (stop blinking). +func (u *USG) Unlocate() error { + return u.site.Unlocate(u.Mac) +} + +// Unlocate a dream machine (stop blinking). +func (u *UDM) Unlocate() error { + return u.site.Unlocate(u.Mac) +} + +// Unlocate a 10Gb security gateway (stop blinking). +func (u *UXG) Unlocate() error { + return u.site.Unlocate(u.Mac) +} + +// Provision force provisions a device by MAC address on your site. +func (s *Site) Provision(mac string) error { + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrForceProvision, Mac: mac}) +} + +// Provision an access point forcefully. +func (u *UAP) Provision() error { + return u.site.Provision(u.Mac) +} + +// Provision a switch forcefully. +func (u *USW) Provision() error { + return u.site.Provision(u.Mac) +} + +// Provision a security gateway forcefully. +func (u *USG) Provision() error { + return u.site.Provision(u.Mac) +} + +// Provision a dream machine forcefully. +func (u *UDM) Provision() error { + return u.site.Provision(u.Mac) +} + +// Provision a 10Gb security gateway forcefully. +func (u *UXG) Provision() error { + return u.site.Provision(u.Mac) +} + +// Upgrade starts a firmware upgrade on a device by MAC address on your site. +// URL is optional. If provided an external upgrade is performed. +func (s *Site) Upgrade(mac string, url string) error { + if url == "" { + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrUpgrade, Mac: mac}) + } + + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrUpgradeExternal, Mac: mac, URL: url}) +} + +// Upgrade firmware on an access point. +// URL is optional. If provided an external upgrade is performed. +func (u *UAP) Upgrade(url string) error { + return u.site.Upgrade(u.Mac, url) +} + +// Upgrade firmware on a switch. +// URL is optional. If provided an external upgrade is performed. +func (u *USW) Upgrade(url string) error { + return u.site.Upgrade(u.Mac, url) +} + +// Upgrade firmware on a security gateway. +// URL is optional. If provided an external upgrade is performed. +func (u *USG) Upgrade(url string) error { + return u.site.Upgrade(u.Mac, url) +} + +// Upgrade firmware on a dream machine. +// URL is optional. If provided an external upgrade is performed. +func (u *UDM) Upgrade(url string) error { + return u.site.Upgrade(u.Mac, url) +} + +// Upgrade formware on a 10Gb security gateway. +// URL is optional. If provided an external upgrade is performed. +func (u *UXG) Upgrade(url string) error { + return u.site.Upgrade(u.Mac, url) +} + +// Migrate sends a device to another controller's URL. +// Probably does not work on devices with built-in controllers like UDM & UXG. +func (s *Site) Migrate(mac string, url string) error { + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrMigrate, Mac: mac, Inform: url}) +} + +// Migrate sends an access point to another controller's URL. +func (u *UAP) Migrate(url string) error { + return u.site.Migrate(u.Mac, url) +} + +// Migrate sends a switch to another controller's URL. +func (u *USW) Migrate(url string) error { + return u.site.Migrate(u.Mac, url) +} + +// Migrate sends a security gateway to another controller's URL. +func (u *USG) Migrate(url string) error { + return u.site.Migrate(u.Mac, url) +} + +// CancelMigrate stops a migration in progress. +// Probably does not work on devices with built-in controllers like UDM & UXG. +func (s *Site) CancelMigrate(mac string) error { + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrCancelMigrate, Mac: mac}) +} + +// CancelMigrate stops a migration in progress. +func (u *UAP) CancelMigrate() error { + return u.site.CancelMigrate(u.Mac) +} + +// CancelMigrate stops a migration in progress. +func (u *USW) CancelMigrate() error { + return u.site.CancelMigrate(u.Mac) +} + +// CancelMigrate stops a migration in progress. +func (u *USG) CancelMigrate() error { + return u.site.CancelMigrate(u.Mac) +} + +// Adopt a device by MAC address to your site. +func (s *Site) Adopt(mac string) error { + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrAdopt, Mac: mac}) +} + +// SpeedTest begins a speed test on a site. func (s *Site) SpeedTest() error { - data, err := json.Marshal(&devMgrCommand{Command: DevMgrSpeedTest}) - if err != nil { - return fmt.Errorf("json marshal: %w", err) - } - - _, err = s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) - if err != nil { - return fmt.Errorf("controller: %w", err) - } - - return nil + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrSpeedTest}) } // SpeedTestStatus returns the raw response for the status of a speed test. // TODO: marshal the response into a data structure. This method will change! func (s *Site) SpeedTestStatus() ([]byte, error) { - data, err := json.Marshal(&devMgrCommand{Command: DevMgrSpeedTestStatus}) - if err != nil { - return nil, fmt.Errorf("json marshal: %w", err) - } - - b, err := s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) - if err != nil { - return nil, fmt.Errorf("controller: %w", err) - } - - return b, nil + body, err := s.devMgrCommandReply(&devMgrCmd{Cmd: DevMgrSpeedTestStatus}) + // marshal into struct here. + return body, err } From e7e98a43f070136d20faee7f4c3eda75a84fd745 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Mar 2021 14:46:06 -0700 Subject: [PATCH 179/194] add migrate to UXG --- core/unifi/devmgr.go | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/core/unifi/devmgr.go b/core/unifi/devmgr.go index 9841aac5..43ed8dd4 100644 --- a/core/unifi/devmgr.go +++ b/core/unifi/devmgr.go @@ -5,7 +5,7 @@ import ( "fmt" ) -// Known commands that can be sent to device manager. +// Known commands that can be sent to device manager. All of these are implemented. //nolint:lll // https://ubntwiki.com/products/software/unifi-controller/api#callable const ( DevMgrPowerCycle = "power-cycle" // mac = switch mac (required), port_idx = PoE port to cycle (required) @@ -25,11 +25,11 @@ const ( // devMgrCmd is the type marshalled and sent to APIDevMgrPath. type devMgrCmd struct { - Cmd string `json:"cmd"` - Mac string `json:"mac"` - URL string `json:"url,omitempty"` - Inform string `json:"inform_url,omitempty"` - Port int `json:"port_idx,omitempty"` + Cmd string `json:"cmd"` // Required. + Mac string `json:"mac"` // Device MAC (required for most, but not all). + URL string `json:"url,omitempty"` // External Upgrade only. + Inform string `json:"inform_url,omitempty"` // Migration only. + Port int `json:"port_idx,omitempty"` // Power Cycle only. } // devMgrCommandReply is for commands with a return value. @@ -189,7 +189,7 @@ func (u *UXG) Provision() error { } // Upgrade starts a firmware upgrade on a device by MAC address on your site. -// URL is optional. If provided an external upgrade is performed. +// URL is optional. If URL is not "" an external upgrade is performed. func (s *Site) Upgrade(mac string, url string) error { if url == "" { return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrUpgrade, Mac: mac}) @@ -199,31 +199,31 @@ func (s *Site) Upgrade(mac string, url string) error { } // Upgrade firmware on an access point. -// URL is optional. If provided an external upgrade is performed. +// URL is optional. If URL is not "" an external upgrade is performed. func (u *UAP) Upgrade(url string) error { return u.site.Upgrade(u.Mac, url) } // Upgrade firmware on a switch. -// URL is optional. If provided an external upgrade is performed. +// URL is optional. If URL is not "" an external upgrade is performed. func (u *USW) Upgrade(url string) error { return u.site.Upgrade(u.Mac, url) } // Upgrade firmware on a security gateway. -// URL is optional. If provided an external upgrade is performed. +// URL is optional. If URL is not "" an external upgrade is performed. func (u *USG) Upgrade(url string) error { return u.site.Upgrade(u.Mac, url) } // Upgrade firmware on a dream machine. -// URL is optional. If provided an external upgrade is performed. +// URL is optional. If URL is not "" an external upgrade is performed. func (u *UDM) Upgrade(url string) error { return u.site.Upgrade(u.Mac, url) } // Upgrade formware on a 10Gb security gateway. -// URL is optional. If provided an external upgrade is performed. +// URL is optional. If URL is not "" an external upgrade is performed. func (u *UXG) Upgrade(url string) error { return u.site.Upgrade(u.Mac, url) } @@ -249,27 +249,37 @@ func (u *USG) Migrate(url string) error { return u.site.Migrate(u.Mac, url) } +// Migrate sends a 10Gb gateway to another controller's URL. +func (u *UXG) Migrate(url string) error { + return u.site.Migrate(u.Mac, url) +} + // CancelMigrate stops a migration in progress. // Probably does not work on devices with built-in controllers like UDM & UXG. func (s *Site) CancelMigrate(mac string) error { return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrCancelMigrate, Mac: mac}) } -// CancelMigrate stops a migration in progress. +// CancelMigrate stops an access point migration in progress. func (u *UAP) CancelMigrate() error { return u.site.CancelMigrate(u.Mac) } -// CancelMigrate stops a migration in progress. +// CancelMigrate stops a switch migration in progress. func (u *USW) CancelMigrate() error { return u.site.CancelMigrate(u.Mac) } -// CancelMigrate stops a migration in progress. +// CancelMigrate stops a security gateway migration in progress. func (u *USG) CancelMigrate() error { return u.site.CancelMigrate(u.Mac) } +// CancelMigrate stops 10Gb gateway a migration in progress. +func (u *UXG) CancelMigrate() error { + return u.site.CancelMigrate(u.Mac) +} + // Adopt a device by MAC address to your site. func (s *Site) Adopt(mac string) error { return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrAdopt, Mac: mac}) From 267e55906e46db51ccc3c3ed2474a4e4adf51047 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Mar 2021 14:48:55 -0700 Subject: [PATCH 180/194] fix build --- core/unifi/devmgr.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/devmgr.go b/core/unifi/devmgr.go index 43ed8dd4..679f6648 100644 --- a/core/unifi/devmgr.go +++ b/core/unifi/devmgr.go @@ -291,7 +291,7 @@ func (s *Site) SpeedTest() error { } // SpeedTestStatus returns the raw response for the status of a speed test. -// TODO: marshal the response into a data structure. This method will change! +// XXX: marshal the response into a data structure. This method will change! func (s *Site) SpeedTestStatus() ([]byte, error) { body, err := s.devMgrCommandReply(&devMgrCmd{Cmd: DevMgrSpeedTestStatus}) // marshal into struct here. From f2f2424302770bb4e6acee622a006e4df4db544d Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Mar 2021 15:01:30 -0700 Subject: [PATCH 181/194] Add SFP data to a Port. --- core/unifi/usw.go | 140 ++++++++++++++++++++++++++-------------------- 1 file changed, 78 insertions(+), 62 deletions(-) diff --git a/core/unifi/usw.go b/core/unifi/usw.go index 444577f2..c5dd571f 100644 --- a/core/unifi/usw.go +++ b/core/unifi/usw.go @@ -100,68 +100,84 @@ type MacTable struct { // Port is a physical connection on a USW or Gateway. // Not every port has the same capabilities. type Port struct { - AggregatedBy FlexBool `json:"aggregated_by"` - Autoneg FlexBool `json:"autoneg,omitempty"` - BytesR FlexInt `json:"bytes-r"` - DNS []string `json:"dns,omitempty"` - Dot1XMode string `json:"dot1x_mode"` - Dot1XStatus string `json:"dot1x_status"` - Enable FlexBool `json:"enable"` - FlowctrlRx FlexBool `json:"flowctrl_rx"` - FlowctrlTx FlexBool `json:"flowctrl_tx"` - FullDuplex FlexBool `json:"full_duplex"` - IP string `json:"ip,omitempty"` - Ifname string `json:"ifname,omitempty"` - IsUplink FlexBool `json:"is_uplink"` - Mac string `json:"mac,omitempty"` - MacTable []MacTable `json:"mac_table,omitempty"` - Jumbo FlexBool `json:"jumbo,omitempty"` - Masked FlexBool `json:"masked"` - Media string `json:"media"` - Name string `json:"name"` - NetworkName string `json:"network_name,omitempty"` - Netmask string `json:"netmask,omitempty"` - NumPort int `json:"num_port,omitempty"` - OpMode string `json:"op_mode"` - PoeCaps FlexInt `json:"poe_caps"` - PoeClass string `json:"poe_class,omitempty"` - PoeCurrent FlexInt `json:"poe_current,omitempty"` - PoeEnable FlexBool `json:"poe_enable,omitempty"` - PoeGood FlexBool `json:"poe_good,omitempty"` - PoeMode string `json:"poe_mode,omitempty"` - PoePower FlexInt `json:"poe_power,omitempty"` - PoeVoltage FlexInt `json:"poe_voltage,omitempty"` - PortDelta struct { - TimeDelta int64 `json:"time_delta"` - TimeDeltaActivity int64 `json:"time_delta_activity"` - } `json:"port_delta,omitempty"` - PortIdx FlexInt `json:"port_idx"` - PortPoe FlexBool `json:"port_poe"` - PortconfID string `json:"portconf_id"` - RxBroadcast FlexInt `json:"rx_broadcast"` - RxBytes FlexInt `json:"rx_bytes"` - RxBytesR FlexInt `json:"rx_bytes-r"` - RxDropped FlexInt `json:"rx_dropped"` - RxErrors FlexInt `json:"rx_errors"` - RxMulticast FlexInt `json:"rx_multicast"` - RxPackets FlexInt `json:"rx_packets"` - RxRate FlexInt `json:"rx_rate,omitempty"` - Satisfaction FlexInt `json:"satisfaction,omitempty"` - SfpFound FlexBool `json:"sfp_found,omitempty"` - Speed FlexInt `json:"speed"` - SpeedCaps FlexInt `json:"speed_caps"` - StpPathcost FlexInt `json:"stp_pathcost"` - StpState string `json:"stp_state"` - TxBroadcast FlexInt `json:"tx_broadcast"` - TxBytes FlexInt `json:"tx_bytes"` - TxBytesR FlexInt `json:"tx_bytes-r"` - TxDropped FlexInt `json:"tx_dropped"` - TxErrors FlexInt `json:"tx_errors"` - TxMulticast FlexInt `json:"tx_multicast"` - TxPackets FlexInt `json:"tx_packets"` - TxRate FlexInt `json:"tx_rate,omitempty"` - Type string `json:"type,omitempty"` - Up FlexBool `json:"up"` + AggregatedBy FlexBool `json:"aggregated_by"` + Autoneg FlexBool `json:"autoneg,omitempty"` + BytesR FlexInt `json:"bytes-r"` + DNS []string `json:"dns,omitempty"` + Dot1XMode string `json:"dot1x_mode"` + Dot1XStatus string `json:"dot1x_status"` + Enable FlexBool `json:"enable"` + FlowctrlRx FlexBool `json:"flowctrl_rx"` + FlowctrlTx FlexBool `json:"flowctrl_tx"` + FullDuplex FlexBool `json:"full_duplex"` + IP string `json:"ip,omitempty"` + Ifname string `json:"ifname,omitempty"` + IsUplink FlexBool `json:"is_uplink"` + Mac string `json:"mac,omitempty"` + MacTable []MacTable `json:"mac_table,omitempty"` + Jumbo FlexBool `json:"jumbo,omitempty"` + Masked FlexBool `json:"masked"` + Media string `json:"media"` + Name string `json:"name"` + NetworkName string `json:"network_name,omitempty"` + Netmask string `json:"netmask,omitempty"` + NumPort int `json:"num_port,omitempty"` + OpMode string `json:"op_mode"` + PoeCaps FlexInt `json:"poe_caps"` + PoeClass string `json:"poe_class,omitempty"` + PoeCurrent FlexInt `json:"poe_current,omitempty"` + PoeEnable FlexBool `json:"poe_enable,omitempty"` + PoeGood FlexBool `json:"poe_good,omitempty"` + PoeMode string `json:"poe_mode,omitempty"` + PoePower FlexInt `json:"poe_power,omitempty"` + PoeVoltage FlexInt `json:"poe_voltage,omitempty"` + PortDelta PortDelta `json:"port_delta,omitempty"` + PortIdx FlexInt `json:"port_idx"` + PortPoe FlexBool `json:"port_poe"` + PortconfID string `json:"portconf_id"` + RxBroadcast FlexInt `json:"rx_broadcast"` + RxBytes FlexInt `json:"rx_bytes"` + RxBytesR FlexInt `json:"rx_bytes-r"` + RxDropped FlexInt `json:"rx_dropped"` + RxErrors FlexInt `json:"rx_errors"` + RxMulticast FlexInt `json:"rx_multicast"` + RxPackets FlexInt `json:"rx_packets"` + RxRate FlexInt `json:"rx_rate,omitempty"` + Satisfaction FlexInt `json:"satisfaction,omitempty"` + SatisfactionReason FlexInt `json:"satisfaction_reason"` + SFPCompliance string `json:"sfp_compliance"` + SFPCurrent string `json:"sfp_current"` + SFPFound FlexBool `json:"sfp_found"` + SFPPart string `json:"sfp_part"` + SFPRev string `json:"sfp_rev"` + SFPRxfault FlexBool `json:"sfp_rxfault"` + SFPRxpower string `json:"sfp_rxpower"` + SFPSerial string `json:"sfp_serial"` + SFPTemperature string `json:"sfp_temperature"` + SFPTxfault FlexBool `json:"sfp_txfault"` + SFPTxpower string `json:"sfp_txpower"` + SFPVendor string `json:"sfp_vendor"` + SFPVoltage string `json:"sfp_voltage"` + Speed FlexInt `json:"speed"` + SpeedCaps FlexInt `json:"speed_caps"` + StpPathcost FlexInt `json:"stp_pathcost"` + StpState string `json:"stp_state"` + TxBroadcast FlexInt `json:"tx_broadcast"` + TxBytes FlexInt `json:"tx_bytes"` + TxBytesR FlexInt `json:"tx_bytes-r"` + TxDropped FlexInt `json:"tx_dropped"` + TxErrors FlexInt `json:"tx_errors"` + TxMulticast FlexInt `json:"tx_multicast"` + TxPackets FlexInt `json:"tx_packets"` + TxRate FlexInt `json:"tx_rate,omitempty"` + Type string `json:"type,omitempty"` + Up FlexBool `json:"up"` +} + +// PortDelta is part of a Port. +type PortDelta struct { + TimeDelta FlexInt `json:"time_delta"` + TimeDeltaActivity FlexInt `json:"time_delta_activity"` } // USWStat holds the "stat" data for a switch. From 813c96ffb63c86d851b27e60989bfeedd295c912 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Mar 2021 15:12:28 -0700 Subject: [PATCH 182/194] with controller on site do not need it per device --- core/unifi/devices.go | 5 ----- core/unifi/uap.go | 1 - core/unifi/udm.go | 1 - core/unifi/usg.go | 1 - core/unifi/usw.go | 1 - core/unifi/uxg.go | 1 - 6 files changed, 10 deletions(-) diff --git a/core/unifi/devices.go b/core/unifi/devices.go index 5a3a468f..35003694 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -140,7 +140,6 @@ func (u *Unifi) unmarshallUAP(site *Site, payload json.RawMessage, devices *Devi dev := &UAP{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("uap", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) - dev.controller = u dev.site = site devices.UAPs = append(devices.UAPs, dev) } @@ -150,7 +149,6 @@ func (u *Unifi) unmarshallUSG(site *Site, payload json.RawMessage, devices *Devi dev := &USG{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("ugw", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) - dev.controller = u dev.site = site devices.USGs = append(devices.USGs, dev) } @@ -160,7 +158,6 @@ func (u *Unifi) unmarshallUSW(site *Site, payload json.RawMessage, devices *Devi dev := &USW{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("usw", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) - dev.controller = u dev.site = site devices.USWs = append(devices.USWs, dev) } @@ -170,7 +167,6 @@ func (u *Unifi) unmarshallUXG(site *Site, payload json.RawMessage, devices *Devi dev := &UXG{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("uxg", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) - dev.controller = u dev.site = site devices.UXGs = append(devices.UXGs, dev) } @@ -180,7 +176,6 @@ func (u *Unifi) unmarshallUDM(site *Site, payload json.RawMessage, devices *Devi dev := &UDM{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("udm", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) - dev.controller = u dev.site = site devices.UDMs = append(devices.UDMs, dev) } diff --git a/core/unifi/uap.go b/core/unifi/uap.go index dcca4ae8..5a104607 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -9,7 +9,6 @@ import ( // This was auto generated then edited by hand to get all the data types right. type UAP struct { site *Site - controller *Unifi SourceName string `json:"-"` ID string `json:"_id"` Adopted FlexBool `json:"adopted"` diff --git a/core/unifi/udm.go b/core/unifi/udm.go index fcc5ef4d..547c5f0e 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -4,7 +4,6 @@ package unifi // The UDM shares several structs/type-data with USW and USG. type UDM struct { site *Site - controller *Unifi SourceName string `json:"-"` SiteID string `json:"site_id"` SiteName string `json:"-"` diff --git a/core/unifi/usg.go b/core/unifi/usg.go index a8c21008..a718c7b0 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg.go @@ -8,7 +8,6 @@ import ( // USG represents all the data from the Ubiquiti Controller for a Unifi Security Gateway. type USG struct { site *Site - controller *Unifi SourceName string `json:"-"` ID string `json:"_id"` Adopted FlexBool `json:"adopted"` diff --git a/core/unifi/usw.go b/core/unifi/usw.go index b8500005..677ee520 100644 --- a/core/unifi/usw.go +++ b/core/unifi/usw.go @@ -8,7 +8,6 @@ import ( // USW represents all the data from the Ubiquiti Controller for a Unifi Switch. type USW struct { site *Site - controller *Unifi SourceName string `json:"-"` SiteName string `json:"-"` ID string `json:"_id"` diff --git a/core/unifi/uxg.go b/core/unifi/uxg.go index 24ced7e6..ddd6c5b5 100644 --- a/core/unifi/uxg.go +++ b/core/unifi/uxg.go @@ -4,7 +4,6 @@ package unifi // The UDM shares several structs/type-data with USW and USG. type UXG struct { site *Site - controller *Unifi SourceName string `json:"-"` SiteName string `json:"-"` ID string `json:"_id"` From 99bc97532a7fcb533c9fe7ece42370deeb6d03d7 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Mar 2021 17:09:06 -0700 Subject: [PATCH 183/194] turn these strings into floats --- core/unifi/usw.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/unifi/usw.go b/core/unifi/usw.go index c5dd571f..d95f2569 100644 --- a/core/unifi/usw.go +++ b/core/unifi/usw.go @@ -146,18 +146,18 @@ type Port struct { Satisfaction FlexInt `json:"satisfaction,omitempty"` SatisfactionReason FlexInt `json:"satisfaction_reason"` SFPCompliance string `json:"sfp_compliance"` - SFPCurrent string `json:"sfp_current"` + SFPCurrent FlexInt `json:"sfp_current"` SFPFound FlexBool `json:"sfp_found"` SFPPart string `json:"sfp_part"` SFPRev string `json:"sfp_rev"` SFPRxfault FlexBool `json:"sfp_rxfault"` - SFPRxpower string `json:"sfp_rxpower"` + SFPRxpower FlexInt `json:"sfp_rxpower"` SFPSerial string `json:"sfp_serial"` - SFPTemperature string `json:"sfp_temperature"` + SFPTemperature FlexInt `json:"sfp_temperature"` SFPTxfault FlexBool `json:"sfp_txfault"` - SFPTxpower string `json:"sfp_txpower"` + SFPTxpower FlexInt `json:"sfp_txpower"` SFPVendor string `json:"sfp_vendor"` - SFPVoltage string `json:"sfp_voltage"` + SFPVoltage FlexInt `json:"sfp_voltage"` Speed FlexInt `json:"speed"` SpeedCaps FlexInt `json:"speed_caps"` StpPathcost FlexInt `json:"stp_pathcost"` From 9d068a14c4919609288aa58269d34edb2f35b8ab Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Mar 2021 17:37:27 -0700 Subject: [PATCH 184/194] make UXG more like USG --- core/unifi/uxg.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/core/unifi/uxg.go b/core/unifi/uxg.go index 41ee2046..ae39e069 100644 --- a/core/unifi/uxg.go +++ b/core/unifi/uxg.go @@ -31,7 +31,7 @@ type UXG struct { Internet FlexBool `json:"internet"` ModelIncompatible FlexBool `json:"model_incompatible"` EthernetTable []*EthernetTable `json:"ethernet_table"` - PortTable []*Port `json:"port_table"` + PortTable []Port `json:"port_table"` EthernetOverrides []*EthernetOverrides `json:"ethernet_overrides"` UsgCaps FlexInt `json:"usg_caps"` HasSpeaker FlexBool `json:"has_speaker"` @@ -42,7 +42,7 @@ type UXG struct { SwitchCaps *SwitchCaps `json:"switch_caps"` HasFan FlexBool `json:"has_fan"` HasTemperature FlexBool `json:"has_temperature"` - Temperatures []*Temperature `json:"temperatures"` + Temperatures []Temperature `json:"temperatures"` Storage []*Storage `json:"storage"` RulesetInterfaces interface{} `json:"ruleset_interfaces"` ConnectedAt FlexInt `json:"connected_at"` @@ -68,21 +68,21 @@ type UXG struct { Uptime FlexInt `json:"uptime"` UnderscoreUptime FlexInt `json:"_uptime"` Locating FlexBool `json:"locating"` - SysStats *SysStats `json:"sys_stats"` - SystemStats *SystemStats `json:"system-stats"` + SysStats SysStats `json:"sys_stats"` + SystemStats SystemStats `json:"system-stats"` GuestKicks FlexInt `json:"guest_kicks"` GuestToken string `json:"guest_token"` UptimeStats map[string]*UptimeStats `json:"uptime_stats"` Overheating FlexBool `json:"overheating"` GeoInfo map[string]*GeoInfo `json:"geo_info"` LedState *LedState `json:"led_state"` - SpeedtestStatus *SpeedtestStatus `json:"speedtest-status"` + SpeedtestStatus SpeedtestStatus `json:"speedtest-status"` SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"` - Wan1 *Wan `json:"wan1"` - Wan2 *Wan `json:"wan2"` - Uplink *Uplink `json:"uplink"` + Wan1 Wan `json:"wan1"` + Wan2 Wan `json:"wan2"` + Uplink Uplink `json:"uplink"` DownlinkTable []*DownlinkTable `json:"downlink_table"` - NetworkTable []*NetworkTable `json:"network_table"` + NetworkTable NetworkTable `json:"network_table"` KnownCfgversion string `json:"known_cfgversion"` ConnectRequestIP string `json:"connect_request_ip"` ConnectRequestPort string `json:"connect_request_port"` From f7c1267b35c35a38549c70f8de3a47371173738f Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Mar 2021 22:17:27 -0700 Subject: [PATCH 185/194] add system stats temps --- core/unifi/usg.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/unifi/usg.go b/core/unifi/usg.go index 9b265a5a..ca126634 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg.go @@ -190,6 +190,9 @@ type SystemStats struct { CPU FlexInt `json:"cpu"` Mem FlexInt `json:"mem"` Uptime FlexInt `json:"uptime"` + // This exists on at least USG4, may others, maybe not. + // {"Board (CPU)":"51 C","Board (PHY)":"51 C","CPU":"72 C","PHY":"77 C"} + Temps map[string]string `json:"temps,omitempty"` } // SysStats is load info for a UDM, USG, USW. From 8cbf73e4aeb5a5f7f7873f93946af9da7edacafb Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 17 Apr 2021 13:41:24 -0700 Subject: [PATCH 186/194] site name is wrong --- core/unifi/alarms.go | 4 ++-- core/unifi/anomalies.go | 4 ++-- core/unifi/clients.go | 6 +++--- core/unifi/devices.go | 20 ++++++++++---------- core/unifi/events.go | 4 ++-- core/unifi/ids.go | 4 ++-- core/unifi/site.go | 4 ++-- core/unifi/uap.go | 4 ++-- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/core/unifi/alarms.go b/core/unifi/alarms.go index 863e27ca..975786b2 100644 --- a/core/unifi/alarms.go +++ b/core/unifi/alarms.go @@ -76,7 +76,7 @@ func (u *Unifi) GetAlarmsSite(site *Site) ([]*Alarm, error) { return nil, ErrNoSiteProvided } - u.DebugLog("Polling Controller for Alarms, site %s (%s)", site.Name, site.Desc) + u.DebugLog("Polling Controller for Alarms, site %s", site.SiteName) var ( path = fmt.Sprintf(APIEventPathAlarms, site.Name) @@ -93,7 +93,7 @@ func (u *Unifi) GetAlarmsSite(site *Site) ([]*Alarm, error) { // Add special SourceName value. alarms.Data[i].SourceName = u.URL // Add the special "Site Name" to each event. This becomes a Grafana filter somewhere. - alarms.Data[i].SiteName = site.Desc + " (" + site.Name + ")" + alarms.Data[i].SiteName = site.SiteName } sort.Sort(alarms.Data) diff --git a/core/unifi/anomalies.go b/core/unifi/anomalies.go index 2dfb5238..cdb66141 100644 --- a/core/unifi/anomalies.go +++ b/core/unifi/anomalies.go @@ -47,7 +47,7 @@ func (u *Unifi) GetAnomaliesSite(site *Site, timeRange ...time.Time) ([]*Anomaly return nil, ErrNoSiteProvided } - u.DebugLog("Polling Controller for Anomalies, site %s (%s)", site.Name, site.Desc) + u.DebugLog("Polling Controller for Anomalies, site %s", site.SiteName) var ( path = fmt.Sprintf(APIAnomaliesPath, site.Name) @@ -68,7 +68,7 @@ func (u *Unifi) GetAnomaliesSite(site *Site, timeRange ...time.Time) ([]*Anomaly anomalies = append(anomalies, &Anomaly{ Datetime: time.Unix(ts/int64(time.Microsecond), 0), SourceName: u.URL, - SiteName: site.Desc + " (" + site.Name + ")", + SiteName: site.SiteName, Anomaly: d.Anomaly, DeviceMAC: d.MAC, // DeviceName: d.Anomaly, diff --git a/core/unifi/clients.go b/core/unifi/clients.go index 193e502a..1e3b4ddf 100644 --- a/core/unifi/clients.go +++ b/core/unifi/clients.go @@ -14,7 +14,7 @@ func (u *Unifi) GetClients(sites []*Site) ([]*Client, error) { Data []*Client `json:"data"` } - u.DebugLog("Polling Controller, retreiving UniFi Clients, site %s (%s) ", site.Name, site.Desc) + u.DebugLog("Polling Controller, retreiving UniFi Clients, site %s ", site.SiteName) clientPath := fmt.Sprintf(APIClientPath, site.Name) if err := u.GetData(clientPath, &response); err != nil { @@ -25,7 +25,7 @@ func (u *Unifi) GetClients(sites []*Site) ([]*Client, error) { // Add special SourceName value. response.Data[i].SourceName = u.URL // Add the special "Site Name" to each client. This becomes a Grafana filter somewhere. - response.Data[i].SiteName = site.Desc + " (" + site.Name + ")" + response.Data[i].SiteName = site.SiteName // Fix name and hostname fields. Sometimes one or the other is blank. response.Data[i].Hostname = strings.TrimSpace(pick(d.Hostname, d.Name, d.Mac)) response.Data[i].Name = strings.TrimSpace(pick(d.Name, d.Hostname)) @@ -42,7 +42,7 @@ func (u *Unifi) GetClientsDPI(sites []*Site) ([]*DPITable, error) { var data []*DPITable for _, site := range sites { - u.DebugLog("Polling Controller, retreiving Client DPI data, site %s (%s) ", site.Name, site.Desc) + u.DebugLog("Polling Controller, retreiving Client DPI data, site %s", site.SiteName) var response struct { Data []*DPITable `json:"data"` diff --git a/core/unifi/devices.go b/core/unifi/devices.go index 35003694..885a1844 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -45,7 +45,7 @@ func (u *Unifi) GetUSWs(site *Site) ([]*USW, error) { return u.parseDevices(response.Data, site).USWs, nil } -// GetUSWs returns all access points, an error, or nil if there are no APs. +// GetUAPs returns all access points, an error, or nil if there are no APs. func (u *Unifi) GetUAPs(site *Site) ([]*UAP, error) { var response struct { Data []json.RawMessage `json:"data"` @@ -59,7 +59,7 @@ func (u *Unifi) GetUAPs(site *Site) ([]*UAP, error) { return u.parseDevices(response.Data, site).UAPs, nil } -// GetUSWs returns all dream machines, an error, or nil if there are no UDMs. +// GetUDMs returns all dream machines, an error, or nil if there are no UDMs. func (u *Unifi) GetUDMs(site *Site) ([]*UDM, error) { var response struct { Data []json.RawMessage `json:"data"` @@ -73,7 +73,7 @@ func (u *Unifi) GetUDMs(site *Site) ([]*UDM, error) { return u.parseDevices(response.Data, site).UDMs, nil } -// GetUSWs returns all 10Gb gateways, an error, or nil if there are no UXGs. +// GetUXGs returns all 10Gb gateways, an error, or nil if there are no UXGs. func (u *Unifi) GetUXGs(site *Site) ([]*UXG, error) { var response struct { Data []json.RawMessage `json:"data"` @@ -87,7 +87,7 @@ func (u *Unifi) GetUXGs(site *Site) ([]*UXG, error) { return u.parseDevices(response.Data, site).UXGs, nil } -// GetUSWs returns all 1Gb gateways, an error, or nil if there are no USGs. +// GetUSGs returns all 1Gb gateways, an error, or nil if there are no USGs. func (u *Unifi) GetUSGs(site *Site) ([]*USG, error) { var response struct { Data []json.RawMessage `json:"data"` @@ -114,7 +114,7 @@ func (u *Unifi) parseDevices(data []json.RawMessage, site *Site) *Devices { } assetType, _ := o["type"].(string) - u.DebugLog("Unmarshalling Device Type: %v, site %s ", assetType, site.Name) + u.DebugLog("Unmarshalling Device Type: %v, site %s ", assetType, site.SiteName) // Choose which type to unmarshal into based on the "type" json key. switch assetType { // Unmarshal again into the correct type.. @@ -137,7 +137,7 @@ func (u *Unifi) parseDevices(data []json.RawMessage, site *Site) *Devices { } func (u *Unifi) unmarshallUAP(site *Site, payload json.RawMessage, devices *Devices) { - dev := &UAP{SiteName: site.Name, SourceName: u.URL} + dev := &UAP{SiteName: site.SiteName, SourceName: u.URL} if u.unmarshalDevice("uap", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) dev.site = site @@ -146,7 +146,7 @@ func (u *Unifi) unmarshallUAP(site *Site, payload json.RawMessage, devices *Devi } func (u *Unifi) unmarshallUSG(site *Site, payload json.RawMessage, devices *Devices) { - dev := &USG{SiteName: site.Name, SourceName: u.URL} + dev := &USG{SiteName: site.SiteName, SourceName: u.URL} if u.unmarshalDevice("ugw", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) dev.site = site @@ -155,7 +155,7 @@ func (u *Unifi) unmarshallUSG(site *Site, payload json.RawMessage, devices *Devi } func (u *Unifi) unmarshallUSW(site *Site, payload json.RawMessage, devices *Devices) { - dev := &USW{SiteName: site.Name, SourceName: u.URL} + dev := &USW{SiteName: site.SiteName, SourceName: u.URL} if u.unmarshalDevice("usw", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) dev.site = site @@ -164,7 +164,7 @@ func (u *Unifi) unmarshallUSW(site *Site, payload json.RawMessage, devices *Devi } func (u *Unifi) unmarshallUXG(site *Site, payload json.RawMessage, devices *Devices) { - dev := &UXG{SiteName: site.Name, SourceName: u.URL} + dev := &UXG{SiteName: site.SiteName, SourceName: u.URL} if u.unmarshalDevice("uxg", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) dev.site = site @@ -173,7 +173,7 @@ func (u *Unifi) unmarshallUXG(site *Site, payload json.RawMessage, devices *Devi } func (u *Unifi) unmarshallUDM(site *Site, payload json.RawMessage, devices *Devices) { - dev := &UDM{SiteName: site.Name, SourceName: u.URL} + dev := &UDM{SiteName: site.SiteName, SourceName: u.URL} if u.unmarshalDevice("udm", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) dev.site = site diff --git a/core/unifi/events.go b/core/unifi/events.go index d43cf4f9..4340c670 100644 --- a/core/unifi/events.go +++ b/core/unifi/events.go @@ -42,7 +42,7 @@ func (u *Unifi) GetSiteEvents(site *Site, hours time.Duration) ([]*Event, error) hours = time.Hour } - u.DebugLog("Polling Controller, retreiving UniFi Events, site %s (%s)", site.Name, site.Desc) + u.DebugLog("Polling Controller, retreiving UniFi Events, site %s", site.SiteName) var ( path = fmt.Sprintf(APIEventPath, site.Name) @@ -61,7 +61,7 @@ func (u *Unifi) GetSiteEvents(site *Site, hours time.Duration) ([]*Event, error) // Add special SourceName value. event.Data[i].SourceName = u.URL // Add the special "Site Name" to each event. This becomes a Grafana filter somewhere. - event.Data[i].SiteName = site.Desc + " (" + site.Name + ")" + event.Data[i].SiteName = site.SiteName } sort.Sort(event.Data) diff --git a/core/unifi/ids.go b/core/unifi/ids.go index c290cbe2..2898506d 100644 --- a/core/unifi/ids.go +++ b/core/unifi/ids.go @@ -79,7 +79,7 @@ func (u *Unifi) GetIDSSite(site *Site, timeRange ...time.Time) ([]*IDS, error) { return nil, ErrNoSiteProvided } - u.DebugLog("Polling Controller for IDS Events, site %s (%s)", site.Name, site.Desc) + u.DebugLog("Polling Controller for IDS Events, site %s", site.SiteName) var ( path = fmt.Sprintf(APIEventPathIDS, site.Name) @@ -98,7 +98,7 @@ func (u *Unifi) GetIDSSite(site *Site, timeRange ...time.Time) ([]*IDS, error) { // Add special SourceName value. ids.Data[i].SourceName = u.URL // Add the special "Site Name" to each event. This becomes a Grafana filter somewhere. - ids.Data[i].SiteName = site.Desc + " (" + site.Name + ")" + ids.Data[i].SiteName = site.SiteName } sort.Sort(ids.Data) diff --git a/core/unifi/site.go b/core/unifi/site.go index 25030bfa..4534a689 100644 --- a/core/unifi/site.go +++ b/core/unifi/site.go @@ -41,7 +41,7 @@ func (u *Unifi) GetSiteDPI(sites []*Site) ([]*DPITable, error) { data := []*DPITable{} for _, site := range sites { - u.DebugLog("Polling Controller, retreiving Site DPI data, site %s (%s) ", site.Name, site.Desc) + u.DebugLog("Polling Controller, retreiving Site DPI data, site %s", site.SiteName) var response struct { Data []*DPITable `json:"data"` @@ -55,7 +55,7 @@ func (u *Unifi) GetSiteDPI(sites []*Site) ([]*DPITable, error) { if l := len(response.Data); l > 1 { return nil, ErrDPIDataBug } else if l == 0 { - u.DebugLog("Site DPI data missing! Is DPI enabled in UniFi controller? Site %s (%s) ", site.Name, site.Desc) + u.DebugLog("Site DPI data missing! Is DPI enabled in UniFi controller? Site %s", site.SiteName) continue } diff --git a/core/unifi/uap.go b/core/unifi/uap.go index dca0dfbb..9418c1cb 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -604,7 +604,7 @@ func (u *Unifi) GetRogueAPsSite(site *Site) ([]*RogueAP, error) { return nil, ErrNoSiteProvided } - u.DebugLog("Polling Controller for RogueAPs, site %s (%s)", site.Name, site.Desc) + u.DebugLog("Polling Controller for RogueAPs, site %s (%s)", site.SiteName, site.Desc) var ( path = fmt.Sprintf(APIRogueAP, site.Name) @@ -621,7 +621,7 @@ func (u *Unifi) GetRogueAPsSite(site *Site) ([]*RogueAP, error) { // Add special SourceName value. rogueaps.Data[i].SourceName = u.URL // Add the special "Site Name" to each event. This becomes a Grafana filter somewhere. - rogueaps.Data[i].SiteName = site.Desc + " (" + site.Name + ")" + rogueaps.Data[i].SiteName = site.SiteName } return rogueaps.Data, nil From 2b0e465fe0ed0dfad3df104559e67c183e6d2d48 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sat, 17 Apr 2021 13:45:16 -0700 Subject: [PATCH 187/194] lint fix, go upgrade --- core/unifi/.travis.yml | 6 +++--- core/unifi/go.mod | 4 ++-- core/unifi/go.sum | 4 ++++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/core/unifi/.travis.yml b/core/unifi/.travis.yml index b8e3b955..050bba31 100644 --- a/core/unifi/.travis.yml +++ b/core/unifi/.travis.yml @@ -1,9 +1,9 @@ language: go go: -- 1.15.x +- 1.16.x before_install: # download super-linter: golangci-lint -- curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin latest +- curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.38.0 script: -- golangci-lint run --enable-all -D exhaustivestruct,nlreturn +- golangci-lint run --enable-all -D exhaustivestruct,nlreturn,wrapcheck,maligned,interfacer - go test ./... diff --git a/core/unifi/go.mod b/core/unifi/go.mod index 9aade56e..d19a14e5 100644 --- a/core/unifi/go.mod +++ b/core/unifi/go.mod @@ -1,10 +1,10 @@ module github.com/unifi-poller/unifi -go 1.15 +go 1.16 require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/stretchr/testify v1.4.0 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect - golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 + golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d ) diff --git a/core/unifi/go.sum b/core/unifi/go.sum index d2c30146..fcb0415e 100644 --- a/core/unifi/go.sum +++ b/core/unifi/go.sum @@ -15,13 +15,17 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrS golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d h1:BgJvlyh+UqCUaPlscHJ+PN8GcpfrFdr7NHjd1JL0+Gs= +golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 551cf7106294d3f5100d388fb4e365c57d930218 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 23 Jun 2021 03:03:14 -0700 Subject: [PATCH 188/194] update org name --- core/unifi/README.md | 6 +++--- core/unifi/go.mod | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/unifi/README.md b/core/unifi/README.md index 33d8a563..9b7df0da 100644 --- a/core/unifi/README.md +++ b/core/unifi/README.md @@ -7,9 +7,9 @@ data. The data is provided in a large struct you can consume in your application This library is designed to PULL data FROM the controller. It has no methods that update settings or change things on the controller. -[Someone expressed interest](https://github.com/unifi-poller/unifi/issues/31) in +[Someone expressed interest](https://github.com/unpoller/unifi/issues/31) in adding methods to update data, and I'm okay with that. I'll even help add them. -[Tell me what you want to do](https://github.com/unifi-poller/unifi/issues/new), and we'll make it happen. +[Tell me what you want to do](https://github.com/unpoller/unifi/issues/new), and we'll make it happen. Pull requests, feature requests, code reviews and feedback are welcomed! @@ -18,7 +18,7 @@ Here's a working example: package main import "log" -import "github.com/unifi-poller/unifi" +import "github.com/unpoller/unifi" func main() { c := *unifi.Config{ diff --git a/core/unifi/go.mod b/core/unifi/go.mod index d19a14e5..dfba68c3 100644 --- a/core/unifi/go.mod +++ b/core/unifi/go.mod @@ -1,4 +1,4 @@ -module github.com/unifi-poller/unifi +module github.com/unpoller/unifi go 1.16 From fb3f2e5578630ce37eb00be301e577a767aa8f78 Mon Sep 17 00:00:00 2001 From: spsobole Date: Thu, 12 Aug 2021 12:46:14 -0600 Subject: [PATCH 189/194] Add support for alluser --- core/unifi/types.go | 4 +++ core/unifi/unifi.go | 7 +++++ core/unifi/users.go | 69 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 core/unifi/users.go diff --git a/core/unifi/types.go b/core/unifi/types.go index d31aa239..bced62e2 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -28,6 +28,8 @@ const ( APIClientDPI string = "/api/s/%s/stat/stadpi" // APIClientPath is Unifi Clients API Path. APIClientPath string = "/api/s/%s/stat/sta" + // APIAllUserPath is Unifi Insight all previous Clients API Path. + APIAllUserPath string = "/api/s/%s/stat/alluser" // APINetworkPath is where we get data about Unifi networks. APINetworkPath string = "/api/s/%s/rest/networkconf" // APIDevicePath is where we get data about Unifi devices. @@ -36,6 +38,8 @@ const ( APILoginPath string = "/api/login" // APILoginPathNew is how we log into UDM 5.12.55+. APILoginPathNew string = "/api/auth/login" + // APILogoutPath is the how we logout from UDM + APILogoutPath string = "/api/auth/logout" // APIEventPathIDS returns Intrusion Detection/Prevention Systems Events. APIEventPathIDS string = "/api/s/%s/stat/ips/event" // APIEventPathAlarms contains the site alarms. diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 93962065..653f6895 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -142,6 +142,13 @@ func (u *Unifi) Login() error { return nil } +// Logout closes the current session +func (u *Unifi) Logout() error { + var response struct { + } + return u.GetData(APILogoutPath, &response) +} + // with the release of controller version 5.12.55 on UDM in Jan 2020 the api paths // changed and broke this library. This function runs when `NewUnifi()` is called to // check if this is a newer controller or not. If it is, we set new to true. diff --git a/core/unifi/users.go b/core/unifi/users.go new file mode 100644 index 00000000..56b034d1 --- /dev/null +++ b/core/unifi/users.go @@ -0,0 +1,69 @@ +package unifi + +import ( + "fmt" + "strings" +) + +// GetUsers returns a response full of clients that connected to the UDM within the provided amount of time +// it uses the insight historical connections data set +func (u *Unifi) GetUsers(sites []*Site, hours int) ([]*User, error) { + data := make([]*User, 0) + + for _, site := range sites { + var response struct { + Data []*User `json:"data"` + } + params := fmt.Sprintf(`{ "type": "all:", "conn": "all", "within":%d }`, hours) + + u.DebugLog("Polling Controller, retrieving UniFi Users, site %s ", site.SiteName) + + clientPath := fmt.Sprintf(APIAllUserPath, site.Name) + if err := u.GetData(clientPath, &response, params); err != nil { + return nil, err + } + + for i, d := range response.Data { + // Add special SourceName value. + response.Data[i].SourceName = u.URL + // Add the special "Site Name" to each client. This becomes a Grafana filter somewhere. + response.Data[i].SiteName = site.SiteName + // Fix name and hostname fields. Sometimes one or the other is blank. + response.Data[i].Hostname = strings.TrimSpace(pick(d.Hostname, d.Name, d.Mac)) + response.Data[i].Name = strings.TrimSpace(pick(d.Name, d.Hostname)) + } + + data = append(data, response.Data...) + } + + return data, nil +} + +// User defines the metadata available for previously connected clients +type User struct { + SourceName string `json:"-"` + SiteName string `json:"-"` + ID string `json:"_id"` + Mac string `json:"mac"` + SiteID string `json:"site_id"` + Oui string `json:"oui,omitempty"` + IsGuest bool `json:"is_guest"` + FirstSeen int64 `json:"first_seen,omitempty"` + LastSeen int64 `json:"last_seen,omitempty"` + IsWired bool `json:"is_wired,omitempty"` + Hostname string `json:"hostname,omitempty"` + Duration int64 `json:"duration,omitempty"` + TxBytes int64 `json:"tx_bytes,omitempty"` + TxPackets int64 `json:"tx_packets,omitempty"` + RxBytes int64 `json:"rx_bytes,omitempty"` + RxPackets int64 `json:"rx_packets,omitempty"` + WifiTxAttempts int64 `json:"wifi_tx_attempts,omitempty"` + TxRetries int64 `json:"tx_retries,omitempty"` + UsergroupID string `json:"usergroup_id,omitempty"` + Name string `json:"name,omitempty"` + Note string `json:"note,omitempty"` + Noted bool `json:"noted,omitempty"` + Blocked bool `json:"blocked,omitempty"` + DevIDOverride int64 `json:"dev_id_override,omitempty"` + FingerprintOverride bool `json:"fingerprint_override,omitempty"` +} From 7b122409df6f5ca88391a20c3bb7d1df8c81b1f2 Mon Sep 17 00:00:00 2001 From: spsobole <26949687+thirdmartini@users.noreply.github.com> Date: Fri, 13 Aug 2021 10:47:38 -0600 Subject: [PATCH 190/194] Fix logout and use FlexBool/FlexInt --- core/unifi/types.go | 4 ++-- core/unifi/unifi.go | 32 +++++++++++++++++++++++++---- core/unifi/users.go | 50 ++++++++++++++++++++++----------------------- 3 files changed, 55 insertions(+), 31 deletions(-) diff --git a/core/unifi/types.go b/core/unifi/types.go index bced62e2..f904a01d 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -38,8 +38,8 @@ const ( APILoginPath string = "/api/login" // APILoginPathNew is how we log into UDM 5.12.55+. APILoginPathNew string = "/api/auth/login" - // APILogoutPath is the how we logout from UDM - APILogoutPath string = "/api/auth/logout" + // APILogoutPath is how we logout from UDM + APILogoutPath string = "/api/logout" // APIEventPathIDS returns Intrusion Detection/Prevention Systems Events. APIEventPathIDS string = "/api/s/%s/stat/ips/event" // APIEventPathAlarms contains the site alarms. diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index 653f6895..da139367 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -28,7 +28,7 @@ import ( var ( ErrAuthenticationFailed = fmt.Errorf("authentication failed") ErrInvalidStatusCode = fmt.Errorf("invalid status code from server") - ErrNoParams = fmt.Errorf("requedted PUT with no parameters") + ErrNoParams = fmt.Errorf("requested PUT with no parameters") ErrInvalidSignature = fmt.Errorf("certificate signature does not match") ) @@ -144,9 +144,9 @@ func (u *Unifi) Login() error { // Logout closes the current session func (u *Unifi) Logout() error { - var response struct { - } - return u.GetData(APILogoutPath, &response) + // a post is needed for logout + _, err := u.PostJSON(APILogoutPath) + return err } // with the release of controller version 5.12.55 on UDM in Jan 2020 the api paths @@ -286,6 +286,19 @@ func (u *Unifi) UniReqPut(apiPath string, params string) (*http.Request, error) return req, nil } +// UniReqPost is the Post call equivalent to UniReq. +func (u *Unifi) UniReqPost(apiPath string, params string) (*http.Request, error) { + apiPath = u.path(apiPath) + + req, err := http.NewRequest(http.MethodPost, u.URL+apiPath, bytes.NewBufferString("")) //nolint:noctx + if err != nil { + return nil, fmt.Errorf("creating request: %w", err) + } + + u.setHeaders(req, params) + return req, nil +} + // GetJSON returns the raw JSON from a path. This is useful for debugging. func (u *Unifi) GetJSON(apiPath string, params ...string) ([]byte, error) { req, err := u.UniReq(apiPath, strings.Join(params, " ")) @@ -307,6 +320,17 @@ func (u *Unifi) PutJSON(apiPath string, params ...string) ([]byte, error) { return u.do(req) } +// PostJSON uses a POST call and returns the raw JSON in the same way as GetData +// Use this if you want to change data via the REST API. +func (u *Unifi) PostJSON(apiPath string, params ...string) ([]byte, error) { + req, err := u.UniReqPost(apiPath, strings.Join(params, " ")) + if err != nil { + return []byte{}, err + } + + return u.do(req) +} + func (u *Unifi) do(req *http.Request) ([]byte, error) { var ( cancel func() diff --git a/core/unifi/users.go b/core/unifi/users.go index 56b034d1..d2384c8f 100644 --- a/core/unifi/users.go +++ b/core/unifi/users.go @@ -41,29 +41,29 @@ func (u *Unifi) GetUsers(sites []*Site, hours int) ([]*User, error) { // User defines the metadata available for previously connected clients type User struct { - SourceName string `json:"-"` - SiteName string `json:"-"` - ID string `json:"_id"` - Mac string `json:"mac"` - SiteID string `json:"site_id"` - Oui string `json:"oui,omitempty"` - IsGuest bool `json:"is_guest"` - FirstSeen int64 `json:"first_seen,omitempty"` - LastSeen int64 `json:"last_seen,omitempty"` - IsWired bool `json:"is_wired,omitempty"` - Hostname string `json:"hostname,omitempty"` - Duration int64 `json:"duration,omitempty"` - TxBytes int64 `json:"tx_bytes,omitempty"` - TxPackets int64 `json:"tx_packets,omitempty"` - RxBytes int64 `json:"rx_bytes,omitempty"` - RxPackets int64 `json:"rx_packets,omitempty"` - WifiTxAttempts int64 `json:"wifi_tx_attempts,omitempty"` - TxRetries int64 `json:"tx_retries,omitempty"` - UsergroupID string `json:"usergroup_id,omitempty"` - Name string `json:"name,omitempty"` - Note string `json:"note,omitempty"` - Noted bool `json:"noted,omitempty"` - Blocked bool `json:"blocked,omitempty"` - DevIDOverride int64 `json:"dev_id_override,omitempty"` - FingerprintOverride bool `json:"fingerprint_override,omitempty"` + SourceName string `json:"-"` + SiteName string `json:"-"` + ID string `json:"_id"` + Mac string `json:"mac"` + SiteID string `json:"site_id"` + Oui string `json:"oui,omitempty"` + IsGuest bool `json:"is_guest"` + FirstSeen FlexInt `json:"first_seen,omitempty"` + LastSeen FlexInt `json:"last_seen,omitempty"` + IsWired bool `json:"is_wired,omitempty"` + Hostname string `json:"hostname,omitempty"` + Duration FlexInt `json:"duration,omitempty"` + TxBytes FlexInt `json:"tx_bytes,omitempty"` + TxPackets FlexInt `json:"tx_packets,omitempty"` + RxBytes FlexInt `json:"rx_bytes,omitempty"` + RxPackets FlexInt `json:"rx_packets,omitempty"` + WifiTxAttempts FlexInt `json:"wifi_tx_attempts,omitempty"` + TxRetries FlexInt `json:"tx_retries,omitempty"` + UsergroupID string `json:"usergroup_id,omitempty"` + Name string `json:"name,omitempty"` + Note string `json:"note,omitempty"` + Noted FlexBool `json:"noted,omitempty"` + Blocked FlexBool `json:"blocked,omitempty"` + DevIDOverride FlexInt `json:"dev_id_override,omitempty"` + FingerprintOverride FlexBool `json:"fingerprint_override,omitempty"` } From 603e5be73008f2351f5030763c134b1d5c94fe71 Mon Sep 17 00:00:00 2001 From: spsobole <26949687+thirdmartini@users.noreply.github.com> Date: Fri, 13 Aug 2021 12:20:20 -0600 Subject: [PATCH 191/194] style fixes per lint warnings --- core/unifi/types.go | 2 +- core/unifi/unifi.go | 3 ++- core/unifi/users.go | 14 ++++++++------ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/core/unifi/types.go b/core/unifi/types.go index f904a01d..5ef5a569 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -38,7 +38,7 @@ const ( APILoginPath string = "/api/login" // APILoginPathNew is how we log into UDM 5.12.55+. APILoginPathNew string = "/api/auth/login" - // APILogoutPath is how we logout from UDM + // APILogoutPath is how we logout from UDM. APILogoutPath string = "/api/logout" // APIEventPathIDS returns Intrusion Detection/Prevention Systems Events. APIEventPathIDS string = "/api/s/%s/stat/ips/event" diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index da139367..dfe20b19 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -142,7 +142,7 @@ func (u *Unifi) Login() error { return nil } -// Logout closes the current session +// Logout closes the current session. func (u *Unifi) Logout() error { // a post is needed for logout _, err := u.PostJSON(APILogoutPath) @@ -296,6 +296,7 @@ func (u *Unifi) UniReqPost(apiPath string, params string) (*http.Request, error) } u.setHeaders(req, params) + return req, nil } diff --git a/core/unifi/users.go b/core/unifi/users.go index d2384c8f..995e2908 100644 --- a/core/unifi/users.go +++ b/core/unifi/users.go @@ -6,15 +6,17 @@ import ( ) // GetUsers returns a response full of clients that connected to the UDM within the provided amount of time -// it uses the insight historical connections data set +// using the insight historical connection data set. func (u *Unifi) GetUsers(sites []*Site, hours int) ([]*User, error) { data := make([]*User, 0) for _, site := range sites { - var response struct { - Data []*User `json:"data"` - } - params := fmt.Sprintf(`{ "type": "all:", "conn": "all", "within":%d }`, hours) + var ( + response struct { + Data []*User `json:"data"` + } + params = fmt.Sprintf(`{ "type": "all:", "conn": "all", "within":%d }`, hours) + ) u.DebugLog("Polling Controller, retrieving UniFi Users, site %s ", site.SiteName) @@ -39,7 +41,7 @@ func (u *Unifi) GetUsers(sites []*Site, hours int) ([]*User, error) { return data, nil } -// User defines the metadata available for previously connected clients +// User defines the metadata available for previously connected clients. type User struct { SourceName string `json:"-"` SiteName string `json:"-"` From 60b68d397055a37aa877e65eb8c198060977cea3 Mon Sep 17 00:00:00 2001 From: spsobole Date: Fri, 13 Aug 2021 15:40:34 -0600 Subject: [PATCH 192/194] Fix missing consumption of params in UniReqPost --- core/unifi/unifi.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index dfe20b19..cd1bf76c 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -290,7 +290,7 @@ func (u *Unifi) UniReqPut(apiPath string, params string) (*http.Request, error) func (u *Unifi) UniReqPost(apiPath string, params string) (*http.Request, error) { apiPath = u.path(apiPath) - req, err := http.NewRequest(http.MethodPost, u.URL+apiPath, bytes.NewBufferString("")) //nolint:noctx + req, err := http.NewRequest(http.MethodPost, u.URL+apiPath, bytes.NewBufferString(params)) //nolint:noctx if err != nil { return nil, fmt.Errorf("creating request: %w", err) } From fae86101e7acf7096b4ac45a9551f7af7de4de69 Mon Sep 17 00:00:00 2001 From: spsobole Date: Fri, 13 Aug 2021 15:58:42 -0600 Subject: [PATCH 193/194] Update tests to use new org import path --- core/unifi/events_test.go | 2 +- core/unifi/types_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/unifi/events_test.go b/core/unifi/events_test.go index ea3f337a..270d0a95 100644 --- a/core/unifi/events_test.go +++ b/core/unifi/events_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/unifi-poller/unifi" + "github.com/unpoller/unifi" ) func TestIPGeoUnmarshalJSON(t *testing.T) { diff --git a/core/unifi/types_test.go b/core/unifi/types_test.go index bbf13a13..90e66969 100644 --- a/core/unifi/types_test.go +++ b/core/unifi/types_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/unifi-poller/unifi" + "github.com/unpoller/unifi" ) func TestFlexInt(t *testing.T) { From 90a03d333b087fdf1f41aed0085261496aafe922 Mon Sep 17 00:00:00 2001 From: Cody Lee Date: Wed, 23 Nov 2022 19:01:47 -0600 Subject: [PATCH 194/194] go mod tidy --- core/unifi/go.mod | 1 - core/unifi/go.sum | 14 -------------- 2 files changed, 15 deletions(-) diff --git a/core/unifi/go.mod b/core/unifi/go.mod index dfba68c3..a1075ea2 100644 --- a/core/unifi/go.mod +++ b/core/unifi/go.mod @@ -5,6 +5,5 @@ go 1.16 require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/stretchr/testify v1.4.0 - golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d ) diff --git a/core/unifi/go.sum b/core/unifi/go.sum index fcb0415e..125f26b4 100644 --- a/core/unifi/go.sum +++ b/core/unifi/go.sum @@ -1,30 +1,16 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d h1:BgJvlyh+UqCUaPlscHJ+PN8GcpfrFdr7NHjd1JL0+Gs= golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=