Compare commits

...

2 Commits

Author SHA1 Message Date
c8c7c9e938
Error Handling
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-14 11:44:20 +02:00
21157e5fb4
Readme angepasst 2023-05-14 11:44:11 +02:00
5 changed files with 105 additions and 56 deletions

View File

@ -1,12 +1,17 @@
# Freifunk Meshviewer Unifi Access Points und Richtfunkstrecken import # Freifunk Meshviewer Unifi Access Points und Richtfunkstrecken import
Dieses tool Importiert Nodes für die Freifunk Map aus den APIs UNMS (Richtfunk) & Unifi (Access Points) Dieses tool Importiert Nodes für die Freifunk Map aus den APIs UISP (Richtfunk) & Unifi (Access Points).
Ebenfalls ist der Import statischer devices möglich. Da diese alle in unerem Proxmox cluster laufen, werden Statistikdaten aus der Proxmox InfluxDB geholt.
Alle Config dateien müssen per http erreichbar sein (z.B. in einem Git)
Für Troisdorf werden diese Dateien hier gepflegt: https://git.freifunk-rhein-sieg.net/Freifunk-Troisdorf/ubnt-api-devices
Für die Rhein-Sieg-Map hier: https://git.freifunk-rhein-sieg.net/Freifunk-Rhein-Sieg/ubnt-api-devices
## Config ## Config
### Unifi Access Points (ucDevices.json) ### Unifi Access Points (unifi_devices.json)
In der Datei ucDevices.json können die Access Points gepflegt werden, die auf der Freifunk Map erscheinen sollen. In der Datei unifi_devices.json können die Access Points gepflegt werden, die auf der Freifunk Map erscheinen sollen.
Hierzu muss die Datei im json Format erweitert werden. Hierzu muss die Datei im json Format erweitert werden.
@ -32,9 +37,9 @@ Erklärung:
* linked_to: (Optional) Die MAC Adresse des Routers an dem der AP angeschlossen ist. Normalerweise gateway_nexthop mit Doppelpunkten. Wenn nicht gesetzt wird kein Link auf der Map angezeigt. * linked_to: (Optional) Die MAC Adresse des Routers an dem der AP angeschlossen ist. Normalerweise gateway_nexthop mit Doppelpunkten. Wenn nicht gesetzt wird kein Link auf der Map angezeigt.
* domain: Die Domain in der sich der AP befindet. (tdf, inn, flu) * domain: Die Domain in der sich der AP befindet. (tdf, inn, flu)
### UNMS Richtfunkstrecken ### UISP Richtfunkstrecken
In der Datei devices.json können die Richtfunkstrecken gepflegt werden, die auf der Freifunk Map erscheinen sollen. In der Datei rifu_devices.json können die Richtfunkstrecken gepflegt werden, die auf der Freifunk Map erscheinen sollen.
```json ```json
{ {
@ -56,11 +61,44 @@ Erklärung:
* gateway: Im Normalfall die NodeID des Supernodes (zu finden in der MAP) * gateway: Im Normalfall die NodeID des Supernodes (zu finden in der MAP)
* domain: Die Domain in der sich der AP befindet. (tdf, inn, flu) * domain: Die Domain in der sich der AP befindet. (tdf, inn, flu)
### UISP Router
In dieser datei werden die Router (meist ER-X) gepflegt. Diese Daten werden dann ebenfalls aus der UISP API Importiert.
```json
{
"name": "Rathaus Uplink",
"mac": "18:e8:29:ad:9a:34",
"gateway_nexthop": "18e8292f7de6",
"gateway": "a28cae6ff604",
"domain": "tdf",
"location": {
"longitude":7.149406208,
"latitude":50.817093402
}
},
```
### Gateways.json
Hier werden Statische Geräte eingetragen die auf dem Proxmox Cluster laufen.
```json
{
"name": "VPN01",
"fqdn": "vpn01.fftdf.de",
"mac": "00:00:00:00:00:01",
"domain": "VPN1",
"adresses": ["5.9.220.114"]
},
```
### Config.json ### Config.json
Es gibt 3 Module die Ein/Ausgeschatet werden können: Es gibt 3 Module die Ein/Ausgeschatet werden können:
* UNMS * UNMS
* Unifi * Unifi
* Meshviewer * Meshviewer
* Gateways
Die Funktion Meshviewer importiert die vorhandenen meshviewer.json und manipuliert dort die Userzahlen. Sobald ein Access Point einen Node aus einer Meshviwer.json als "gateway_nexthop" eingetragen hat, werden die Clients an dem verbundenen Access Point und nicht mehr am Offloader angezeigt. Die Funktion Meshviewer importiert die vorhandenen meshviewer.json und manipuliert dort die Userzahlen. Sobald ein Access Point einen Node aus einer Meshviwer.json als "gateway_nexthop" eingetragen hat, werden die Clients an dem verbundenen Access Point und nicht mehr am Offloader angezeigt.

48
main.go
View File

@ -38,12 +38,12 @@ func main() {
// start API processing (runs in a loop) // start API processing (runs in a loop)
go func() { go func() {
if err := processAPIs(); err != nil { if err := processAPIs(); err != nil {
log.Fatalln("API processing failed, error is", err) log.Fatalln("API processing failed, error is: ", err)
} }
tick := time.Tick(delay) tick := time.Tick(delay)
for range tick { for range tick {
if err := processAPIs(); err != nil { if err := processAPIs(); err != nil {
log.Fatalln("API processing failed, error is", err) log.Fatalln("API processing failed, error is: ", err)
} }
} }
}() }()
@ -51,29 +51,16 @@ func main() {
serveJSON() serveJSON()
} }
func loadconfig(file string) config {
var config config
configFile, err := os.Open(file)
if err != nil {
log.Fatalln(err)
}
jsonParse := json.NewDecoder(configFile)
jsonParse.Decode(&config)
return config
}
// int to bool converter
func itob(i int) bool {
return i == 1
}
func processAPIs() error { func processAPIs() error {
var nodes []node var nodes []node
var links []link var links []link
if conf.Unms.Enabled { if conf.Unms.Enabled {
log.Println("Processing UNMS") log.Println("Processing UNMS")
unmsNodes, unmsLinks := processUNMSAPI() unmsNodes, unmsLinks, err := processUNMSAPI()
if err != nil {
return err
}
unmsRouters, err := processUNMSAPIRouter() unmsRouters, err := processUNMSAPIRouter()
if err != nil { if err != nil {
return err return err
@ -84,7 +71,10 @@ func processAPIs() error {
} }
if conf.Unifi.Enabled { if conf.Unifi.Enabled {
log.Println("Processing Unifi") log.Println("Processing Unifi")
ucNodes, _ := processUcAPIs() ucNodes, _, err := processUcAPIs()
if err != nil {
return err
}
nodes = append(nodes, ucNodes...) nodes = append(nodes, ucNodes...)
} }
if conf.Meshviewer.Enabled { if conf.Meshviewer.Enabled {
@ -122,6 +112,24 @@ func processAPIs() error {
return nil return nil
} }
func loadconfig(file string) config {
var config config
configFile, err := os.Open(file)
if err != nil {
log.Fatalln("Failed loding Config file: ", err)
}
jsonParse := json.NewDecoder(configFile)
if err := jsonParse.Decode(&config); err != nil {
log.Fatalln(err)
}
return config
}
// int to bool converter
func itob(i int) bool {
return i == 1
}
// function to get file from meshviewer // function to get file from meshviewer
func getFile(url string) []byte { func getFile(url string) []byte {
resp, err := http.Get(url) resp, err := http.Get(url)

View File

@ -133,7 +133,6 @@ func getMeshviewer() ([]node, []link) {
var links []link var links []link
for i := range conf.Meshviewer.Files { for i := range conf.Meshviewer.Files {
log.Println("Hole Meshviewer JSON von: ", conf.Meshviewer.Files[i].URL)
m, err := getMeshviewerJSON(conf.Meshviewer.Files[i].URL) m, err := getMeshviewerJSON(conf.Meshviewer.Files[i].URL)
if err != nil { if err != nil {
return nodes, links return nodes, links

View File

@ -13,7 +13,7 @@ import (
) )
// Unifi Controller API processing // Unifi Controller API processing
func processUcAPIs() ([]node, []link) { func processUcAPIs() ([]node, []link, error) {
//get list of Unifi devices to display //get list of Unifi devices to display
var nodes []node var nodes []node
var links []link var links []link
@ -22,16 +22,18 @@ func processUcAPIs() ([]node, []link) {
//call Unifi Controller //call Unifi Controller
ucAPI := UnifiNewAPI(conf.Unifi.User, conf.Unifi.Password, conf.Unifi.APIURL) ucAPI := UnifiNewAPI(conf.Unifi.User, conf.Unifi.Password, conf.Unifi.APIURL)
//login //login
ucAPI.ucLogin() if err := ucAPI.ucLogin(); err != nil {
return nil, nil, err
}
//get all Sites from Controller //get all Sites from Controller
sites, err := ucAPI.ucGetSites() sites, err := ucAPI.ucGetSites()
if err != nil { if err != nil {
log.Println(err) return nil, nil, err
} }
//get all devices in all sites //get all devices in all sites
devices, err := ucAPI.ucGetDevices(sites) devices, err := ucAPI.ucGetDevices(sites)
if err != nil { if err != nil {
log.Println(err) return nil, nil, err
} }
//build nodes struct //build nodes struct
@ -39,6 +41,7 @@ func processUcAPIs() ([]node, []link) {
for _, jsonDevice := range d.Devices { for _, jsonDevice := range d.Devices {
var currentDevice ucDevice var currentDevice ucDevice
var currentJSONDevice device var currentJSONDevice device
isOnline := currentDevice.State == 1
for _, device := range devices { for _, device := range devices {
if strings.EqualFold(device.Mac, jsonDevice.MAC) { if strings.EqualFold(device.Mac, jsonDevice.MAC) {
currentDevice = device currentDevice = device
@ -53,14 +56,15 @@ func processUcAPIs() ([]node, []link) {
} }
load, err := strconv.ParseFloat(currentDevice.Sysstats.CPU, 64) load, err := strconv.ParseFloat(currentDevice.Sysstats.CPU, 64)
if err != nil { if err != nil {
fmt.Println("Error: ", currentDevice.Name) log.Println("Error psrsing CPU load from ", currentDevice.Name)
//log.Fatalln(err) log.Println(err)
load = 0 load = 0
} }
mem, err := strconv.ParseFloat(currentDevice.Sysstats.Memory, 64) mem, err := strconv.ParseFloat(currentDevice.Sysstats.Memory, 64)
if err != nil { if err != nil {
//log.Fatalln(err) log.Println("Error psrsing CPU load from ", currentDevice.Name)
load = 0 log.Println(err)
mem = 0
} }
var model = lookupModels(currentDevice.Model) var model = lookupModels(currentDevice.Model)
var clients int var clients int
@ -101,7 +105,7 @@ func processUcAPIs() ([]node, []link) {
Model: model, Model: model,
}) })
} }
return nodes, links return nodes, links, err
} }
func UnifiNewAPI(user string, pass string, baseURL string) UnifiAPIData { func UnifiNewAPI(user string, pass string, baseURL string) UnifiAPIData {

42
unms.go
View File

@ -17,19 +17,19 @@ import (
) )
// UNMS API processing (Richtfunk) // UNMS API processing (Richtfunk)
func processUNMSAPI() ([]node, []link) { func processUNMSAPI() ([]node, []link, error) {
// Variables for runtime // Variables for runtime
var links []link var links []link
var nodes []node var nodes []node
d := getDevices(conf.Unms.DevicesURL) d := getDevices(conf.Unms.DevicesURL)
// API CALL 1 // API CALL 1 (get Device overview)
log.Println("calling API 1") log.Println("Starting UISP API Crawler for Rifu devices")
log.Println("Getting device overview from UNMS API")
var u []unifiAPIResponse var u []unifiAPIResponse
err := UnmsCallAPI("/devices", &u) if err := UnmsCallAPI("/devices", &u); err != nil {
if err != nil { return nil, nil, err
log.Fatalln(err)
} }
for i := range d.Devices { for i := range d.Devices {
@ -41,20 +41,22 @@ func processUNMSAPI() ([]node, []link) {
currentDevice = d.Devices[i] currentDevice = d.Devices[i]
} }
} }
isOnline := dev.Overview.Status == "active" isOnline := dev.Overview.Status == "active"
// END OF API CALL 1 // END OF API CALL 1
// API CALL 2 // Getting details from UISP
log.Println("calling API 2 for device", d.Devices[i].Name) log.Println("Getting device details for: ", d.Devices[i].Name)
var details unifiAPIDetails var details unifiAPIDetails
UnmsCallAPI("/devices/erouters/"+dev.Identification.ID, &details) if err := UnmsCallAPI("/devices/erouters/"+dev.Identification.ID, &details); err != nil {
// END OF API CALL 2 return nil, nil, err
}
// API CALL 3 // Getting details for RiFu
log.Println("calling API 3 for device", d.Devices[i].Name) log.Println("Getting details for RiFu Link for: ", d.Devices[i].Name)
var airmaxes []unifiAPIAirmax var airmaxes []unifiAPIAirmax
UnmsCallAPI("/devices/airmaxes/"+dev.Identification.ID+"/stations", &airmaxes) if err := UnmsCallAPI("/devices/airmaxes/"+dev.Identification.ID+"/stations", &airmaxes); err != nil {
return nil, nil, err
}
// check if remote mac address is part of our published network // check if remote mac address is part of our published network
for i := range airmaxes { for i := range airmaxes {
if isRemoteMACpublished(airmaxes[i].DeviceIdentification.MAC, d.Devices) { if isRemoteMACpublished(airmaxes[i].DeviceIdentification.MAC, d.Devices) {
@ -98,7 +100,7 @@ func processUNMSAPI() ([]node, []link) {
Model: details.Identification.Model, Model: details.Identification.Model,
}) })
} }
return nodes, links return nodes, links, nil
} }
func processUNMSAPIRouter() ([]node, error) { func processUNMSAPIRouter() ([]node, error) {
@ -107,13 +109,11 @@ func processUNMSAPIRouter() ([]node, error) {
d := getDevices(conf.Unms.RouterURL) d := getDevices(conf.Unms.RouterURL)
// API CALL 1, get all devices list from UNMS // API CALL 1, get all devices list from UNMS
log.Println("Get all devices from UNMS") log.Println("Get all Routers from UISP")
var u []unifiAPIResponse var u []unifiAPIResponse
err := UnmsCallAPI("/devices", &u) if err := UnmsCallAPI("/devices", &u); err != nil {
if err != nil {
return nil, err return nil, err
} }
// END OF API CALL 1
// Get Information for devices device // Get Information for devices device
for i := range d.Devices { for i := range d.Devices {
@ -129,14 +129,14 @@ func processUNMSAPIRouter() ([]node, error) {
isOnline := dev.Overview.Status == "active" isOnline := dev.Overview.Status == "active"
// API CALL FOR ROUTER DETAILS (Interface RX/TX) // API CALL FOR ROUTER DETAILS (Interface RX/TX)
log.Println("Getting details of ", d.Devices[i].Name, "from UNMS API") log.Println("Getting details of ", d.Devices[i].Name, "from UISP API")
var details unifiAPIDetails var details unifiAPIDetails
if err := UnmsCallAPI("/devices/erouters/"+dev.Identification.ID, &details); err != nil { if err := UnmsCallAPI("/devices/erouters/"+dev.Identification.ID, &details); err != nil {
return nil, err return nil, err
} }
// API CALL FOR DEVICE STATISTICS (CPU, RAM) // API CALL FOR DEVICE STATISTICS (CPU, RAM)
log.Println("Getting statistics of ", d.Devices[i].Name, "from UNMS API") log.Println("Getting statistics of ", d.Devices[i].Name, "from UISP API")
var statistics UNMSstatistics var statistics UNMSstatistics
if err := UnmsCallAPI("/devices/"+dev.Identification.ID+"/statistics?interval=hour", &statistics); err != nil { if err := UnmsCallAPI("/devices/"+dev.Identification.ID+"/statistics?interval=hour", &statistics); err != nil {
return nil, err return nil, err