ubnt-freifunk-map-api/unifi.go
Stefan Hoffmann e7aa06f647
All checks were successful
continuous-integration/drone/push Build is passing
Housekeeping
2021-05-18 21:17:09 +02:00

214 lines
5.1 KiB
Go

package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"strconv"
"strings"
"time"
)
//Unifi Controller API processing
func processUcAPIs() ([]node, []link) {
//get list of Unifi devices to display
var nodes []node
var links []link
d := getDevices(conf.Unifi.UCDevicesURL)
//call Unifi Controller
ucAPI := UnifiNewAPI(conf.Unifi.User, conf.Unifi.Password, conf.Unifi.APIURL)
//login
ucAPI.ucLogin()
//get all Sites from Controller
sites, err := ucAPI.ucGetSites()
if err != nil {
log.Fatalln(err)
}
//get all devices in all sites
devices, err := ucAPI.ucGetDevices(sites)
if err != nil {
log.Fatalln(err)
}
//build nodes struct
//mvJson, err := getMeshviewerJSON()
for _, jsonDevice := range d.Devices {
var currentDevice ucDevice
var currentJSONDevice device
for _, device := range devices {
if strings.ToUpper(device.Mac) == strings.ToUpper(jsonDevice.MAC) {
currentDevice = device
currentJSONDevice = jsonDevice
}
}
if isRemoteMACpublished(jsonDevice.MAC, d.Devices) {
//hier muss gecheckt werden ob der link valide ist
if checkMeshviewerLink(jsonDevice.LinkedTo) {
links = UnifiAddLink(jsonDevice, links)
}
}
load, err := strconv.ParseFloat(currentDevice.Sysstats.CPU, 64)
if err != nil {
fmt.Println("Error: ", currentDevice.Name)
//log.Fatalln(err)
load = 0
}
mem, err := strconv.ParseFloat(currentDevice.Sysstats.Memory, 64)
if err != nil {
//log.Fatalln(err)
load = 0
}
var model = lookupModels(currentDevice.Model)
var clients = currentDevice.Users
if conf.Unifi.DisplayUsers == false {
clients = 0
}
nodes = append(nodes, node{
Firstseen: "0",
Lastseen: time.Unix(int64(currentDevice.LastSeen), 0).Format(iso8601),
IsOnline: itob(currentDevice.State),
IsGateway: false,
Clients: clients,
ClientsWifi24: 0,
ClientsWifi5: 0,
ClientsOther: clients,
RootFSUsage: 0,
LoadAVG: load / 100,
MemoryUsage: mem / 100,
Uptime: time.Now().Add(-1 * time.Second * time.Duration(currentDevice.Uptime)).Format(iso8601),
GatewayNexthop: currentJSONDevice.GatewayNexthop,
Gateway: currentJSONDevice.Gateway,
Location: &currentJSONDevice.Location,
NodeID: strings.ReplaceAll(currentDevice.Mac, ":", ""),
MAC: currentDevice.Mac,
Adresses: []string{currentDevice.IP},
Domain: currentJSONDevice.Domain,
Hostname: "[Unifi] " + currentDevice.Name,
Owner: "Freifunk Rhein-Sieg",
Firmware: firmware{
Base: "Ubiquiti - Stock",
Release: currentDevice.Version,
},
Autoupdater: autoupdater{
Enabled: false,
Branch: "stable",
},
NProc: 1,
Model: model,
})
}
return nodes, links
}
func UnifiNewAPI(user string, pass string, baseURL string) UnifiAPIData {
return UnifiAPIData{
user: user,
pass: pass,
baseURL: baseURL,
client: httpClient(),
}
}
func (u *UnifiAPIData) ucCallAPI(url string, method string, body *bytes.Buffer, output interface{}) error {
req, err := http.NewRequest(method, u.baseURL+url, body)
if err != nil {
return fmt.Errorf("can't set request %s", u.baseURL+url)
}
req.Header.Set("Content-Type", "application/json")
response, err := u.client.Do(req)
if err != nil {
return fmt.Errorf("can't login %s", u.baseURL+url)
}
defer response.Body.Close()
if response.StatusCode != 200 {
return fmt.Errorf("Login failed %s", u.baseURL+url)
}
data, err := ioutil.ReadAll(response.Body)
if err != nil {
return err
}
err = json.Unmarshal(data, &output)
if err != nil {
return err
}
return nil
}
func (u *UnifiAPIData) ucLogin() error {
var loginData = []byte(`{"username":"` + u.user + `","password":"` + u.pass + `"}`)
url := "/api/login"
err := u.ucCallAPI(url, http.MethodPost, bytes.NewBuffer(loginData), nil)
if err != nil {
return err
}
return nil
}
func (u *UnifiAPIData) ucGetSites() ([]ucSite, error) {
var d struct {
Data []ucSite `json:"data"`
}
url := "/api/self/sites"
err := u.ucCallAPI(url, http.MethodGet, bytes.NewBuffer([]byte{}), &d)
if err != nil {
return []ucSite{}, err
}
return d.Data, nil
}
func (u *UnifiAPIData) ucGetDevices(sites []ucSite) ([]ucDevice, error) {
var d struct {
Data []ucDevice `json:"data"`
}
var s []ucDevice
for _, site := range sites {
url := "/api/s/" + site.ID + "/stat/device"
u.ucCallAPI(url, http.MethodGet, bytes.NewBuffer([]byte{}), &d)
s = append(s, d.Data...)
}
return s, nil
}
func UnifiAddLink(dev device, links []link) []link {
for i := range links {
if links[i].SourceAddr == dev.MAC {
// link already exists
return links
}
}
if dev.LinkedTo == "" {
//no LinkedTo in ucDevices.json
return links
}
links = append(links, link{
Type: "cable",
Source: strings.ReplaceAll(dev.MAC, ":", ""),
Target: strings.ReplaceAll(dev.GatewayNexthop, ":", ""),
SourceTQ: 1,
TargetTQ: 1,
SourceAddr: dev.MAC,
TargetAddr: dev.LinkedTo,
})
return links
}
func findNodeID(NodeID string) bool {
for i := range ucDev.Devices {
if ucDev.Devices[i].GatewayNexthop == NodeID {
return true
}
}
return false
}