add uptimes, rx/tx per client, controller id, eventgroups
This commit is contained in:
parent
55612d3e27
commit
3aa0bab6b2
|
|
@ -13,7 +13,6 @@ The web server may be secured with a simple password. SSL is also optional.
|
||||||
### Controllers
|
### Controllers
|
||||||
|
|
||||||
- The web server interface allows you to see the configuration for each controller.
|
- The web server interface allows you to see the configuration for each controller.
|
||||||
- You may select a controller, and then select a site on the controller.
|
|
||||||
- Some meta data about each controller is displayed, such as sites, clients and devices.
|
- Some meta data about each controller is displayed, such as sites, clients and devices.
|
||||||
- Example config: [up.json.example](https://github.com/unifi-poller/unifi-poller/blob/master/examples/up.json.example)
|
- Example config: [up.json.example](https://github.com/unifi-poller/unifi-poller/blob/master/examples/up.json.example)
|
||||||
|
|
||||||
|
|
@ -26,47 +25,3 @@ The web server may be secured with a simple password. SSL is also optional.
|
||||||
|
|
||||||
- You may view output plugin configuration. Currently Prometheus and InfluxDB.
|
- You may view output plugin configuration. Currently Prometheus and InfluxDB.
|
||||||
- The example config above shows output plugin data.
|
- The example config above shows output plugin data.
|
||||||
|
|
||||||
### Sites
|
|
||||||
|
|
||||||
Each controller has 1 or more sites. Most people only have 1, but some enterprises
|
|
||||||
run this software and have many more. Each site has devices like switches (`USW`), access
|
|
||||||
points (`UAP`) and routers (`USG`/`UDM`). We'll have counts for each device type. Each device has a name.
|
|
||||||
Each device has a count of clients (access points have clients). We'll want to expose
|
|
||||||
this, but it's not in a useful format yet. It'll look something like what you see below,
|
|
||||||
but keep the visualization expandable. We may add "model" and "serial number" for each device.
|
|
||||||
There is a handful of meta data per device. Some users have hundreds of devices.
|
|
||||||
```
|
|
||||||
{
|
|
||||||
"site_name_here": {
|
|
||||||
"clients": 22,
|
|
||||||
"UAP": [
|
|
||||||
{
|
|
||||||
"name": "ap1-room",
|
|
||||||
"clients": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ap2-bran",
|
|
||||||
"clients": 6
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"USW": [
|
|
||||||
{
|
|
||||||
"name": "sw1-cube",
|
|
||||||
"model": "US-500w-P",
|
|
||||||
"serial": "xyz637sjs999",
|
|
||||||
"clients": 7
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "sw2-trap",
|
|
||||||
"clients": 3
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"USG": [
|
|
||||||
{
|
|
||||||
"name": "gw1-role",
|
|
||||||
"clients": 22
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package webserver
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
@ -35,13 +36,19 @@ func (s *Server) handleStatic(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// Returns web server and poller configs. /api/v1/config.
|
// Returns web server and poller configs. /api/v1/config.
|
||||||
func (s *Server) handleConfig(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
data := map[string]interface{}{"poller": s.Collect.Poller()}
|
data := map[string]interface{}{
|
||||||
|
"poller": s.Collect.Poller(),
|
||||||
|
"uptime": int(time.Since(s.start).Round(time.Second).Seconds()),
|
||||||
|
}
|
||||||
s.handleJSON(w, data)
|
s.handleJSON(w, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a list of input and output plugins: /api/v1/plugins.
|
// Returns a list of input and output plugins: /api/v1/plugins.
|
||||||
func (s *Server) handlePlugins(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handlePlugins(w http.ResponseWriter, r *http.Request) {
|
||||||
data := map[string][]string{"inputs": s.Collect.Inputs(), "outputs": s.Collect.Outputs()}
|
data := map[string][]string{
|
||||||
|
"inputs": s.Collect.Inputs(),
|
||||||
|
"outputs": s.Collect.Outputs(),
|
||||||
|
}
|
||||||
s.handleJSON(w, data)
|
s.handleJSON(w, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,6 +68,8 @@ func (s *Server) handleOutput(w http.ResponseWriter, r *http.Request) {
|
||||||
switch val := vars["value"]; vars["sub"] {
|
switch val := vars["value"]; vars["sub"] {
|
||||||
default:
|
default:
|
||||||
s.handleJSON(w, c.Config)
|
s.handleJSON(w, c.Config)
|
||||||
|
case "eventgroups":
|
||||||
|
s.handleJSON(w, c.Events.Groups())
|
||||||
case "events":
|
case "events":
|
||||||
switch events, ok := c.Events[val]; {
|
switch events, ok := c.Events[val]; {
|
||||||
case val == "":
|
case val == "":
|
||||||
|
|
@ -95,6 +104,8 @@ func (s *Server) handleInput(w http.ResponseWriter, r *http.Request) {
|
||||||
switch val := vars["value"]; vars["sub"] {
|
switch val := vars["value"]; vars["sub"] {
|
||||||
default:
|
default:
|
||||||
s.handleJSON(w, c.Config)
|
s.handleJSON(w, c.Config)
|
||||||
|
case "eventgroups":
|
||||||
|
s.handleJSON(w, c.Events.Groups())
|
||||||
case "events":
|
case "events":
|
||||||
switch events, ok := c.Events[val]; {
|
switch events, ok := c.Events[val]; {
|
||||||
case val == "":
|
case val == "":
|
||||||
|
|
|
||||||
|
|
@ -167,11 +167,11 @@ func (w *webPlugins) newInputEvent(plugin, id string, event *Event) {
|
||||||
defer input.Unlock()
|
defer input.Unlock()
|
||||||
|
|
||||||
if input.Events == nil {
|
if input.Events == nil {
|
||||||
input.Events = make(map[string]*Events)
|
input.Events = make(Events)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := input.Events[id]; !ok {
|
if _, ok := input.Events[id]; !ok {
|
||||||
input.Events[id] = &Events{}
|
input.Events[id] = &EventGroup{}
|
||||||
}
|
}
|
||||||
|
|
||||||
input.Events[id].add(event, int(w.Config.MaxEvents))
|
input.Events[id].add(event, int(w.Config.MaxEvents))
|
||||||
|
|
@ -187,11 +187,11 @@ func (w *webPlugins) newOutputEvent(plugin, id string, event *Event) {
|
||||||
defer output.Unlock()
|
defer output.Unlock()
|
||||||
|
|
||||||
if output.Events == nil {
|
if output.Events == nil {
|
||||||
output.Events = make(map[string]*Events)
|
output.Events = make(Events)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := output.Events[id]; !ok {
|
if _, ok := output.Events[id]; !ok {
|
||||||
output.Events[id] = &Events{}
|
output.Events[id] = &EventGroup{}
|
||||||
}
|
}
|
||||||
|
|
||||||
output.Events[id].add(event, int(w.Config.MaxEvents))
|
output.Events[id].add(event, int(w.Config.MaxEvents))
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import (
|
||||||
type Input struct {
|
type Input struct {
|
||||||
Name string
|
Name string
|
||||||
Sites Sites
|
Sites Sites
|
||||||
Events map[string]*Events
|
Events Events
|
||||||
Devices Devices
|
Devices Devices
|
||||||
Clients Clients
|
Clients Clients
|
||||||
Config interface{}
|
Config interface{}
|
||||||
|
|
@ -25,7 +25,7 @@ type Input struct {
|
||||||
// Setting Config will overwrite previous value.
|
// Setting Config will overwrite previous value.
|
||||||
type Output struct {
|
type Output struct {
|
||||||
Name string
|
Name string
|
||||||
Events map[string]*Events
|
Events Events
|
||||||
Config interface{}
|
Config interface{}
|
||||||
Counter map[string]int64
|
Counter map[string]int64
|
||||||
sync.RWMutex // Locks this data structure.
|
sync.RWMutex // Locks this data structure.
|
||||||
|
|
@ -41,14 +41,18 @@ type Sites []*Site
|
||||||
|
|
||||||
// Site is a network location and its meta data.
|
// Site is a network location and its meta data.
|
||||||
type Site struct {
|
type Site struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Desc string `json:"desc"`
|
Desc string `json:"desc"`
|
||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
|
Controller string `json:"controller"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Events allows each plugin to have a map of events. ie. one map per controller.
|
// Events is all the events a plugin has. string = Controller.UUID + text.
|
||||||
type Events struct {
|
type Events map[string]*EventGroup
|
||||||
|
|
||||||
|
// EventGroup allows each plugin to have a map of events. ie. one map per controller.
|
||||||
|
type EventGroup struct {
|
||||||
Latest time.Time `json:"latest"`
|
Latest time.Time `json:"latest"`
|
||||||
Events []*Event `json:"events"`
|
Events []*Event `json:"events"`
|
||||||
}
|
}
|
||||||
|
|
@ -60,8 +64,16 @@ type Event struct {
|
||||||
Tags map[string]string `json:"tags,omitempty"`
|
Tags map[string]string `json:"tags,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e Events) Groups() (groups []string) {
|
||||||
|
for n := range e {
|
||||||
|
groups = append(groups, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups
|
||||||
|
}
|
||||||
|
|
||||||
// add adds a new event and makes sure the slice is not too big.
|
// add adds a new event and makes sure the slice is not too big.
|
||||||
func (e *Events) add(event *Event, max int) {
|
func (e *EventGroup) add(event *Event, max int) {
|
||||||
if !e.Latest.Before(event.Ts) {
|
if !e.Latest.Before(event.Ts) {
|
||||||
return // Ignore older events.
|
return // Ignore older events.
|
||||||
}
|
}
|
||||||
|
|
@ -79,15 +91,18 @@ type Devices []*Device
|
||||||
|
|
||||||
// Device holds the data for a network device.
|
// Device holds the data for a network device.
|
||||||
type Device struct {
|
type Device struct {
|
||||||
Name string `json:"name"`
|
Clients int `json:"clients"`
|
||||||
SiteID string `json:"site_id"`
|
Uptime int `json:"uptime"`
|
||||||
Source string `json:"source"`
|
Name string `json:"name"`
|
||||||
MAC string `json:"mac"`
|
SiteID string `json:"site_id"`
|
||||||
IP string `json:"ip"`
|
Source string `json:"source"`
|
||||||
Type string `json:"type"`
|
Controller string `json:"controller"`
|
||||||
Model string `json:"model"`
|
MAC string `json:"mac"`
|
||||||
Version string `json:"version"`
|
IP string `json:"ip"`
|
||||||
Config interface{} `json:"config,omitempty"`
|
Type string `json:"type"`
|
||||||
|
Model string `json:"model"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Config interface{} `json:"config,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clients is a list of clients with their data.
|
// Clients is a list of clients with their data.
|
||||||
|
|
@ -95,13 +110,16 @@ type Clients []*Client
|
||||||
|
|
||||||
// Client holds the data for a network client.
|
// Client holds the data for a network client.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
Name string `json:"name"`
|
Rx int64 `json:"rx_bytes"`
|
||||||
SiteID string `json:"site_id"`
|
Tx int64 `json:"tx_bytes"`
|
||||||
Source string `json:"source"`
|
Name string `json:"name"`
|
||||||
MAC string `json:"mac"`
|
SiteID string `json:"site_id"`
|
||||||
IP string `json:"ip"`
|
Source string `json:"source"`
|
||||||
Type string `json:"type"`
|
Controller string `json:"controller"`
|
||||||
DeviceMAC string `json:"device_mac"`
|
MAC string `json:"mac"`
|
||||||
Since time.Time `json:"since"`
|
IP string `json:"ip"`
|
||||||
Last time.Time `json:"last"`
|
Type string `json:"type"`
|
||||||
|
DeviceMAC string `json:"device_mac"`
|
||||||
|
Since time.Time `json:"since"`
|
||||||
|
Last time.Time `json:"last"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,12 +43,13 @@ type Server struct {
|
||||||
server *http.Server
|
server *http.Server
|
||||||
plugins *webPlugins
|
plugins *webPlugins
|
||||||
Collect poller.Collect
|
Collect poller.Collect
|
||||||
|
start time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// init is how this modular code is initialized by the main app.
|
// init is how this modular code is initialized by the main app.
|
||||||
// This module adds itself as an output module to the poller core.
|
// This module adds itself as an output module to the poller core.
|
||||||
func init() { // nolint: gochecknoinits
|
func init() { // nolint: gochecknoinits
|
||||||
s := &Server{plugins: plugins, Config: &Config{
|
s := &Server{plugins: plugins, start: time.Now(), Config: &Config{
|
||||||
Port: DefaultPort,
|
Port: DefaultPort,
|
||||||
HTMLPath: filepath.Join(poller.DefaultObjPath, "web"),
|
HTMLPath: filepath.Join(poller.DefaultObjPath, "web"),
|
||||||
MaxEvents: DefaultEvents,
|
MaxEvents: DefaultEvents,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue