Add controller 5.11 support.

This commit is contained in:
davidnewhall2 2019-07-07 15:23:02 -07:00
parent 36a47f5923
commit 493a399189
9 changed files with 658 additions and 374 deletions

View File

@ -12,3 +12,4 @@ install:
- dep ensure - dep ensure
script: script:
- golangci-lint run --enable-all -e G402 - golangci-lint run --enable-all -e G402
- go test ./...

View File

@ -54,10 +54,11 @@ type Unifi struct {
baseURL string baseURL string
ErrorLog Logger ErrorLog Logger
DebugLog Logger DebugLog Logger
*server
} }
// Server is the /status endpoint from the Unifi controller. // server is the /status endpoint from the Unifi controller.
type Server struct { type server struct {
Up FlexBool `json:"up"` Up FlexBool `json:"up"`
ServerVersion string `json:"server_version"` ServerVersion string `json:"server_version"`
UUID string `json:"uuid"` UUID string `json:"uuid"`

View File

@ -1,6 +1,9 @@
package unifi package unifi
import "time" import (
"encoding/json"
"time"
)
// UAP represents all the data from the Ubiquiti Controller for a Unifi Access Point. // UAP represents all the data from the Ubiquiti Controller for a Unifi Access Point.
type UAP struct { type UAP struct {
@ -305,7 +308,24 @@ type UAP struct {
UplinkMac string `json:"uplink_mac"` UplinkMac string `json:"uplink_mac"`
UplinkRemotePort int `json:"uplink_remote_port"` UplinkRemotePort int `json:"uplink_remote_port"`
} `json:"last_uplink"` } `json:"last_uplink"`
Stat struct { Stat *UAPStat `json:"stat"`
TxBytes FlexInt `json:"tx_bytes"`
RxBytes FlexInt `json:"rx_bytes"`
Bytes FlexInt `json:"bytes"`
VwireEnabled FlexBool `json:"vwireEnabled"`
UplinkTable []interface{} `json:"uplink_table"`
NumSta int `json:"num_sta"`
UserNumSta int `json:"user-num_sta"`
GuestNumSta int `json:"guest-num_sta"`
TwoPhaseAdopt FlexBool `json:"two_phase_adopt,omitempty"`
}
// UAPStat holds the "stat" data for an access point.
// This is split out because of a JSON data format change from 5.10 to 5.11.
type UAPStat struct {
*ap
}
type ap struct {
SiteID string `json:"site_id"` SiteID string `json:"site_id"`
O string `json:"o"` O string `json:"o"`
Oid string `json:"oid"` Oid string `json:"oid"`
@ -440,14 +460,17 @@ type UAP struct {
WifiTxDropped FlexInt `json:"wifi_tx_dropped"` WifiTxDropped FlexInt `json:"wifi_tx_dropped"`
Bytes FlexInt `json:"bytes"` Bytes FlexInt `json:"bytes"`
Duration FlexInt `json:"duration"` Duration FlexInt `json:"duration"`
} `json:"stat,omitempty"` }
TxBytes FlexInt `json:"tx_bytes"`
RxBytes FlexInt `json:"rx_bytes"` // UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Access Point Stat data.
Bytes FlexInt `json:"bytes"` func (v *UAPStat) UnmarshalJSON(data []byte) error {
VwireEnabled FlexBool `json:"vwireEnabled"` var n struct {
UplinkTable []interface{} `json:"uplink_table"` ap `json:"ap"`
NumSta int `json:"num_sta"` }
UserNumSta int `json:"user-num_sta"` v.ap = &n.ap
GuestNumSta int `json:"guest-num_sta"` err := json.Unmarshal(data, v.ap) // controller version 5.10.
TwoPhaseAdopt FlexBool `json:"two_phase_adopt,omitempty"` if err != nil {
return json.Unmarshal(data, &n) // controller version 5.11.
}
return nil
} }

View File

@ -0,0 +1,53 @@
package unifi
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestUAPUnmarshalJSON(t *testing.T) {
testcontroller511 := `{
"ap": {
"site_id": "mySite",
"o": "ap",
"oid": "00:00:00:00:00:00",
"ap": "00:00:00:00:00:00",
"time": 1577742600000,
"datetime": "2019-12-30T09:50:00Z",
"user-wifi1-rx_packets": 6596670,
"user-wifi0-rx_packets": 42659527,
"user-rx_packets": 49294197,
"guest-rx_packets": 0,
"wifi0-rx_packets": 42639527,
"wifi1-rx_packets": 6591670,
"rx_packets": 49299197}}`
testcontroller510 := `{
"site_id": "mySite",
"o": "ap",
"oid": "00:00:00:00:00:00",
"ap": "00:00:00:00:00:00",
"time": 1577742600000,
"datetime": "2019-12-30T09:50:00Z",
"user-wifi1-rx_packets": 6596670,
"user-wifi0-rx_packets": 42659527,
"user-rx_packets": 49294197,
"guest-rx_packets": 0,
"wifi0-rx_packets": 42639527,
"wifi1-rx_packets": 6591670,
"rx_packets": 49299197}`
t.Parallel()
a := assert.New(t)
u := &UAPStat{}
err := u.UnmarshalJSON([]byte(testcontroller510))
a.Nil(err, "must be no error unmarshaling test strings")
a.Equal(float64(49299197), u.RxPackets.Val, "data was not properly unmarshaled")
u = &UAPStat{} // reset
err = u.UnmarshalJSON([]byte(testcontroller511))
a.Nil(err, "must be no error unmarshaling test strings")
a.Equal(float64(49299197), u.RxPackets.Val, "data was not properly unmarshaled")
}

View File

@ -58,16 +58,22 @@ func (u *Unifi) getController(user, pass string) error {
return errors.Errorf("authentication failed (user: %s): %s (status: %s)", return errors.Errorf("authentication failed (user: %s): %s (status: %s)",
user, u.baseURL+LoginPath, resp.Status) user, u.baseURL+LoginPath, resp.Status)
} }
return nil return errors.Wrap(u.getServer(), "unable to get server version")
}
// getServer sets the controller's version and UUID.
func (u *Unifi) getServer() error {
var response struct {
Data server `json:"meta"`
}
u.server = &response.Data
return u.GetData(StatusPath, &response)
} }
// GetServer returns the controller's version and UUID. // GetServer returns the controller's version and UUID.
func (u *Unifi) GetServer() (Server, error) { // This method is deprecated and will go away in a future release, use u.Server*
var response struct { func (u *Unifi) GetServer() (*server, error) {
Data Server `json:"meta"` return u.server, nil
}
err := u.GetData(StatusPath, &response)
return response.Data, err
} }
// GetClients returns a response full of clients' data from the Unifi Controller. // GetClients returns a response full of clients' data from the Unifi Controller.

