Check if device is online for statistics processing
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Stefan Hoffmann 2023-04-28 16:47:15 +02:00
parent 16dd56e320
commit 22c935ce2a
Signed by: stefan
GPG Key ID: 8EFC7042BF8D5CDD
6 changed files with 115 additions and 106 deletions

View File

@ -1,14 +1,14 @@
{
"unms": {
"enabled": false,
"unmsAPIUrl": "https://unifi.freifunk-troisdorf.de/v2.1",
"unmsAPIUrl": "https://uisp.freifunk-troisdorf.de/v2.1",
"APItoken": "UNMS API TOKEN",
"devicesURL": "https://git.freifunk-rhein-sieg.net/Freifunk-Troisdorf/ubnt-freifunk-map-api/raw/branch/master/example.devices.json"
},
"unifi": {
"enabled": false,
"displayusers": true,
"APIUrl": "https://unifi.freifunk-troisdorf.de:8443",
"APIUrl": "https://unifi.freifunk-troisdorf.de",
"user": "APIuser",
"password": "PASSWORD",
"ucDevicesURL": "https://git.freifunk-rhein-sieg.net/Freifunk-Troisdorf/ubnt-freifunk-map-api/raw/branch/master/example.ucDevices.json"

10
go.mod
View File

@ -1,9 +1,17 @@
module git.freifunk-rhein-sieg.net/Freifunk-Troisdorf/ubnt-freifunk-map-api
go 1.16
go 1.20
require (
git.nils.zone/nils/prettify v0.0.4
github.com/fatih/structs v1.1.0
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
)
require (
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 // indirect
github.com/fatih/color v1.9.0 // indirect
github.com/mattn/go-colorable v0.1.4 // indirect
github.com/mattn/go-isatty v0.0.11 // indirect
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect
)

109
main.go
View File

@ -4,7 +4,7 @@ import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"io"
"log"
"net/http"
"net/http/cookiejar"
@ -34,8 +34,19 @@ func main() {
if *configPath == "" {
log.Fatalln("Please specify path to config.json flag '-configPath'")
}
// start API processing (runs in a loop)
go processAPIs()
go func() {
if err := processAPIs(); err != nil {
log.Fatalln("API processing failed, error is", err)
}
tick := time.Tick(delay)
for range tick {
if err := processAPIs(); err != nil {
log.Fatalln("API processing failed, error is", err)
}
}
}()
//processUNMSAPIRouter()
//createMetrics(influxDBClient())
// start webserver on Port 3000
@ -55,59 +66,57 @@ func loadconfig(file string) config {
// int to bool converter
func itob(i int) bool {
if i == 1 {
return true
}
return false
return i == 1
}
func processAPIs() {
tick := time.Tick(delay)
for range tick {
var nodes []node
var links []link
func processAPIs() error {
var nodes []node
var links []link
if conf.Unms.Enabled {
log.Println("Processing UNMS")
unmsNodes, unmsLinks := processUNMSAPI()
unmsRouters := processUNMSAPIRouter()
nodes = append(nodes, unmsNodes...)
nodes = append(nodes, unmsRouters...)
links = append(links, unmsLinks...)
}
if conf.Unifi.Enabled {
log.Println("Processing Unifi")
ucNodes, _ := processUcAPIs()
nodes = append(nodes, ucNodes...)
}
if conf.Meshviewer.Enabled {
log.Println("Processing Meshviewer")
mvNodes, mvLinks := getMeshviewer()
nodes = append(nodes, mvNodes...)
links = append(links, mvLinks...)
}
// assemble final struct
o := output{
Timestamp: time.Now().Format(iso8601),
Nodes: nodes,
Links: links,
}
// create file output
log.Println("writing json file")
if err := o.writeToFile(); err != nil {
log.Fatalln(err)
}
// get outages to serve as .csv
l := getUNMSLogs()
err := writeOutagesToCSV(l)
if conf.Unms.Enabled {
log.Println("Processing UNMS")
unmsNodes, unmsLinks := processUNMSAPI()
unmsRouters, err := processUNMSAPIRouter()
if err != nil {
log.Println("Error writing outages.csv")
return err
}
// we're done here
log.Println("...done")
nodes = append(nodes, unmsNodes...)
nodes = append(nodes, unmsRouters...)
links = append(links, unmsLinks...)
}
if conf.Unifi.Enabled {
log.Println("Processing Unifi")
ucNodes, _ := processUcAPIs()
nodes = append(nodes, ucNodes...)
}
if conf.Meshviewer.Enabled {
log.Println("Processing Meshviewer")
mvNodes, mvLinks := getMeshviewer()
nodes = append(nodes, mvNodes...)
links = append(links, mvLinks...)
}
// assemble final struct
o := output{
Timestamp: time.Now().Format(iso8601),
Nodes: nodes,
Links: links,
}
// create file output
log.Println("writing json file")
if err := o.writeToFile(); err != nil {
log.Fatalln(err)
}
// get outages to serve as .csv
l := getUNMSLogs()
err := writeOutagesToCSV(l)
if err != nil {
log.Println("Error writing outages.csv")
}
// we're done here
log.Println("...done")
return nil
}
// function to get file from meshviewer
@ -117,7 +126,7 @@ func getFile(url string) []byte {
log.Println("Error getting file from:", url)
}
data := resp.Body
byteValue, _ := ioutil.ReadAll(data)
byteValue, _ := io.ReadAll(data)
return byteValue
}

View File

@ -314,40 +314,26 @@ type UNMSLogResponse struct {
} `json:"items"`
}
type XY struct {
X int `json:"x"`
Y int `json:"y"`
}
type UNMSstatistics struct {
Period int `json:"period"`
Interval struct {
Start int `json:"start"`
End int `json:"end"`
} `json:"interval"`
CPU []struct {
X int `json:"x"`
Y int `json:"y"`
} `json:"cpu"`
RAM []struct {
X int `json:"x"`
Y int `json:"y"`
} `json:"ram"`
Ping []struct {
X int `json:"x"`
Y int `json:"y"`
} `json:"ping"`
Errors []struct {
X int `json:"x"`
Y int `json:"y"`
} `json:"errors"`
CPU []XY `json:"cpu"`
RAM []XY `json:"ram"`
Errors []XY `json:"errors"`
Interfaces []struct {
ID string `json:"id"`
Priority int `json:"priority"`
Name string `json:"name"`
Receive []struct {
X int `json:"x"`
Y int `json:"y"`
} `json:"receive"`
Transmit []struct {
X int `json:"x"`
Y int `json:"y"`
} `json:"transmit"`
Receive []XY `json:"receive"`
Transmit []XY `json:"transmit"`
} `json:"interfaces"`
}

View File

@ -4,7 +4,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"io"
"log"
"net/http"
"strconv"
@ -126,10 +126,10 @@ func (u *UnifiAPIData) ucCallAPI(url string, method string, body *bytes.Buffer,
}
defer response.Body.Close()
if response.StatusCode != 200 {
return fmt.Errorf("Login failed %s", u.baseURL+url)
return fmt.Errorf("login failed %s", u.baseURL+url)
}
data, err := ioutil.ReadAll(response.Body)
data, err := io.ReadAll(response.Body)
if err != nil {
return err
}

58
unms.go
View File

@ -42,10 +42,7 @@ func processUNMSAPI() ([]node, []link) {
}
}
var isOnline bool = false
if dev.Overview.Status == "active" {
isOnline = true
}
isOnline := dev.Overview.Status == "active"
// END OF API CALL 1
// API CALL 2
@ -104,7 +101,7 @@ func processUNMSAPI() ([]node, []link) {
return nodes, links
}
func processUNMSAPIRouter() []node {
func processUNMSAPIRouter() ([]node, error) {
// Variables for runtime
var nodes []node
@ -115,7 +112,7 @@ func processUNMSAPIRouter() []node {
var u []unifiAPIResponse
err := UnmsCallAPI("/devices", &u)
if err != nil {
log.Fatalln(err)
return nil, err
}
// END OF API CALL 1
@ -130,26 +127,29 @@ func processUNMSAPIRouter() []node {
}
}
var isOnline bool = false
if dev.Overview.Status == "active" {
isOnline = true
}
isOnline := dev.Overview.Status == "active"
// API CALL FOR ROUTER DETAILS (Interface RX/TX)
log.Println("Getting details of ", d.Devices[i].Name, "from UNMS API")
var details unifiAPIDetails
UnmsCallAPI("/devices/erouters/"+dev.Identification.ID, &details)
if err := UnmsCallAPI("/devices/erouters/"+dev.Identification.ID, &details); err != nil {
return nil, err
}
// API CALL FOR DEVICE STATISTICS (CPU, RAM)
log.Println("Getting statistics of ", d.Devices[i].Name, "from UNMS API")
var statistics UNMSstatistics
UnmsCallAPI("/devices/"+dev.Identification.ID+"/statistics?interval=hour", &statistics)
if err := UnmsCallAPI("/devices/"+dev.Identification.ID+"/statistics?interval=hour", &statistics); err != nil {
return nil, err
}
// API CALL FOR DHCP LEASES
log.Println("Getting DHCP Leases of ", d.Devices[i].Name, "from UNMS API")
var dhcpleases UNMSdhcp
if isOnline {
UnmsCallAPI("/devices/erouters/"+dev.Identification.ID+"/dhcp/leases", &dhcpleases)
if err := UnmsCallAPI("/devices/erouters/"+dev.Identification.ID+"/dhcp/leases", &dhcpleases); err != nil {
return nil, err
}
} else {
log.Println("Router ist offline, skipping DHCP Leases")
}
@ -164,7 +164,8 @@ func processUNMSAPIRouter() []node {
}
//
fields := map[string]interface{}{}
// fields := map[string]interface{}{}
fields := make(map[string]any)
tags := map[string]string{
"hostname": strings.ReplaceAll(d.Devices[i].Name, " ", "-"),
"nodeid": strings.ReplaceAll(dev.Identification.MAC, ":", ""),
@ -177,15 +178,21 @@ func processUNMSAPIRouter() []node {
fields[interface_name_tx] = details.Interfaces[eth].Statistics.Txrate
}
// Generate fields for all Statistics
load := (float64(statistics.CPU[0].Y) / float64(100))
fields["cpu"] = statistics.CPU[0].Y
fields["load"] = load
fields["ram"] = statistics.RAM[0].Y
// set default values if we can't get statistics
fields["cpu"] = 0
fields["load"] = float64(0)
fields["ram"] = 0
if isOnline {
// Generate fields for all Statistics
load := (float64(statistics.CPU[0].Y) / float64(100))
fields["cpu"] = statistics.CPU[0].Y
fields["load"] = load
fields["ram"] = statistics.RAM[0].Y
}
// Generate field for DHCP Leases
leases := len(dhcpleases)
fields["clients.total"] = leases
fields["clients.total"] = len(dhcpleases)
// Generate Dataponts
point, err := client.NewPoint(
@ -240,7 +247,7 @@ func processUNMSAPIRouter() []node {
Model: details.Identification.Model,
})
}
return nodes
return nodes, nil
}
func influxDBClient() client.Client {
@ -253,7 +260,7 @@ func influxDBClient() client.Client {
return c
}
func UnmsCallAPI(url string, i interface{}) error {
func UnmsCallAPI(url string, i any) error {
request, err := http.NewRequest(http.MethodGet, conf.Unms.UnmsAPIURL+url, nil)
if err != nil {
return errors.New(fmt.Sprint("can't set request", conf.Unms.UnmsAPIURL+url))
@ -265,7 +272,7 @@ func UnmsCallAPI(url string, i interface{}) error {
return fmt.Errorf("can't get request %s with x-auth-token %s", conf.Unms.UnmsAPIURL+url, conf.Unms.APItoken)
}
if response.StatusCode != 200 {
log.Fatalln("Can´t call UNMS API, check token and URL. HTTP Status: ", response.StatusCode)
log.Fatalln("Can't call UNMS API, check token and URL. HTTP Status: ", response.StatusCode)
}
data, err := ioutil.ReadAll(response.Body)
defer response.Body.Close()
@ -273,8 +280,7 @@ func UnmsCallAPI(url string, i interface{}) error {
return fmt.Errorf("can't read response body: %+v", response.Body)
}
// no error occurred, unmarshal to struct
json.Unmarshal(data, &i)
return nil
return json.Unmarshal(data, &i)
}
func UnmsGetAddresses(ip string) []string {