Merge pull request #44 from unifi-poller/dn2_uxg_plus
Add UXG data struct, storage for UDM, and other minor improvements.
This commit is contained in:
commit
ca6239efa9
|
|
@ -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 ./...
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -36,42 +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 := "<type key missing>"
|
||||
|
||||
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":
|
||||
u.unmarshallUXG(siteName, r, devices)
|
||||
default:
|
||||
u.ErrorLog("unknown asset type - %v - skipping", assetType)
|
||||
}
|
||||
|
|
@ -80,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 {
|
||||
|
|
@ -92,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.
|
||||
|
|
|
|||
|
|
@ -21,6 +21,17 @@ type DPIData struct {
|
|||
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.
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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=
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"`
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -6,13 +6,10 @@ import (
|
|||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
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.
|
||||
|
|
@ -27,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"
|
||||
|
|
@ -79,6 +76,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 +89,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
|
||||
|
|
@ -124,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) {
|
||||
|
|
@ -138,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
|
||||
|
|
|
|||
|
|
@ -28,10 +28,7 @@ type UDM struct {
|
|||
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"`
|
||||
ConfigNetwork *ConfigNetwork `json:"config_network"`
|
||||
VwireTable []interface{} `json:"vwire_table"`
|
||||
Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"`
|
||||
JumboframeEnabled FlexBool `json:"jumboframe_enabled"`
|
||||
|
|
@ -49,16 +46,9 @@ type UDM struct {
|
|||
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"`
|
||||
EthernetTable []*EthernetTable `json:"ethernet_table"`
|
||||
PortTable []Port `json:"port_table"`
|
||||
EthernetOverrides []struct {
|
||||
Ifname string `json:"ifname"`
|
||||
Networkgroup string `json:"networkgroup"`
|
||||
} `json:"ethernet_overrides"`
|
||||
EthernetOverrides []*EthernetOverrides `json:"ethernet_overrides"`
|
||||
UsgCaps FlexInt `json:"usg_caps"`
|
||||
HasSpeaker FlexBool `json:"has_speaker"`
|
||||
HasEth1 FlexBool `json:"has_eth1"`
|
||||
|
|
@ -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"`
|
||||
|
|
@ -110,6 +100,7 @@ type UDM struct {
|
|||
PortconfID string `json:"portconf_id"`
|
||||
} `json:"port_overrides"`
|
||||
Stat UDMStat `json:"stat"`
|
||||
Storage []*Storage `json:"storage"`
|
||||
TxBytes FlexInt `json:"tx_bytes"`
|
||||
RxBytes FlexInt `json:"rx_bytes"`
|
||||
Bytes FlexInt `json:"bytes"`
|
||||
|
|
@ -131,7 +122,19 @@ type UDM struct {
|
|||
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"`
|
||||
|
|
@ -150,6 +153,7 @@ type NetworkTable []struct {
|
|||
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"`
|
||||
|
|
@ -167,6 +171,9 @@ type NetworkTable []struct {
|
|||
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"`
|
||||
|
|
@ -174,6 +181,15 @@ type NetworkTable []struct {
|
|||
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 {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -33,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, "/")
|
||||
|
|
@ -46,8 +47,10 @@ func NewUnifi(config *Config) (*Unifi, error) {
|
|||
config.DebugLog = discardLogs
|
||||
}
|
||||
|
||||
u := &Unifi{Config: config,
|
||||
u := &Unifi{
|
||||
Config: config,
|
||||
Client: &http.Client{
|
||||
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
|
||||
|
|
@ -82,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.
|
||||
|
|
@ -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
|
||||
|
|
@ -103,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.
|
||||
|
|
@ -123,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.
|
||||
|
|
@ -185,39 +198,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))
|
||||
// UniReqPut is the Put call equivalent to UniReq.
|
||||
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.
|
||||
|
|
@ -231,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 {
|
||||
|
|
@ -242,16 +260,26 @@ 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
|
||||
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.
|
||||
|
|
@ -260,7 +288,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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -11,15 +11,8 @@ type USG struct {
|
|||
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"`
|
||||
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"`
|
||||
|
|
@ -37,10 +30,7 @@ type USG struct {
|
|||
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"`
|
||||
EthernetOverrides []*EthernetOverrides `json:"ethernet_overrides"`
|
||||
HwCaps FlexInt `json:"hw_caps"`
|
||||
BoardRev FlexInt `json:"board_rev"`
|
||||
Unsupported FlexBool `json:"unsupported"`
|
||||
|
|
@ -57,34 +47,14 @@ 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"`
|
||||
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"`
|
||||
PortTable []*Port `json:"port_table"`
|
||||
NetworkTable NetworkTable `json:"network_table"`
|
||||
Uplink Uplink `json:"uplink"`
|
||||
Stat USGStat `json:"stat"`
|
||||
|
|
@ -114,12 +84,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 +102,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 +114,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 +138,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,6 +148,7 @@ 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"`
|
||||
}
|
||||
|
|
@ -182,6 +159,8 @@ type SpeedtestStatus struct {
|
|||
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"`
|
||||
|
|
@ -190,6 +169,22 @@ type SpeedtestStatus struct {
|
|||
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.
|
||||
type SystemStats struct {
|
||||
CPU FlexInt `json:"cpu"`
|
||||
|
|
@ -233,6 +228,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.
|
||||
|
|
|
|||
|
|
@ -13,16 +13,9 @@ type USW struct {
|
|||
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"`
|
||||
ConfigNetwork *ConfigNetwork `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"`
|
||||
EthernetTable []*EthernetTable `json:"ethernet_table"`
|
||||
FlowctrlEnabled FlexBool `json:"flowctrl_enabled"`
|
||||
FwCaps FlexInt `json:"fw_caps"`
|
||||
HasFan FlexBool `json:"has_fan"`
|
||||
|
|
@ -51,11 +44,7 @@ type USW struct {
|
|||
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"`
|
||||
SwitchCaps *SwitchCaps `json:"switch_caps"`
|
||||
HwCaps FlexInt `json:"hw_caps"`
|
||||
Unsupported FlexBool `json:"unsupported"`
|
||||
UnsupportedReason FlexInt `json:"unsupported_reason"`
|
||||
|
|
@ -77,12 +66,7 @@ type USW struct {
|
|||
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"`
|
||||
DownlinkTable []*DownlinkTable `json:"downlink_table"`
|
||||
Uplink Uplink `json:"uplink"`
|
||||
LastUplink struct {
|
||||
UplinkMac string `json:"uplink_mac"`
|
||||
|
|
@ -97,7 +81,24 @@ type USW struct {
|
|||
GuestNumSta FlexInt `json:"guest-num_sta"`
|
||||
}
|
||||
|
||||
// Port is a physical connection on a USW or UDM.
|
||||
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 Gateway.
|
||||
// Not every port has the same capabilities.
|
||||
type Port struct {
|
||||
AggregatedBy FlexBool `json:"aggregated_by"`
|
||||
Autoneg FlexBool `json:"autoneg,omitempty"`
|
||||
|
|
@ -113,11 +114,13 @@ type Port struct {
|
|||
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"`
|
||||
|
|
@ -130,6 +133,7 @@ type Port struct {
|
|||
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"`
|
||||
|
|
@ -141,6 +145,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 +159,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"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,157 @@
|
|||
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 FlexBool `json:"model_in_lts"`
|
||||
ModelInEol FlexBool `json:"model_in_eol"`
|
||||
Type string `json:"type"`
|
||||
Version string `json:"version"`
|
||||
Adopted FlexBool `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 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 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 FlexBool `json:"has_fan"`
|
||||
HasTemperature FlexBool `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 FlexBool `json:"lcm_brightness_override"`
|
||||
LcmIdleTimeoutOverride FlexBool `json:"lcm_idle_timeout_override"`
|
||||
Name string `json:"name"`
|
||||
Unsupported FlexBool `json:"unsupported"`
|
||||
UnsupportedReason FlexInt `json:"unsupported_reason"`
|
||||
Serial string `json:"serial"`
|
||||
HashID string `json:"hash_id"`
|
||||
TwoPhaseAdopt FlexBool `json:"two_phase_adopt"`
|
||||
DeviceID string `json:"device_id"`
|
||||
State FlexInt `json:"state"`
|
||||
StartDisconnectedMillis FlexInt `json:"start_disconnected_millis"`
|
||||
UpgradeState FlexInt `json:"upgrade_state"`
|
||||
StartConnectedMillis FlexInt `json:"start_connected_millis"`
|
||||
LastSeen FlexInt `json:"last_seen"`
|
||||
Uptime FlexInt `json:"uptime"`
|
||||
UnderscoreUptime FlexInt `json:"_uptime"`
|
||||
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 FlexBool `json:"overheating"`
|
||||
GeoInfo map[string]*GeoInfo `json:"geo_info"`
|
||||
LedState *LedState `json:"led_state"`
|
||||
SpeedtestStatus *SpeedtestStatus `json:"speedtest-status"`
|
||||
SpeedtestStatusSaved FlexBool `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 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"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
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"`
|
||||
}
|
||||
|
||||
// UptimeStats is incuded with certain devices.
|
||||
type UptimeStats struct {
|
||||
Availability FlexInt `json:"availability"`
|
||||
LatencyAverage FlexInt `json:"latency_average"`
|
||||
TimePeriod FlexInt `json:"time_period"`
|
||||
}
|
||||
|
||||
// UXGStat holds the "stat" data for a 10Gb gateway.
|
||||
type UXGStat struct {
|
||||
*Gw `json:"gw"`
|
||||
*Sw `json:"sw"`
|
||||
}
|
||||
Loading…
Reference in New Issue