View File

@ -1,6 +1,9 @@
package unifi package unifi
import "time" import (
"encoding/json"
"time"
)
// USG represents all the data from the Ubiquiti Controller for a Unifi Security Gateway. // USG represents all the data from the Ubiquiti Controller for a Unifi Security Gateway.
type USG struct { type USG struct {
@ -230,7 +233,25 @@ type USG struct {
MaxSpeed FlexInt `json:"max_speed"` MaxSpeed FlexInt `json:"max_speed"`
Type string `json:"type"` Type string `json:"type"`
} `json:"uplink"` } `json:"uplink"`
Stat struct { Stat *USGStat `json:"stat"`
TxBytes FlexInt `json:"tx_bytes"`
RxBytes FlexInt `json:"rx_bytes"`
Bytes FlexInt `json:"bytes"`
NumSta FlexInt `json:"num_sta"`
UserNumSta FlexInt `json:"user-num_sta"`
GuestNumSta FlexInt `json:"guest-num_sta"`
NumDesktop FlexInt `json:"num_desktop"`
NumMobile FlexInt `json:"num_mobile"`
NumHandheld FlexInt `json:"num_handheld"`
}
// USGStat holds the "stat" data for a gateway.
// This is split out because of a JSON data format change from 5.10 to 5.11.
type USGStat struct {
*gw
}
type gw struct {
SiteID string `json:"site_id"` SiteID string `json:"site_id"`
O string `json:"o"` O string `json:"o"`
Oid string `json:"oid"` Oid string `json:"oid"`
@ -248,14 +269,17 @@ type USG struct {
LanTxBytes FlexInt `json:"lan-tx_bytes"` LanTxBytes FlexInt `json:"lan-tx_bytes"`
WanRxDropped FlexInt `json:"wan-rx_dropped"` WanRxDropped FlexInt `json:"wan-rx_dropped"`
LanRxDropped FlexInt `json:"lan-rx_dropped"` LanRxDropped FlexInt `json:"lan-rx_dropped"`
} `json:"stat"` }
TxBytes FlexInt `json:"tx_bytes"`
RxBytes FlexInt `json:"rx_bytes"` // UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Gateway Stat data.
Bytes FlexInt `json:"bytes"` func (v *USGStat) UnmarshalJSON(data []byte) error {
NumSta FlexInt `json:"num_sta"` var n struct {
UserNumSta FlexInt `json:"user-num_sta"` gw `json:"gw"`
GuestNumSta FlexInt `json:"guest-num_sta"` }
NumDesktop FlexInt `json:"num_desktop"` v.gw = &n.gw
NumMobile FlexInt `json:"num_mobile"` err := json.Unmarshal(data, v.gw) // controller version 5.10.
NumHandheld FlexInt `json:"num_handheld"` if err != nil {
return json.Unmarshal(data, &n) // controller version 5.11.
}
return nil
} }

