removed all panic(err) calls, added meaningful error messages, added checks for returning statuscodes from API

This commit is contained in:
Nils Stinnesbeck 2020-12-31 12:20:58 +01:00
parent b293cbd66b
commit 68a8a2ff37
Signed by: nils
GPG Key ID: 86D4882C6C6CA48B
3 changed files with 59 additions and 32 deletions

View File

@ -1,9 +1,9 @@
{ {
"timestamp": "2020-12-29T18:46:27+0100", "timestamp": "2020-12-31T12:19:04+0100",
"nodes": [ "nodes": [
{ {
"firstseen": "2020-01-20T17:38:03+0000", "firstseen": "2020-01-20T17:38:03+0000",
"lastseen": "2020-12-29T17:46:00+0000", "lastseen": "2020-12-31T11:18:07+0000",
"is_online": true, "is_online": true,
"is_gateway": false, "is_gateway": false,
"clients": 0, "clients": 0,
@ -11,9 +11,9 @@
"clients_wifi5": 0, "clients_wifi5": 0,
"clients_other": 0, "clients_other": 0,
"rootfs_usage": 0, "rootfs_usage": 0,
"loadavg": 0.03, "loadavg": 0.26,
"memory_usage": 0.66, "memory_usage": 0.67,
"uptime": "2020-11-22T14:02:11+0000", "uptime": "2020-11-22T14:02:12+0000",
"gateway_nexthop": "18e8292f7de6", "gateway_nexthop": "18e8292f7de6",
"gateway": "a28cae6ff604", "gateway": "a28cae6ff604",
"location": { "location": {
@ -41,7 +41,7 @@
}, },
{ {
"firstseen": "2020-05-05T20:08:20+0000", "firstseen": "2020-05-05T20:08:20+0000",
"lastseen": "2020-12-29T17:46:08+0000", "lastseen": "2020-12-31T11:18:26+0000",
"is_online": true, "is_online": true,
"is_gateway": false, "is_gateway": false,
"clients": 0, "clients": 0,
@ -49,9 +49,9 @@
"clients_wifi5": 0, "clients_wifi5": 0,
"clients_other": 0, "clients_other": 0,
"rootfs_usage": 0, "rootfs_usage": 0,
"loadavg": 0.02, "loadavg": 0.25,
"memory_usage": 0.68, "memory_usage": 0.68,
"uptime": "2020-10-24T21:47:31+0000", "uptime": "2020-10-24T21:47:32+0000",
"gateway_nexthop": "18e8292f7de6", "gateway_nexthop": "18e8292f7de6",
"gateway": "a28cae6ff604", "gateway": "a28cae6ff604",
"location": { "location": {
@ -83,8 +83,8 @@
"type": "wifi", "type": "wifi",
"source": "18e8298ec64d", "source": "18e8298ec64d",
"target": "18e829dcc37e", "target": "18e829dcc37e",
"source_tq": 0.315, "source_tq": 0.345,
"target_tq": 0.315, "target_tq": 0.345,
"source_addr": "18:e8:29:8e:c6:4d", "source_addr": "18:e8:29:8e:c6:4d",
"target_addr": "18:e8:29:dc:c3:7e" "target_addr": "18:e8:29:dc:c3:7e"
} }

65
main.go
View File

@ -2,7 +2,9 @@ package main
import ( import (
"encoding/json" "encoding/json"
"errors"
"flag" "flag"
"fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"net/http" "net/http"
@ -27,19 +29,27 @@ func main() {
// check if token is set // check if token is set
if *token == "" { if *token == "" {
log.Println("Please specify an API token via the flag '-token'") log.Fatalln("Please specify an API token via the flag '-token'")
os.Exit(1)
} }
log.Println("starting...")
// Variables for runtime // Variables for runtime
var links []link var links []link
var nodes []node var nodes []node
d := getDevices() d, err := getDevices()
if err != nil {
log.Fatalln(err)
}
// API CALL 1 // API CALL 1
log.Println("calling API 1")
var u []unifiAPIResponse var u []unifiAPIResponse
callUnifiAPI("/devices", &u) err = callUnifiAPI("/devices", &u)
if err != nil {
log.Fatalln(err)
}
for i := range d.Devices { for i := range d.Devices {
var dev unifiAPIResponse var dev unifiAPIResponse
@ -51,26 +61,23 @@ func main() {
} }
} }
// fmt.Println(time.Now().Format(iso8601))
var isOnline bool = false var isOnline bool = false
if dev.Overview.Status == "active" { if dev.Overview.Status == "active" {
isOnline = true isOnline = true
} }
// uptime := dev.Identification.Started.Format(iso8601)
// nodeID := strings.ReplaceAll(dev.Identification.MAC, ":", "")
// END OF API CALL 1 // END OF API CALL 1
// API CALL 2 // API CALL 2
log.Println("calling API 2 for device", d.Devices[i].Name)
var details unifiAPIDetails var details unifiAPIDetails
callUnifiAPI("/devices/erouters/"+dev.Identification.ID, &details) callUnifiAPI("/devices/erouters/"+dev.Identification.ID, &details)
// END OF API CALL 2 // END OF API CALL 2
// API CALL 3 // API CALL 3
log.Println("calling API 3 for device", d.Devices[i].Name)
var airmaxes []unifiAPIAirmax var airmaxes []unifiAPIAirmax
callUnifiAPI("/devices/airmaxes/"+dev.Identification.ID+"/stations", &airmaxes) callUnifiAPI("/devices/airmaxes/"+dev.Identification.ID+"/stations", &airmaxes)
// check if remote mac address is part of our published network // check if remote mac address is part of our published network
// if isRemoteMACpublished()
for i := range airmaxes { for i := range airmaxes {
if isRemoteMACpublished(airmaxes[i].DeviceIdentification.MAC, d.Devices) == true { if isRemoteMACpublished(airmaxes[i].DeviceIdentification.MAC, d.Devices) == true {
links = addLink(dev, airmaxes[i], links) links = addLink(dev, airmaxes[i], links)
@ -89,8 +96,8 @@ func main() {
ClientsWifi5: 0, ClientsWifi5: 0,
ClientsOther: 0, ClientsOther: 0,
RootFSUsage: 0, RootFSUsage: 0,
LoadAVG: details.Overview.CPU/100, LoadAVG: details.Overview.CPU / 100,
MemoryUsage: details.Overview.RAM/100, MemoryUsage: details.Overview.RAM / 100,
Uptime: dev.Identification.Started.Format(iso8601), Uptime: dev.Identification.Started.Format(iso8601),
GatewayNexthop: currentDevice.GatewayNexthop, GatewayNexthop: currentDevice.GatewayNexthop,
Gateway: currentDevice.Gateway, Gateway: currentDevice.Gateway,
@ -122,14 +129,18 @@ func main() {
} }
// create file output // create file output
log.Println("writing json file")
writeJSONtoFile(o) writeJSONtoFile(o)
// we're done here
log.Println("...done")
} }
func getDevices() devices { func getDevices() (devices, error) {
// get devices from JSON file // get devices from JSON file
jsonFile, err := os.Open("devices.json") jsonFile, err := os.Open("devices.json")
if err != nil { if err != nil {
panic(err) return devices{}, errors.New("can't open devices.json")
} }
defer jsonFile.Close() defer jsonFile.Close()
@ -140,28 +151,37 @@ func getDevices() devices {
var d devices var d devices
// unmarshal to struct // unmarshal to struct
json.Unmarshal(byteValue, &d) json.Unmarshal(byteValue, &d)
return d return d, nil
} }
func callUnifiAPI(url string, i interface{}) { func callUnifiAPI(url string, i interface{}) error {
request, err := http.NewRequest(http.MethodGet, baseURL+url, nil) request, err := http.NewRequest(http.MethodGet, baseURL+url, nil)
if err != nil { if err != nil {
panic(err) return errors.New(fmt.Sprint("can't set request", baseURL+url))
} }
request.Header.Set("x-auth-token", *token) request.Header.Set("x-auth-token", *token)
client := &http.Client{} client := &http.Client{}
response, err := client.Do(request) response, err := client.Do(request)
if err != nil { if err != nil {
panic(err) return fmt.Errorf("can't get request %s with x-auth-token %s", baseURL+url, *token)
} }
data, err := ioutil.ReadAll(response.Body) data, err := ioutil.ReadAll(response.Body)
defer response.Body.Close()
if err != nil { if err != nil {
panic(err) return fmt.Errorf("can't read response body: %+v", response.Body)
} }
// fmt.Println(string(data)) // try to fetch errors
var a apiResponse
json.Unmarshal(data, &a)
if a.StatusCode != 0 {
return fmt.Errorf("got following errorcode from API: %d %s %s", a.StatusCode, a.Error, a.Message)
}
// no error occurred, unmarshal to struct
json.Unmarshal(data, &i) json.Unmarshal(data, &i)
return nil
} }
func isRemoteMACpublished(mac string, devices []device) bool { func isRemoteMACpublished(mac string, devices []device) bool {
@ -192,17 +212,18 @@ func addLink(dev unifiAPIResponse, airmaxes unifiAPIAirmax, links []link) []link
return links return links
} }
func writeJSONtoFile(o output) { func writeJSONtoFile(o output) error {
file, err := json.MarshalIndent(o, "", " ") file, err := json.MarshalIndent(o, "", " ")
if err != nil { if err != nil {
panic(err) return fmt.Errorf("can't marshal to json: %+v", o)
} }
// write to file // write to file
err = ioutil.WriteFile("example.json", file, 0644) err = ioutil.WriteFile("example.json", file, 0644)
if err != nil { if err != nil {
panic(err) return fmt.Errorf("can't write to json file example.json")
} }
return nil
} }
func getAddresses(ip string) []string { func getAddresses(ip string) []string {

View File

@ -110,3 +110,9 @@ type output struct {
Nodes []node `json:"nodes"` Nodes []node `json:"nodes"`
Links []link `json:"links"` Links []link `json:"links"`
} }
type apiResponse struct {
StatusCode int `json:"statusCode"`
Error string `json:"error"`
Message string `json:"message"`
}