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
|
||||
|
||||
- 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.
|
||||
- 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.
|
||||
- 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 (
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"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.
|
||||
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)
|
||||
}
|
||||
|
||||
// Returns a list of input and output plugins: /api/v1/plugins.
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +68,8 @@ func (s *Server) handleOutput(w http.ResponseWriter, r *http.Request) {
|
|||
switch val := vars["value"]; vars["sub"] {
|
||||
default:
|
||||
s.handleJSON(w, c.Config)
|
||||
case "eventgroups":
|
||||
s.handleJSON(w, c.Events.Groups())
|
||||
case "events":
|
||||
switch events, ok := c.Events[val]; {
|
||||
case val == "":
|
||||
|
|
@ -95,6 +104,8 @@ func (s *Server) handleInput(w http.ResponseWriter, r *http.Request) {
|
|||
switch val := vars["value"]; vars["sub"] {
|
||||
default:
|
||||
s.handleJSON(w, c.Config)
|
||||
case "eventgroups":
|
||||
s.handleJSON(w, c.Events.Groups())
|
||||
case "events":
|
||||
switch events, ok := c.Events[val]; {
|
||||
case val == "":
|
||||
|
|
|
|||
|
|
@ -167,11 +167,11 @@ func (w *webPlugins) newInputEvent(plugin, id string, event *Event) {
|
|||
defer input.Unlock()
|
||||
|
||||
if input.Events == nil {
|
||||
input.Events = make(map[string]*Events)
|
||||
input.Events = make(Events)
|
||||
}
|
||||
|
||||
if _, ok := input.Events[id]; !ok {
|
||||
input.Events[id] = &Events{}
|
||||
input.Events[id] = &EventGroup{}
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
if output.Events == nil {
|
||||
output.Events = make(map[string]*Events)
|
||||
output.Events = make(Events)
|
||||
}
|
||||
|
||||
if _, ok := output.Events[id]; !ok {
|
||||
output.Events[id] = &Events{}
|
||||
output.Events[id] = &EventGroup{}
|
||||
}
|
||||
|
||||
output.Events[id].add(event, int(w.Config.MaxEvents))
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import (
|
|||
type Input struct {
|
||||
Name string
|
||||
Sites Sites
|
||||
Events map[string]*Events
|
||||
Events Events
|
||||
Devices Devices
|
||||
Clients Clients
|
||||
Config interface{}
|
||||
|
|
@ -25,7 +25,7 @@ type Input struct {
|
|||
// Setting Config will overwrite previous value.
|
||||
type Output struct {
|
||||
Name string
|
||||
Events map[string]*Events
|
||||
Events Events
|
||||
Config interface{}
|
||||
Counter map[string]int64
|
||||
sync.RWMutex // Locks this data structure.
|
||||
|
|
@ -41,14 +41,18 @@ type Sites []*Site
|
|||
|
||||
// Site is a network location and its meta data.
|
||||
type Site struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Desc string `json:"desc"`
|
||||
Source string `json:"source"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Desc string `json:"desc"`
|
||||
Source string `json:"source"`
|
||||
Controller string `json:"controller"`
|
||||
}
|
||||
|
||||
// Events allows each plugin to have a map of events. ie. one map per controller.
|
||||
type Events struct {
|
||||
// Events is all the events a plugin has. string = Controller.UUID + text.
|
||||
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"`
|
||||
Events []*Event `json:"events"`
|
||||
}
|
||||
|
|
@ -60,8 +64,16 @@ type Event struct {
|
|||
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.
|
||||
func (e *Events) add(event *Event, max int) {
|
||||
func (e *EventGroup) add(event *Event, max int) {
|
||||
if !e.Latest.Before(event.Ts) {
|
||||
return // Ignore older events.
|
||||
}
|
||||
|
|
@ -79,15 +91,18 @@ type Devices []*Device
|
|||
|
||||
// Device holds the data for a network device.
|
||||
type Device struct {
|
||||
Name string `json:"name"`
|
||||
SiteID string `json:"site_id"`
|
||||
Source string `json:"source"`
|
||||
MAC string `json:"mac"`
|
||||
IP string `json:"ip"`
|
||||
Type string `json:"type"`
|
||||
Model string `json:"model"`
|
||||
Version string `json:"version"`
|
||||
Config interface{} `json:"config,omitempty"`
|
||||
Clients int `json:"clients"`
|
||||
Uptime int `json:"uptime"`
|
||||
Name string `json:"name"`
|
||||
SiteID string `json:"site_id"`
|
||||
Source string `json:"source"`
|
||||
Controller string `json:"controller"`
|
||||
MAC string `json:"mac"`
|
||||
IP string `json:"ip"`
|
||||
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.
|
||||
|
|
@ -95,13 +110,16 @@ type Clients []*Client
|
|||
|
||||
// Client holds the data for a network client.
|
||||
type Client struct {
|
||||
Name string `json:"name"`
|
||||
SiteID string `json:"site_id"`
|
||||
Source string `json:"source"`
|
||||
MAC string `json:"mac"`
|
||||
IP string `json:"ip"`
|
||||
Type string `json:"type"`
|
||||
DeviceMAC string `json:"device_mac"`
|
||||
Since time.Time `json:"since"`
|
||||
Last time.Time `json:"last"`
|
||||
Rx int64 `json:"rx_bytes"`
|
||||
Tx int64 `json:"tx_bytes"`
|
||||
Name string `json:"name"`
|
||||
SiteID string `json:"site_id"`
|
||||
Source string `json:"source"`
|
||||
Controller string `json:"controller"`
|
||||
MAC string `json:"mac"`
|
||||
IP string `json:"ip"`
|
||||
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
|
||||
plugins *webPlugins
|
||||
Collect poller.Collect
|
||||
start time.Time
|
||||
}
|
||||
|
||||
// init is how this modular code is initialized by the main app.
|
||||
// This module adds itself as an output module to the poller core.
|
||||
func init() { // nolint: gochecknoinits
|
||||
s := &Server{plugins: plugins, Config: &Config{
|
||||
s := &Server{plugins: plugins, start: time.Now(), Config: &Config{
|
||||
Port: DefaultPort,
|
||||
HTMLPath: filepath.Join(poller.DefaultObjPath, "web"),
|
||||
MaxEvents: DefaultEvents,
|
||||
|
|
|
|||
Loading…
Reference in New Issue