View File

@ -0,0 +1,59 @@
package unifi
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestUSGUnmarshalJSON(t *testing.T) {
testcontroller511 := `{
"gw": {
"site_id": "mySite",
"o": "gw",
"oid": "00:00:00:00:00:00",
"gw": "00:00:00:00:00:00",
"time": 1577742600000,
"datetime": "2019-12-30T09:50:00Z",
"bytes": 0,
"duration": 3590568000,
"wan-rx_packets": 299729434558,
"wan-rx_bytes": 299882768958208,
"wan-tx_packets": 249639259523,
"wan-tx_bytes": 169183252492369,
"lan-rx_packets": 78912349453,
"lan-rx_bytes": 37599596992669,
"lan-tx_packets": 12991234992,
"lan-tx_bytes": 11794664098210}}`
testcontroller510 := `{
"site_id": "mySite",
"o": "gw",
"oid": "00:00:00:00:00:00",
"gw": "00:00:00:00:00:00",
"time": 1577742600000,
"datetime": "2019-12-30T09:50:00Z",
"bytes": 0,
"duration": 3590568000,
"wan-rx_packets": 299729434558,
"wan-rx_bytes": 299882768958208,
"wan-tx_packets": 249639259523,
"wan-tx_bytes": 169183252492369,
"lan-rx_packets": 78912349453,
"lan-rx_bytes": 37599596992669,
"lan-tx_packets": 12991234992,
"lan-tx_bytes": 11794664098210}`
t.Parallel()
a := assert.New(t)
u := &USGStat{}
err := u.UnmarshalJSON([]byte(testcontroller510))
a.Nil(err, "must be no error unmarshaling test strings")
a.Equal(float64(37599596992669), u.LanRxBytes.Val, "data was not properly unmarshaled")
u = &USGStat{} // reset
err = u.UnmarshalJSON([]byte(testcontroller511))
a.Nil(err, "must be no error unmarshaling test strings")
a.Equal(float64(37599596992669), u.LanRxBytes.Val, "data was not properly unmarshaled")
}

View File

