Compare commits

..

No commits in common. "c8c7c9e9383ae4a173b0c0c66ac80445d3dd9b58" and "c9b496d5eb3b3982f1c1260b18a6494617a8ee39" have entirely different histories.

5 changed files with 56 additions and 105 deletions

View File

@ -1,17 +1,12 @@
# 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 UISP (Richtfunk) & Unifi (Access Points). Dieses tool Importiert Nodes für die Freifunk Map aus den APIs UNMS (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 (unifi_devices.json) ### Unifi Access Points (ucDevices.json)
In der Datei unifi_devices.json können die Access Points gepflegt werden, die auf der Freifunk Map erscheinen sollen. In der Datei ucDevices.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.
@ -37,9 +32,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)
### UISP Richtfunkstrecken ### UNMS Richtfunkstrecken
In der Datei rifu_devices.json können die Richtfunkstrecken gepflegt werden, die auf der Freifunk Map erscheinen sollen. In der Datei devices.json können die Richtfunkstrecken gepflegt werden, die auf der Freifunk Map erscheinen sollen.
```json ```json
{ {
@ -61,44 +56,11 @@ 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,16 +51,29 @@ 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, err := processUNMSAPI() unmsNodes, unmsLinks := processUNMSAPI()
if err != nil {
return err
}
unmsRouters, err := processUNMSAPIRouter() unmsRouters, err := processUNMSAPIRouter()
if err != nil { if err != nil {
return err return err
@ -71,10 +84,7 @@ func processAPIs() error {
} }
if conf.Unifi.Enabled { if conf.Unifi.Enabled {
log.Println("Processing Unifi") log.Println("Processing Unifi")
ucNodes, _, err := processUcAPIs() ucNodes, _ := processUcAPIs()
if err != nil {
return err
}
nodes = append(nodes, ucNodes...) nodes = append(nodes, ucNodes...)
} }
if conf.Meshviewer.Enabled { if conf.Meshviewer.Enabled {
@ -112,24 +122,6 @@ 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,6 +133,7 @@ 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, error) { func processUcAPIs() ([]node, []link) {
//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,18 +22,16 @@ func processUcAPIs() ([]node, []link, error) {
//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
if err := ucAPI.ucLogin(); err != nil { ucAPI.ucLogin()
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 {
return nil, nil, err log.Println(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 {
return nil, nil, err log.Println(err)
} }
//build nodes struct //build nodes struct
@ -41,7 +39,6 @@ func processUcAPIs() ([]node, []link, error) {
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
@ -56,15 +53,14 @@ func processUcAPIs() ([]node, []link, error) {
} }
load, err := strconv.ParseFloat(currentDevice.Sysstats.CPU, 64) load, err := strconv.ParseFloat(currentDevice.Sysstats.CPU, 64)
if err != nil { if err != nil {
log.Println("Error psrsing CPU load from ", currentDevice.Name) fmt.Println("Error: ", currentDevice.Name)
log.Println(err) //log.Fatalln(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.Println("Error psrsing CPU load from ", currentDevice.Name) //log.Fatalln(err)
log.Println(err) load = 0
mem = 0
} }
var model = lookupModels(currentDevice.Model) var model = lookupModels(currentDevice.Model)
var clients int var clients int
@ -105,7 +101,7 @@ func processUcAPIs() ([]node, []link, error) {
Model: model, Model: model,
}) })
} }
return nodes, links, err return nodes, links
} }
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, error) { func processUNMSAPI() ([]node, []link) {
// 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 (get Device overview) // API CALL 1
log.Println("Starting UISP API Crawler for Rifu devices") log.Println("calling API 1")
log.Println("Getting device overview from UNMS API")
var u []unifiAPIResponse var u []unifiAPIResponse
if err := UnmsCallAPI("/devices", &u); err != nil { err := UnmsCallAPI("/devices", &u)
return nil, nil, err if err != nil {
log.Fatalln(err)
} }
for i := range d.Devices { for i := range d.Devices {
@ -41,22 +41,20 @@ func processUNMSAPI() ([]node, []link, error) {
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
// Getting details from UISP // API CALL 2
log.Println("Getting device details for: ", d.Devices[i].Name) log.Println("calling API 2 for device", d.Devices[i].Name)
var details unifiAPIDetails var details unifiAPIDetails
if err := UnmsCallAPI("/devices/erouters/"+dev.Identification.ID, &details); err != nil { UnmsCallAPI("/devices/erouters/"+dev.Identification.ID, &details)
return nil, nil, err // END OF API CALL 2
}
// Getting details for RiFu // API CALL 3
log.Println("Getting details for RiFu Link for: ", d.Devices[i].Name) log.Println("calling API 3 for device", d.Devices[i].Name)
var airmaxes []unifiAPIAirmax var airmaxes []unifiAPIAirmax
if err := UnmsCallAPI("/devices/airmaxes/"+dev.Identification.ID+"/stations", &airmaxes); err != nil { UnmsCallAPI("/devices/airmaxes/"+dev.Identification.ID+"/stations", &airmaxes)
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) {
@ -100,7 +98,7 @@ func processUNMSAPI() ([]node, []link, error) {
Model: details.Identification.Model, Model: details.Identification.Model,
}) })
} }
return nodes, links, nil return nodes, links
} }
func processUNMSAPIRouter() ([]node, error) { func processUNMSAPIRouter() ([]node, error) {
@ -109,11 +107,13 @@ 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 Routers from UISP") log.Println("Get all devices from UNMS")
var u []unifiAPIResponse var u []unifiAPIResponse
if err := UnmsCallAPI("/devices", &u); err != nil { err := UnmsCallAPI("/devices", &u)
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 UISP API") log.Println("Getting details of ", d.Devices[i].Name, "from UNMS 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 UISP API") log.Println("Getting statistics of ", d.Devices[i].Name, "from UNMS 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