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
|
language: go
|
||||||
go:
|
go:
|
||||||
- 1.14.x
|
- 1.15.x
|
||||||
before_install:
|
before_install:
|
||||||
# download super-linter: golangci-lint
|
# 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 latest
|
||||||
script:
|
script:
|
||||||
- golangci-lint run --enable-all
|
- golangci-lint run --enable-all -D exhaustivestruct,nlreturn
|
||||||
- go test ./...
|
- go test ./...
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ func (u *Unifi) GetAlarms(sites []*Site) ([]*Alarm, error) {
|
||||||
// GetAlarmsSite retreives the Alarms for a single Site.
|
// GetAlarmsSite retreives the Alarms for a single Site.
|
||||||
func (u *Unifi) GetAlarmsSite(site *Site) ([]*Alarm, error) {
|
func (u *Unifi) GetAlarmsSite(site *Site) ([]*Alarm, error) {
|
||||||
if site == nil || site.Name == "" {
|
if site == nil || site.Name == "" {
|
||||||
return nil, errNoSiteProvided
|
return nil, ErrNoSiteProvided
|
||||||
}
|
}
|
||||||
|
|
||||||
u.DebugLog("Polling Controller for Alarms, site %s (%s)", site.Name, site.Desc)
|
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.
|
// GetAnomaliesSite retreives the Anomalies for a single Site.
|
||||||
func (u *Unifi) GetAnomaliesSite(site *Site, timeRange ...time.Time) ([]*Anomaly, error) {
|
func (u *Unifi) GetAnomaliesSite(site *Site, timeRange ...time.Time) ([]*Anomaly, error) {
|
||||||
if site == nil || site.Name == "" {
|
if site == nil || site.Name == "" {
|
||||||
return nil, errNoSiteProvided
|
return nil, ErrNoSiteProvided
|
||||||
}
|
}
|
||||||
|
|
||||||
u.DebugLog("Polling Controller for Anomalies, site %s (%s)", site.Name, site.Desc)
|
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)
|
end := timeRange[1].Unix() * int64(time.Microsecond)
|
||||||
out = append(out, "end="+strconv.FormatInt(end, 10), "start="+strconv.FormatInt(start, 10))
|
out = append(out, "end="+strconv.FormatInt(end, 10), "start="+strconv.FormatInt(start, 10))
|
||||||
default:
|
default:
|
||||||
return "", errInvalidTimeRange
|
return "", ErrInvalidTimeRange
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(out) == 0 {
|
if len(out) == 0 {
|
||||||
|
|
|
||||||
|
|
@ -36,42 +36,27 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices {
|
||||||
|
|
||||||
for _, r := range data {
|
for _, r := range data {
|
||||||
// Loop each item in the raw JSON message, detect its type and unmarshal it.
|
// Loop each item in the raw JSON message, detect its type and unmarshal it.
|
||||||
assetType := "<type key missing>"
|
o := make(map[string]interface{})
|
||||||
|
if u.unmarshalDevice("map", r, &o) != nil {
|
||||||
if o := make(map[string]interface{}); u.unmarshalDevice("map", r, &o) != nil {
|
u.ErrorLog("unknown asset type - cannot find asset type in payload - skipping")
|
||||||
continue
|
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)
|
u.DebugLog("Unmarshalling Device Type: %v, site %s ", assetType, siteName)
|
||||||
// Choose which type to unmarshal into based on the "type" json key.
|
// Choose which type to unmarshal into based on the "type" json key.
|
||||||
|
|
||||||
switch assetType { // Unmarshal again into the correct type..
|
switch assetType { // Unmarshal again into the correct type..
|
||||||
case "uap":
|
case "uap":
|
||||||
dev := &UAP{SiteName: siteName, SourceName: u.URL}
|
u.unmarshallUAP(siteName, r, devices)
|
||||||
if u.unmarshalDevice(assetType, r, dev) == nil {
|
|
||||||
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.
|
case "ugw", "usg": // in case they ever fix the name in the api.
|
||||||
dev := &USG{SiteName: siteName, SourceName: u.URL}
|
u.unmarshallUSG(siteName, r, devices)
|
||||||
if u.unmarshalDevice(assetType, r, dev) == nil {
|
|
||||||
dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac))
|
|
||||||
devices.USGs = append(devices.USGs, dev)
|
|
||||||
}
|
|
||||||
case "usw":
|
case "usw":
|
||||||
dev := &USW{SiteName: siteName, SourceName: u.URL}
|
u.unmarshallUSW(siteName, r, devices)
|
||||||
if u.unmarshalDevice(assetType, r, dev) == nil {
|
|
||||||
dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac))
|
|
||||||
devices.USWs = append(devices.USWs, dev)
|
|
||||||
}
|
|
||||||
case "udm":
|
case "udm":
|
||||||
dev := &UDM{SiteName: siteName, SourceName: u.URL}
|
u.unmarshallUDM(siteName, r, devices)
|
||||||
if u.unmarshalDevice(assetType, r, dev) == nil {
|
case "uxg":
|
||||||
dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac))
|
u.unmarshallUXG(siteName, r, devices)
|
||||||
devices.UDMs = append(devices.UDMs, dev)
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
u.ErrorLog("unknown asset type - %v - skipping", assetType)
|
u.ErrorLog("unknown asset type - %v - skipping", assetType)
|
||||||
}
|
}
|
||||||
|
|
@ -80,6 +65,46 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices {
|
||||||
return 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().
|
// unmarshalDevice handles logging for the unmarshal operations in parseDevices().
|
||||||
func (u *Unifi) unmarshalDevice(dev string, data json.RawMessage, v interface{}) (err error) {
|
func (u *Unifi) unmarshalDevice(dev string, data json.RawMessage, v interface{}) (err error) {
|
||||||
if err = json.Unmarshal(data, v); err != nil {
|
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 -==")
|
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.
|
// pick returns the first non empty string in a list.
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,17 @@ type DPIData struct {
|
||||||
TxBytes int64 `json:"tx_bytes"`
|
TxBytes int64 `json:"tx_bytes"`
|
||||||
RxPackets int64 `json:"rx_packets"`
|
RxPackets int64 `json:"rx_packets"`
|
||||||
TxPackets int64 `json:"tx_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.
|
// DPIMap allows binding methods to the DPICat and DPIApps variables.
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errNoSiteProvided = fmt.Errorf("site must not be nil or empty")
|
ErrNoSiteProvided = fmt.Errorf("site must not be nil or empty")
|
||||||
errInvalidTimeRange = fmt.Errorf("only 0, 1 or 2 times may be provided to timeRange")
|
ErrInvalidTimeRange = fmt.Errorf("only 0, 1 or 2 times may be provided to timeRange")
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
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.
|
// 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) {
|
func (u *Unifi) GetSiteEvents(site *Site, hours time.Duration) ([]*Event, error) {
|
||||||
if site == nil || site.Name == "" {
|
if site == nil || site.Name == "" {
|
||||||
return nil, errNoSiteProvided
|
return nil, ErrNoSiteProvided
|
||||||
}
|
}
|
||||||
|
|
||||||
if hours < time.Hour {
|
if hours < time.Hour {
|
||||||
|
|
@ -196,5 +196,9 @@ func (v *IPGeo) UnmarshalJSON(data []byte) error {
|
||||||
v.CountryName = g.CountryName
|
v.CountryName = g.CountryName
|
||||||
v.Organization = g.Organization
|
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
|
module github.com/unifi-poller/unifi
|
||||||
|
|
||||||
go 1.14
|
go 1.15
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/pkg/errors v0.9.1
|
|
||||||
github.com/stretchr/testify v1.4.0
|
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-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 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-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-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-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-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.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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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 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().
|
// Events between start and end are returned. End defaults to time.Now().
|
||||||
func (u *Unifi) GetIDSSite(site *Site, timeRange ...time.Time) ([]*IDS, error) {
|
func (u *Unifi) GetIDSSite(site *Site, timeRange ...time.Time) ([]*IDS, error) {
|
||||||
if site == nil || site.Name == "" {
|
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)
|
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.Start = timeRange[0].Unix() * int64(time.Microsecond)
|
||||||
rp.End = timeRange[1].Unix() * int64(time.Microsecond)
|
rp.End = timeRange[1].Unix() * int64(time.Microsecond)
|
||||||
default:
|
default:
|
||||||
return "", errInvalidTimeRange
|
return "", ErrInvalidTimeRange
|
||||||
}
|
}
|
||||||
|
|
||||||
params, err := json.Marshal(&rp)
|
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
|
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)
|
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 {
|
type Network struct {
|
||||||
DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"`
|
DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"`
|
||||||
DhcpdEnabled FlexBool `json:"dhcpd_enabled"`
|
DhcpdEnabled FlexBool `json:"dhcpd_enabled"`
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var ErrDPIDataBug = fmt.Errorf("dpi data table contains more than 1 item; please open a bug report")
|
||||||
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.
|
// GetSites returns a list of configured sites on the UniFi controller.
|
||||||
func (u *Unifi) GetSites() ([]*Site, error) {
|
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 {
|
if l := len(response.Data); l > 1 {
|
||||||
return nil, errDPIDataBug
|
return nil, ErrDPIDataBug
|
||||||
} else if l == 0 {
|
} 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 (%s) ", site.Name, site.Desc)
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,10 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var ErrCannotUnmarshalFlexInt = fmt.Errorf("cannot unmarshal to FlexInt")
|
||||||
errCannotUnmarshalFlexInt = fmt.Errorf("cannot unmarshal to FlexInt")
|
|
||||||
)
|
|
||||||
|
|
||||||
// This is a list of unifi API paths.
|
// This is a list of unifi API paths.
|
||||||
// The %s in each string must be replaced with a Site.Name.
|
// 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 string = "/api/s/%s/stat/sitedpi"
|
||||||
// APISiteDPI is site DPI data.
|
// APISiteDPI is site DPI data.
|
||||||
APIClientDPI string = "/api/s/%s/stat/stadpi"
|
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"
|
APIClientPath string = "/api/s/%s/stat/sta"
|
||||||
// APINetworkPath is where we get data about Unifi networks.
|
// APINetworkPath is where we get data about Unifi networks.
|
||||||
APINetworkPath string = "/api/s/%s/rest/networkconf"
|
APINetworkPath string = "/api/s/%s/rest/networkconf"
|
||||||
// APIDevicePath is where we get data about Unifi devices.
|
// APIDevicePath is where we get data about Unifi devices.
|
||||||
APIDevicePath string = "/api/s/%s/stat/device"
|
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"
|
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"
|
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"
|
APIEventPathIDS string = "/api/s/%s/stat/ips/event"
|
||||||
// APIEventPathAlarms contains the site alarms.
|
// APIEventPathAlarms contains the site alarms.
|
||||||
APIEventPathAlarms string = "/api/s/%s/list/alarm"
|
APIEventPathAlarms string = "/api/s/%s/list/alarm"
|
||||||
|
|
@ -79,6 +76,7 @@ type Devices struct {
|
||||||
USGs []*USG
|
USGs []*USG
|
||||||
USWs []*USW
|
USWs []*USW
|
||||||
UDMs []*UDM
|
UDMs []*UDM
|
||||||
|
UXGs []*UXG
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config is the data passed into our library. This configures things and allows
|
// Config is the data passed into our library. This configures things and allows
|
||||||
|
|
@ -91,6 +89,7 @@ type Config struct {
|
||||||
New bool
|
New bool
|
||||||
ErrorLog Logger
|
ErrorLog Logger
|
||||||
DebugLog 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
|
// 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{}
|
var unk interface{}
|
||||||
|
|
||||||
if err := json.Unmarshal(b, &unk); err != nil {
|
if err := json.Unmarshal(b, &unk); err != nil {
|
||||||
return err
|
return fmt.Errorf("json unmarshal: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch i := unk.(type) {
|
switch i := unk.(type) {
|
||||||
|
|
@ -138,7 +137,7 @@ func (f *FlexInt) UnmarshalJSON(b []byte) error {
|
||||||
f.Txt = "0"
|
f.Txt = "0"
|
||||||
f.Val = 0
|
f.Val = 0
|
||||||
default:
|
default:
|
||||||
return errors.Wrapf(errCannotUnmarshalFlexInt, "%v", b)
|
return fmt.Errorf("%v: %w", b, ErrCannotUnmarshalFlexInt)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,7 @@ type UDM struct {
|
||||||
LastSeen FlexInt `json:"last_seen"`
|
LastSeen FlexInt `json:"last_seen"`
|
||||||
AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"`
|
AdoptableWhenUpgraded FlexBool `json:"adoptable_when_upgraded"`
|
||||||
Cfgversion string `json:"cfgversion"`
|
Cfgversion string `json:"cfgversion"`
|
||||||
ConfigNetwork struct {
|
ConfigNetwork *ConfigNetwork `json:"config_network"`
|
||||||
Type string `json:"type"`
|
|
||||||
IP string `json:"ip"`
|
|
||||||
} `json:"config_network"`
|
|
||||||
VwireTable []interface{} `json:"vwire_table"`
|
VwireTable []interface{} `json:"vwire_table"`
|
||||||
Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"`
|
Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"`
|
||||||
JumboframeEnabled FlexBool `json:"jumboframe_enabled"`
|
JumboframeEnabled FlexBool `json:"jumboframe_enabled"`
|
||||||
|
|
@ -49,16 +46,9 @@ type UDM struct {
|
||||||
InformIP string `json:"inform_ip"`
|
InformIP string `json:"inform_ip"`
|
||||||
RequiredVersion string `json:"required_version"`
|
RequiredVersion string `json:"required_version"`
|
||||||
BoardRev FlexInt `json:"board_rev"`
|
BoardRev FlexInt `json:"board_rev"`
|
||||||
EthernetTable []struct {
|
EthernetTable []*EthernetTable `json:"ethernet_table"`
|
||||||
Mac string `json:"mac"`
|
|
||||||
NumPort FlexInt `json:"num_port"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
} `json:"ethernet_table"`
|
|
||||||
PortTable []Port `json:"port_table"`
|
PortTable []Port `json:"port_table"`
|
||||||
EthernetOverrides []struct {
|
EthernetOverrides []*EthernetOverrides `json:"ethernet_overrides"`
|
||||||
Ifname string `json:"ifname"`
|
|
||||||
Networkgroup string `json:"networkgroup"`
|
|
||||||
} `json:"ethernet_overrides"`
|
|
||||||
UsgCaps FlexInt `json:"usg_caps"`
|
UsgCaps FlexInt `json:"usg_caps"`
|
||||||
HasSpeaker FlexBool `json:"has_speaker"`
|
HasSpeaker FlexBool `json:"has_speaker"`
|
||||||
HasEth1 FlexBool `json:"has_eth1"`
|
HasEth1 FlexBool `json:"has_eth1"`
|
||||||
|
|
@ -96,7 +86,7 @@ type UDM struct {
|
||||||
Uplink Uplink `json:"uplink"`
|
Uplink Uplink `json:"uplink"`
|
||||||
ConnectRequestIP string `json:"connect_request_ip"`
|
ConnectRequestIP string `json:"connect_request_ip"`
|
||||||
ConnectRequestPort string `json:"connect_request_port"`
|
ConnectRequestPort string `json:"connect_request_port"`
|
||||||
DownlinkTable []interface{} `json:"downlink_table"`
|
DownlinkTable []*DownlinkTable `json:"downlink_table"`
|
||||||
WlangroupIDNa string `json:"wlangroup_id_na"`
|
WlangroupIDNa string `json:"wlangroup_id_na"`
|
||||||
WlangroupIDNg string `json:"wlangroup_id_ng"`
|
WlangroupIDNg string `json:"wlangroup_id_ng"`
|
||||||
BandsteeringMode string `json:"bandsteering_mode"`
|
BandsteeringMode string `json:"bandsteering_mode"`
|
||||||
|
|
@ -110,6 +100,7 @@ type UDM struct {
|
||||||
PortconfID string `json:"portconf_id"`
|
PortconfID string `json:"portconf_id"`
|
||||||
} `json:"port_overrides"`
|
} `json:"port_overrides"`
|
||||||
Stat UDMStat `json:"stat"`
|
Stat UDMStat `json:"stat"`
|
||||||
|
Storage []*Storage `json:"storage"`
|
||||||
TxBytes FlexInt `json:"tx_bytes"`
|
TxBytes FlexInt `json:"tx_bytes"`
|
||||||
RxBytes FlexInt `json:"rx_bytes"`
|
RxBytes FlexInt `json:"rx_bytes"`
|
||||||
Bytes FlexInt `json:"bytes"`
|
Bytes FlexInt `json:"bytes"`
|
||||||
|
|
@ -131,7 +122,19 @@ type UDM struct {
|
||||||
NumHandheld FlexInt `json:"num_handheld"` // 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.
|
// NetworkTable is the list of networks on a gateway.
|
||||||
|
// Not all gateways have all features.
|
||||||
type NetworkTable []struct {
|
type NetworkTable []struct {
|
||||||
ID string `json:"_id"`
|
ID string `json:"_id"`
|
||||||
AttrNoDelete FlexBool `json:"attr_no_delete"`
|
AttrNoDelete FlexBool `json:"attr_no_delete"`
|
||||||
|
|
@ -150,6 +153,7 @@ type NetworkTable []struct {
|
||||||
Dhcpdv6Enabled FlexBool `json:"dhcpdv6_enabled"`
|
Dhcpdv6Enabled FlexBool `json:"dhcpdv6_enabled"`
|
||||||
Ipv6RaEnabled FlexBool `json:"ipv6_ra_enabled"`
|
Ipv6RaEnabled FlexBool `json:"ipv6_ra_enabled"`
|
||||||
LteLanEnabled FlexBool `json:"lte_lan_enabled"`
|
LteLanEnabled FlexBool `json:"lte_lan_enabled"`
|
||||||
|
AutoScaleEnabled FlexBool `json:"auto_scale_enabled"`
|
||||||
Networkgroup string `json:"networkgroup"`
|
Networkgroup string `json:"networkgroup"`
|
||||||
DhcpdLeasetime FlexInt `json:"dhcpd_leasetime"`
|
DhcpdLeasetime FlexInt `json:"dhcpd_leasetime"`
|
||||||
DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"`
|
DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"`
|
||||||
|
|
@ -167,6 +171,9 @@ type NetworkTable []struct {
|
||||||
IsGuest FlexBool `json:"is_guest"`
|
IsGuest FlexBool `json:"is_guest"`
|
||||||
IP string `json:"ip"`
|
IP string `json:"ip"`
|
||||||
Up FlexBool `json:"up"`
|
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"`
|
NumSta FlexInt `json:"num_sta"`
|
||||||
RxBytes FlexInt `json:"rx_bytes"`
|
RxBytes FlexInt `json:"rx_bytes"`
|
||||||
RxPackets FlexInt `json:"rx_packets"`
|
RxPackets FlexInt `json:"rx_packets"`
|
||||||
|
|
@ -174,6 +181,15 @@ type NetworkTable []struct {
|
||||||
TxPackets FlexInt `json:"tx_packets"`
|
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 {
|
type Temperature struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ package unifi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -18,13 +19,13 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"golang.org/x/net/publicsuffix"
|
"golang.org/x/net/publicsuffix"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errAuthenticationFailed = fmt.Errorf("authentication failed")
|
ErrAuthenticationFailed = fmt.Errorf("authentication failed")
|
||||||
errInvalidStatusCode = fmt.Errorf("invalid status code from server")
|
ErrInvalidStatusCode = fmt.Errorf("invalid status code from server")
|
||||||
|
ErrNoParams = fmt.Errorf("requedted PUT with no parameters")
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewUnifi creates a http.Client with authenticated cookies.
|
// NewUnifi creates a http.Client with authenticated cookies.
|
||||||
|
|
@ -33,7 +34,7 @@ var (
|
||||||
func NewUnifi(config *Config) (*Unifi, error) {
|
func NewUnifi(config *Config) (*Unifi, error) {
|
||||||
jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
|
jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("creating cookiejar: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
config.URL = strings.TrimRight(config.URL, "/")
|
config.URL = strings.TrimRight(config.URL, "/")
|
||||||
|
|
@ -46,8 +47,10 @@ func NewUnifi(config *Config) (*Unifi, error) {
|
||||||
config.DebugLog = discardLogs
|
config.DebugLog = discardLogs
|
||||||
}
|
}
|
||||||
|
|
||||||
u := &Unifi{Config: config,
|
u := &Unifi{
|
||||||
|
Config: config,
|
||||||
Client: &http.Client{
|
Client: &http.Client{
|
||||||
|
Timeout: config.Timeout,
|
||||||
Jar: jar,
|
Jar: jar,
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: !config.VerifySSL}, // nolint: gosec
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: !config.VerifySSL}, // nolint: gosec
|
||||||
|
|
@ -64,7 +67,7 @@ func NewUnifi(config *Config) (*Unifi, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := u.GetServerData(); err != nil {
|
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
|
return u, nil
|
||||||
|
|
@ -82,7 +85,7 @@ func (u *Unifi) Login() error {
|
||||||
|
|
||||||
resp, err := u.Do(req)
|
resp, err := u.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("making request: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer resp.Body.Close() // we need no data here.
|
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)
|
req.URL, time.Since(start).Round(time.Millisecond), resp.ContentLength)
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
return errors.Wrapf(errAuthenticationFailed, "(user: %s): %s (status: %s)",
|
return fmt.Errorf("(user: %s): %s (status: %s): %w",
|
||||||
u.User, req.URL, resp.Status)
|
u.User, req.URL, resp.Status, ErrAuthenticationFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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.
|
// 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.
|
// Setting new to true makes the path() method return different (new) paths.
|
||||||
func (u *Unifi) checkNewStyleAPI() error {
|
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)
|
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 {
|
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.
|
// 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)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("making request: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer resp.Body.Close() // we need no data here.
|
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.
|
// 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. :)
|
// And if you're doing that... sumbut a pull request with your new struct. :)
|
||||||
// This is a helper method that is exposed for convenience.
|
// 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 {
|
switch apiPath = u.path(apiPath); params {
|
||||||
case "":
|
case "":
|
||||||
req, err = http.NewRequest("GET", u.URL+apiPath, nil)
|
req, err = http.NewRequest(http.MethodGet, u.URL+apiPath, nil)
|
||||||
default:
|
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 {
|
if err != nil {
|
||||||
return
|
return nil, fmt.Errorf("creating request: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
u.setHeaders(req, params)
|
u.setHeaders(req, params)
|
||||||
|
|
||||||
return
|
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) (req *http.Request, err error) {
|
func (u *Unifi) UniReqPut(apiPath string, params string) (*http.Request, error) {
|
||||||
switch apiPath = u.path(apiPath); params {
|
if params == "" {
|
||||||
case "":
|
return nil, ErrNoParams
|
||||||
err = fmt.Errorf("Put with no parameters. Use UniReq()")
|
|
||||||
default:
|
|
||||||
req, err = http.NewRequest("PUT", u.URL+apiPath, bytes.NewBufferString(params))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apiPath = u.path(apiPath)
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodPut, u.URL+apiPath, bytes.NewBufferString(params)) //nolint:noctx
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, fmt.Errorf("creating request: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
u.setHeaders(req, params)
|
u.setHeaders(req, params)
|
||||||
|
|
||||||
return
|
return req, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetJSON returns the raw JSON from a path. This is useful for debugging.
|
// 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
|
// 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) {
|
func (u *Unifi) PutJSON(apiPath string, params ...string) ([]byte, error) {
|
||||||
req, err := u.UniReqPut(apiPath, strings.Join(params, " "))
|
req, err := u.UniReqPut(apiPath, strings.Join(params, " "))
|
||||||
if err != nil {
|
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) {
|
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 {
|
if err != nil {
|
||||||
return []byte{}, err
|
return []byte{}, fmt.Errorf("making request: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return body, err
|
return body, fmt.Errorf("reading response: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the returned CSRF header.
|
// Save the returned CSRF header.
|
||||||
|
|
@ -260,7 +288,7 @@ func (u *Unifi) do(req *http.Request) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
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
|
return body, err
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,11 @@ func TestUniReq(t *testing.T) {
|
||||||
a := assert.New(t)
|
a := assert.New(t)
|
||||||
p := "/test/path"
|
p := "/test/path"
|
||||||
u := "http://some.url:8443"
|
u := "http://some.url:8443"
|
||||||
|
|
||||||
// Test empty parameters.
|
// 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, "")
|
r, err := authReq.UniReq(p, "")
|
||||||
|
|
||||||
a.Nil(err, "newrequest must not produce an error")
|
a.Nil(err, "newrequest must not produce an error")
|
||||||
a.EqualValues(p, r.URL.Path,
|
a.EqualValues(p, r.URL.Path,
|
||||||
"the provided apiPath was not added to http request")
|
"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}}
|
authReq = &Unifi{Client: &http.Client{}, Config: &Config{URL: "http://some.url:8443", DebugLog: discardLogs}}
|
||||||
r, err = authReq.UniReq(p, k)
|
r, err = authReq.UniReq(p, k)
|
||||||
a.Nil(err, "newrequest must not produce an error")
|
a.Nil(err, "newrequest must not produce an error")
|
||||||
|
|
||||||
a.EqualValues(p, r.URL.Path,
|
a.EqualValues(p, r.URL.Path,
|
||||||
"the provided apiPath was not added to http request")
|
"the provided apiPath was not added to http request")
|
||||||
a.EqualValues(u, 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("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")
|
a.EqualValues("application/json", r.Header.Get("Accept"), "Accept header must be set to application/json")
|
||||||
|
|
||||||
// Check the parameters.
|
// Check the parameters.
|
||||||
d, err := ioutil.ReadAll(r.Body)
|
d, err := ioutil.ReadAll(r.Body)
|
||||||
a.Nil(err, "problem reading request body, POST parameters may be malformed")
|
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)
|
a := assert.New(t)
|
||||||
p := "/test/path"
|
p := "/test/path"
|
||||||
u := "http://some.url:8443"
|
u := "http://some.url:8443"
|
||||||
|
|
||||||
// Test empty parameters.
|
// 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.UniReqPut(p, "")
|
_, err := authReq.UniReqPut(p, "")
|
||||||
a.NotNil(err, "empty params must produce an error")
|
a.NotNil(err, "empty params must produce an error")
|
||||||
|
|
||||||
// Test with parameters
|
// Test with parameters
|
||||||
k := "key1=value9&key2=value7"
|
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.UniReqPut(p, k)
|
r, err := authReq.UniReqPut(p, k)
|
||||||
a.Nil(err, "newrequest must not produce an error")
|
a.Nil(err, "newrequest must not produce an error")
|
||||||
|
|
||||||
a.EqualValues(p, r.URL.Path,
|
a.EqualValues(p, r.URL.Path,
|
||||||
"the provided apiPath was not added to http request")
|
"the provided apiPath was not added to http request")
|
||||||
a.EqualValues(u, r.URL.Scheme+"://"+r.URL.Host, "URL improperly encoded")
|
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("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")
|
a.EqualValues("application/json", r.Header.Get("Accept"), "Accept header must be set to application/json")
|
||||||
|
|
||||||
// Check the parameters.
|
// Check the parameters.
|
||||||
d, err := ioutil.ReadAll(r.Body)
|
d, err := ioutil.ReadAll(r.Body)
|
||||||
a.Nil(err, "problem reading request body, PUT parameters may be malformed")
|
a.Nil(err, "problem reading request body, PUT parameters may be malformed")
|
||||||
a.EqualValues(k, string(d), "PUT parameters improperly encoded")
|
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),
|
a.EqualValues(`{"username": "user1","password": "pass2"}`, string(post_params),
|
||||||
"user/pass json parameters improperly encoded")
|
"user/pass json parameters improperly encoded")
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,8 @@ type USG struct {
|
||||||
ID string `json:"_id"`
|
ID string `json:"_id"`
|
||||||
Adopted FlexBool `json:"adopted"`
|
Adopted FlexBool `json:"adopted"`
|
||||||
Cfgversion string `json:"cfgversion"`
|
Cfgversion string `json:"cfgversion"`
|
||||||
ConfigNetwork struct {
|
ConfigNetwork *ConfigNetwork `json:"config_network"`
|
||||||
Type string `json:"type"`
|
EthernetTable []*EthernetTable `json:"ethernet_table"`
|
||||||
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"`
|
FwCaps FlexInt `json:"fw_caps"`
|
||||||
InformIP string `json:"inform_ip"`
|
InformIP string `json:"inform_ip"`
|
||||||
InformURL string `json:"inform_url"`
|
InformURL string `json:"inform_url"`
|
||||||
|
|
@ -37,10 +30,7 @@ type USG struct {
|
||||||
UsgCaps FlexInt `json:"usg_caps"`
|
UsgCaps FlexInt `json:"usg_caps"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
RequiredVersion string `json:"required_version"`
|
RequiredVersion string `json:"required_version"`
|
||||||
EthernetOverrides []struct {
|
EthernetOverrides []*EthernetOverrides `json:"ethernet_overrides"`
|
||||||
Ifname string `json:"ifname"`
|
|
||||||
Networkgroup string `json:"networkgroup"`
|
|
||||||
} `json:"ethernet_overrides"`
|
|
||||||
HwCaps FlexInt `json:"hw_caps"`
|
HwCaps FlexInt `json:"hw_caps"`
|
||||||
BoardRev FlexInt `json:"board_rev"`
|
BoardRev FlexInt `json:"board_rev"`
|
||||||
Unsupported FlexBool `json:"unsupported"`
|
Unsupported FlexBool `json:"unsupported"`
|
||||||
|
|
@ -57,34 +47,14 @@ type USG struct {
|
||||||
ConnectRequestIP string `json:"connect_request_ip"`
|
ConnectRequestIP string `json:"connect_request_ip"`
|
||||||
ConnectRequestPort string `json:"connect_request_port"`
|
ConnectRequestPort string `json:"connect_request_port"`
|
||||||
SysStats SysStats `json:"sys_stats"`
|
SysStats SysStats `json:"sys_stats"`
|
||||||
|
Temperatures []Temperature `json:"temperatures,omitempty"`
|
||||||
SystemStats SystemStats `json:"system-stats"`
|
SystemStats SystemStats `json:"system-stats"`
|
||||||
GuestToken string `json:"guest_token"`
|
GuestToken string `json:"guest_token"`
|
||||||
SpeedtestStatus SpeedtestStatus `json:"speedtest-status"`
|
SpeedtestStatus SpeedtestStatus `json:"speedtest-status"`
|
||||||
SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"`
|
SpeedtestStatusSaved FlexBool `json:"speedtest-status-saved"`
|
||||||
Wan1 Wan `json:"wan1"`
|
Wan1 Wan `json:"wan1"`
|
||||||
Wan2 Wan `json:"wan2"`
|
Wan2 Wan `json:"wan2"`
|
||||||
PortTable []struct {
|
PortTable []*Port `json:"port_table"`
|
||||||
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"`
|
NetworkTable NetworkTable `json:"network_table"`
|
||||||
Uplink Uplink `json:"uplink"`
|
Uplink Uplink `json:"uplink"`
|
||||||
Stat USGStat `json:"stat"`
|
Stat USGStat `json:"stat"`
|
||||||
|
|
@ -114,12 +84,15 @@ type Uplink struct {
|
||||||
Nameservers []string `json:"nameservers"`
|
Nameservers []string `json:"nameservers"`
|
||||||
Netmask string `json:"netmask"`
|
Netmask string `json:"netmask"`
|
||||||
NumPort FlexInt `json:"num_port"`
|
NumPort FlexInt `json:"num_port"`
|
||||||
|
Media string `json:"media"`
|
||||||
|
PortIdx FlexInt `json:"port_idx"`
|
||||||
RxBytes FlexInt `json:"rx_bytes"`
|
RxBytes FlexInt `json:"rx_bytes"`
|
||||||
RxBytesR FlexInt `json:"rx_bytes-r"`
|
RxBytesR FlexInt `json:"rx_bytes-r"`
|
||||||
RxDropped FlexInt `json:"rx_dropped"`
|
RxDropped FlexInt `json:"rx_dropped"`
|
||||||
RxErrors FlexInt `json:"rx_errors"`
|
RxErrors FlexInt `json:"rx_errors"`
|
||||||
RxMulticast FlexInt `json:"rx_multicast"`
|
RxMulticast FlexInt `json:"rx_multicast"`
|
||||||
RxPackets FlexInt `json:"rx_packets"`
|
RxPackets FlexInt `json:"rx_packets"`
|
||||||
|
RxRate FlexInt `json:"rx_rate"`
|
||||||
Speed FlexInt `json:"speed"`
|
Speed FlexInt `json:"speed"`
|
||||||
SpeedtestLastrun FlexInt `json:"speedtest_lastrun,omitempty"`
|
SpeedtestLastrun FlexInt `json:"speedtest_lastrun,omitempty"`
|
||||||
SpeedtestPing FlexInt `json:"speedtest_ping,omitempty"`
|
SpeedtestPing FlexInt `json:"speedtest_ping,omitempty"`
|
||||||
|
|
@ -129,6 +102,7 @@ type Uplink struct {
|
||||||
TxDropped FlexInt `json:"tx_dropped"`
|
TxDropped FlexInt `json:"tx_dropped"`
|
||||||
TxErrors FlexInt `json:"tx_errors"`
|
TxErrors FlexInt `json:"tx_errors"`
|
||||||
TxPackets FlexInt `json:"tx_packets"`
|
TxPackets FlexInt `json:"tx_packets"`
|
||||||
|
TxRate FlexInt `json:"tx_rate"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Up FlexBool `json:"up"`
|
Up FlexBool `json:"up"`
|
||||||
Uptime FlexInt `json:"uptime"`
|
Uptime FlexInt `json:"uptime"`
|
||||||
|
|
@ -140,7 +114,7 @@ type Uplink struct {
|
||||||
type Wan struct {
|
type Wan struct {
|
||||||
Autoneg FlexBool `json:"autoneg"`
|
Autoneg FlexBool `json:"autoneg"`
|
||||||
BytesR FlexInt `json:"bytes-r"`
|
BytesR FlexInt `json:"bytes-r"`
|
||||||
DNS []string `json:"dns"`
|
DNS []string `json:"dns"` // may be deprecated
|
||||||
Enable FlexBool `json:"enable"`
|
Enable FlexBool `json:"enable"`
|
||||||
FlowctrlRx FlexBool `json:"flowctrl_rx"`
|
FlowctrlRx FlexBool `json:"flowctrl_rx"`
|
||||||
FlowctrlTx FlexBool `json:"flowctrl_tx"`
|
FlowctrlTx FlexBool `json:"flowctrl_tx"`
|
||||||
|
|
@ -164,7 +138,9 @@ type Wan struct {
|
||||||
RxErrors FlexInt `json:"rx_errors"`
|
RxErrors FlexInt `json:"rx_errors"`
|
||||||
RxMulticast FlexInt `json:"rx_multicast"`
|
RxMulticast FlexInt `json:"rx_multicast"`
|
||||||
RxPackets FlexInt `json:"rx_packets"`
|
RxPackets FlexInt `json:"rx_packets"`
|
||||||
|
RxRate FlexInt `json:"rx_rate"`
|
||||||
Speed FlexInt `json:"speed"`
|
Speed FlexInt `json:"speed"`
|
||||||
|
SpeedCaps FlexInt `json:"speed_caps"`
|
||||||
TxBroadcast FlexInt `json:"tx_broadcast"`
|
TxBroadcast FlexInt `json:"tx_broadcast"`
|
||||||
TxBytes FlexInt `json:"tx_bytes"`
|
TxBytes FlexInt `json:"tx_bytes"`
|
||||||
TxBytesR FlexInt `json:"tx_bytes-r"`
|
TxBytesR FlexInt `json:"tx_bytes-r"`
|
||||||
|
|
@ -172,6 +148,7 @@ type Wan struct {
|
||||||
TxErrors FlexInt `json:"tx_errors"`
|
TxErrors FlexInt `json:"tx_errors"`
|
||||||
TxMulticast FlexInt `json:"tx_multicast"`
|
TxMulticast FlexInt `json:"tx_multicast"`
|
||||||
TxPackets FlexInt `json:"tx_packets"`
|
TxPackets FlexInt `json:"tx_packets"`
|
||||||
|
TxRate FlexInt `json:"tx_rate"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Up FlexBool `json:"up"`
|
Up FlexBool `json:"up"`
|
||||||
}
|
}
|
||||||
|
|
@ -182,6 +159,8 @@ type SpeedtestStatus struct {
|
||||||
Rundate FlexInt `json:"rundate"`
|
Rundate FlexInt `json:"rundate"`
|
||||||
Runtime FlexInt `json:"runtime"`
|
Runtime FlexInt `json:"runtime"`
|
||||||
ServerDesc string `json:"server_desc,omitempty"`
|
ServerDesc string `json:"server_desc,omitempty"`
|
||||||
|
Server *SpeedtestServer `json:"server"`
|
||||||
|
SourceInterface string `json:"source_interface"`
|
||||||
StatusDownload FlexInt `json:"status_download"`
|
StatusDownload FlexInt `json:"status_download"`
|
||||||
StatusPing FlexInt `json:"status_ping"`
|
StatusPing FlexInt `json:"status_ping"`
|
||||||
StatusSummary FlexInt `json:"status_summary"`
|
StatusSummary FlexInt `json:"status_summary"`
|
||||||
|
|
@ -190,6 +169,22 @@ type SpeedtestStatus struct {
|
||||||
XputUpload FlexInt `json:"xput_upload"`
|
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.
|
// SystemStats is system info for a UDM, USG, USW.
|
||||||
type SystemStats struct {
|
type SystemStats struct {
|
||||||
CPU FlexInt `json:"cpu"`
|
CPU FlexInt `json:"cpu"`
|
||||||
|
|
@ -233,6 +228,7 @@ type Gw struct {
|
||||||
LanTxBytes FlexInt `json:"lan-tx_bytes"`
|
LanTxBytes FlexInt `json:"lan-tx_bytes"`
|
||||||
LanRxDropped FlexInt `json:"lan-rx_dropped"`
|
LanRxDropped FlexInt `json:"lan-rx_dropped"`
|
||||||
WanRxErrors FlexInt `json:"wan-rx_errors,omitempty"`
|
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.
|
// UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Gateway Stat data.
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,9 @@ type USW struct {
|
||||||
Adopted FlexBool `json:"adopted"`
|
Adopted FlexBool `json:"adopted"`
|
||||||
BoardRev FlexInt `json:"board_rev"`
|
BoardRev FlexInt `json:"board_rev"`
|
||||||
Cfgversion string `json:"cfgversion"`
|
Cfgversion string `json:"cfgversion"`
|
||||||
ConfigNetwork struct {
|
ConfigNetwork *ConfigNetwork `json:"config_network"`
|
||||||
Type string `json:"type"`
|
|
||||||
IP string `json:"ip"`
|
|
||||||
} `json:"config_network"`
|
|
||||||
Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"`
|
Dot1XPortctrlEnabled FlexBool `json:"dot1x_portctrl_enabled"`
|
||||||
EthernetTable []struct {
|
EthernetTable []*EthernetTable `json:"ethernet_table"`
|
||||||
Mac string `json:"mac"`
|
|
||||||
NumPort FlexInt `json:"num_port,omitempty"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
} `json:"ethernet_table"`
|
|
||||||
FlowctrlEnabled FlexBool `json:"flowctrl_enabled"`
|
FlowctrlEnabled FlexBool `json:"flowctrl_enabled"`
|
||||||
FwCaps FlexInt `json:"fw_caps"`
|
FwCaps FlexInt `json:"fw_caps"`
|
||||||
HasFan FlexBool `json:"has_fan"`
|
HasFan FlexBool `json:"has_fan"`
|
||||||
|
|
@ -51,11 +44,7 @@ type USW struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
RequiredVersion string `json:"required_version"`
|
RequiredVersion string `json:"required_version"`
|
||||||
SwitchCaps struct {
|
SwitchCaps *SwitchCaps `json:"switch_caps"`
|
||||||
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"`
|
HwCaps FlexInt `json:"hw_caps"`
|
||||||
Unsupported FlexBool `json:"unsupported"`
|
Unsupported FlexBool `json:"unsupported"`
|
||||||
UnsupportedReason FlexInt `json:"unsupported_reason"`
|
UnsupportedReason FlexInt `json:"unsupported_reason"`
|
||||||
|
|
@ -77,12 +66,7 @@ type USW struct {
|
||||||
GeneralTemperature FlexInt `json:"general_temperature"`
|
GeneralTemperature FlexInt `json:"general_temperature"`
|
||||||
Overheating FlexBool `json:"overheating"`
|
Overheating FlexBool `json:"overheating"`
|
||||||
TotalMaxPower FlexInt `json:"total_max_power"`
|
TotalMaxPower FlexInt `json:"total_max_power"`
|
||||||
DownlinkTable []struct {
|
DownlinkTable []*DownlinkTable `json:"downlink_table"`
|
||||||
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"`
|
Uplink Uplink `json:"uplink"`
|
||||||
LastUplink struct {
|
LastUplink struct {
|
||||||
UplinkMac string `json:"uplink_mac"`
|
UplinkMac string `json:"uplink_mac"`
|
||||||
|
|
@ -97,7 +81,24 @@ type USW struct {
|
||||||
GuestNumSta FlexInt `json:"guest-num_sta"`
|
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 {
|
type Port struct {
|
||||||
AggregatedBy FlexBool `json:"aggregated_by"`
|
AggregatedBy FlexBool `json:"aggregated_by"`
|
||||||
Autoneg FlexBool `json:"autoneg,omitempty"`
|
Autoneg FlexBool `json:"autoneg,omitempty"`
|
||||||
|
|
@ -113,11 +114,13 @@ type Port struct {
|
||||||
Ifname string `json:"ifname,omitempty"`
|
Ifname string `json:"ifname,omitempty"`
|
||||||
IsUplink FlexBool `json:"is_uplink"`
|
IsUplink FlexBool `json:"is_uplink"`
|
||||||
Mac string `json:"mac,omitempty"`
|
Mac string `json:"mac,omitempty"`
|
||||||
|
MacTable []MacTable `json:"mac_table,omitempty"`
|
||||||
Jumbo FlexBool `json:"jumbo,omitempty"`
|
Jumbo FlexBool `json:"jumbo,omitempty"`
|
||||||
Masked FlexBool `json:"masked"`
|
Masked FlexBool `json:"masked"`
|
||||||
Media string `json:"media"`
|
Media string `json:"media"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
NetworkName string `json:"network_name,omitempty"`
|
NetworkName string `json:"network_name,omitempty"`
|
||||||
|
Netmask string `json:"netmask,omitempty"`
|
||||||
NumPort int `json:"num_port,omitempty"`
|
NumPort int `json:"num_port,omitempty"`
|
||||||
OpMode string `json:"op_mode"`
|
OpMode string `json:"op_mode"`
|
||||||
PoeCaps FlexInt `json:"poe_caps"`
|
PoeCaps FlexInt `json:"poe_caps"`
|
||||||
|
|
@ -130,6 +133,7 @@ type Port struct {
|
||||||
PoeVoltage FlexInt `json:"poe_voltage,omitempty"`
|
PoeVoltage FlexInt `json:"poe_voltage,omitempty"`
|
||||||
PortDelta struct {
|
PortDelta struct {
|
||||||
TimeDelta int64 `json:"time_delta"`
|
TimeDelta int64 `json:"time_delta"`
|
||||||
|
TimeDeltaActivity int64 `json:"time_delta_activity"`
|
||||||
} `json:"port_delta,omitempty"`
|
} `json:"port_delta,omitempty"`
|
||||||
PortIdx FlexInt `json:"port_idx"`
|
PortIdx FlexInt `json:"port_idx"`
|
||||||
PortPoe FlexBool `json:"port_poe"`
|
PortPoe FlexBool `json:"port_poe"`
|
||||||
|
|
@ -141,6 +145,7 @@ type Port struct {
|
||||||
RxErrors FlexInt `json:"rx_errors"`
|
RxErrors FlexInt `json:"rx_errors"`
|
||||||
RxMulticast FlexInt `json:"rx_multicast"`
|
RxMulticast FlexInt `json:"rx_multicast"`
|
||||||
RxPackets FlexInt `json:"rx_packets"`
|
RxPackets FlexInt `json:"rx_packets"`
|
||||||
|
RxRate FlexInt `json:"rx_rate,omitempty"`
|
||||||
Satisfaction FlexInt `json:"satisfaction,omitempty"`
|
Satisfaction FlexInt `json:"satisfaction,omitempty"`
|
||||||
SfpFound FlexBool `json:"sfp_found,omitempty"`
|
SfpFound FlexBool `json:"sfp_found,omitempty"`
|
||||||
Speed FlexInt `json:"speed"`
|
Speed FlexInt `json:"speed"`
|
||||||
|
|
@ -154,6 +159,7 @@ type Port struct {
|
||||||
TxErrors FlexInt `json:"tx_errors"`
|
TxErrors FlexInt `json:"tx_errors"`
|
||||||
TxMulticast FlexInt `json:"tx_multicast"`
|
TxMulticast FlexInt `json:"tx_multicast"`
|
||||||
TxPackets FlexInt `json:"tx_packets"`
|
TxPackets FlexInt `json:"tx_packets"`
|
||||||
|
TxRate FlexInt `json:"tx_rate,omitempty"`
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
Up FlexBool `json:"up"`
|
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