@ -1,6 +1,9 @@
package unifi package unifi
import "time" import (
"encoding/json"
"time"
)
// USW represents all the data from the Ubiquiti Controller for a Unifi Switch. // USW represents all the data from the Ubiquiti Controller for a Unifi Switch.
type USW struct { type USW struct {
@ -168,7 +171,22 @@ type USW struct {
UplinkMac string `json:"uplink_mac"` UplinkMac string `json:"uplink_mac"`
} `json:"last_uplink"` } `json:"last_uplink"`
UplinkDepth FlexInt `json:"uplink_depth"` UplinkDepth FlexInt `json:"uplink_depth"`
Stat struct { Stat *USWStat `json:"stat"`
TxBytes FlexInt `json:"tx_bytes"`
RxBytes FlexInt `json:"rx_bytes"`
Bytes FlexInt `json:"bytes"`
NumSta FlexInt `json:"num_sta"`
UserNumSta FlexInt `json:"user-num_sta"`
GuestNumSta FlexInt `json:"guest-num_sta"`
}
// USWStat holds the "stat" data for a switch.
// This is split out because of a JSON data format change from 5.10 to 5.11.
type USWStat struct {
*sw
}
type sw struct {
SiteID string `json:"site_id"` SiteID string `json:"site_id"`
O string `json:"o"` O string `json:"o"`
Oid string `json:"oid"` Oid string `json:"oid"`
@ -358,11 +376,17 @@ type USW struct {
Port4RxBroadcast FlexInt `json:"port_4-rx_broadcast"` Port4RxBroadcast FlexInt `json:"port_4-rx_broadcast"`
Port4TxMulticast FlexInt `json:"port_4-tx_multicast"` Port4TxMulticast FlexInt `json:"port_4-tx_multicast"`
Port4TxBroadcast FlexInt `json:"port_4-tx_broadcast"` Port4TxBroadcast FlexInt `json:"port_4-tx_broadcast"`
} `json:"stat"` }
TxBytes FlexInt `json:"tx_bytes"`
RxBytes FlexInt `json:"rx_bytes"` // UnmarshalJSON unmarshalls 5.10 or 5.11 formatted Switch Stat data.
Bytes FlexInt `json:"bytes"` func (v *USWStat) UnmarshalJSON(data []byte) error {
NumSta FlexInt `json:"num_sta"` var n struct {
UserNumSta FlexInt `json:"user-num_sta"` sw `json:"sw"`
GuestNumSta FlexInt `json:"guest-num_sta"` }
v.sw = &n.sw
err := json.Unmarshal(data, v.sw) // controller version 5.10.
if err != nil {
return json.Unmarshal(data, &n) // controller version 5.11.
}
return nil
} }

View File

@ -0,0 +1,93 @@
package unifi
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestUSWUnmarshalJSON(t *testing.T) {
testcontroller511 := `{
"sw": {
"site_id": "mySite",
"o": "sw",
"oid": "00:00:00:00:00:00",
"sw": "00:00:00:00:00:00",
"time": 1577742600000,
"datetime": "2019-12-30T09:40:00Z",
"rx_packets": 321,
"rx_bytes": 321,
"rx_errors": 123,
"rx_dropped": 123,
"rx_crypts": 123,
"rx_frags": 123,
"tx_packets": 123,
"tx_bytes": 123,
"tx_errors": 0,
"tx_dropped": 0,
"tx_retries": 0,
"rx_multicast": 123,
"rx_broadcast": 123,
"tx_multicast": 123,
"tx_broadcast": 123,
"bytes": 123,
"duration": 123,
"port_1-tx_packets": 123,
"port_1-tx_bytes": 123,
"port_1-tx_multicast": 123,
"port_1-tx_broadcast": 123,
"port_1-rx_packets": 123,
"port_1-rx_bytes": 123,
"port_1-rx_dropped": 123,
"port_1-rx_multicast": 123,
"port_1-rx_broadcast": 123,
"port_1-rx_errors": 123}}`
testcontroller510 := `{
"site_id": "mySite",
"o": "sw",
"oid": "00:00:00:00:00:00",
"sw": "00:00:00:00:00:00",
"time": 1577742600000,
"datetime": "2019-12-30T09:40:00Z",
"rx_packets": 321,
"rx_bytes": 321,
"rx_errors": 123,
"rx_dropped": 123,
"rx_crypts": 123,
"rx_frags": 123,
"tx_packets": 123,
"tx_bytes": 123,
"tx_errors": 0,
"tx_dropped": 0,
"tx_retries": 0,
"rx_multicast": 123,
"rx_broadcast": 123,
"tx_multicast": 123,
"tx_broadcast": 123,
"bytes": 123,
"duration": 123,
"port_1-tx_packets": 123,
"port_1-tx_bytes": 123,
"port_1-tx_multicast": 123,
"port_1-tx_broadcast": 123,
"port_1-rx_packets": 123,
"port_1-rx_bytes": 123,
"port_1-rx_dropped": 123,
"port_1-rx_multicast": 123,
"port_1-rx_broadcast": 123,
"port_1-rx_errors": 123}`
t.Parallel()
a := assert.New(t)
u := &USWStat{}
err := u.UnmarshalJSON([]byte(testcontroller510))
a.Nil(err, "must be no error unmarshaling test strings")
a.Equal(float64(123), u.RxMulticast.Val, "data was not properly unmarshaled")
u = &USWStat{} // reset
err = u.UnmarshalJSON([]byte(testcontroller511))
a.Nil(err, "must be no error unmarshaling test strings")
a.Equal(float64(123), u.RxMulticast.Val, "data was not properly unmarshaled")
}