package main import ( "encoding/json" "errors" "fmt" "io/ioutil" "log" "net/http" "strconv" "strings" "time" _ "github.com/fatih/structs" //_ "github.com/influxdata/influxdb1-client" // this is important because of the bug in go mod client "github.com/influxdata/influxdb1-client/v2" ) // UNMS API processing (Richtfunk) func processUNMSAPI() ([]node, []link) { // Variables for runtime var links []link var nodes []node d := getDevices(conf.Unms.DevicesURL) // API CALL 1 log.Println("calling API 1") var u []unifiAPIResponse err := UnmsCallAPI("/devices", &u) if err != nil { log.Fatalln(err) } for i := range d.Devices { var dev unifiAPIResponse var currentDevice device for j := range u { if strings.ToUpper(u[j].Identification.MAC) == strings.ToUpper(d.Devices[i].MAC) { dev = u[j] currentDevice = d.Devices[i] } } var isOnline bool = false if dev.Overview.Status == "active" { isOnline = true } // END OF API CALL 1 // API CALL 2 log.Println("calling API 2 for device", d.Devices[i].Name) var details unifiAPIDetails UnmsCallAPI("/devices/erouters/"+dev.Identification.ID, &details) // END OF API CALL 2 // API CALL 3 log.Println("calling API 3 for device", d.Devices[i].Name) var airmaxes []unifiAPIAirmax UnmsCallAPI("/devices/airmaxes/"+dev.Identification.ID+"/stations", &airmaxes) // check if remote mac address is part of our published network for i := range airmaxes { if isRemoteMACpublished(airmaxes[i].DeviceIdentification.MAC, d.Devices) { links = UnmsAddLink(dev, airmaxes[i], links) } } // END OF API CALL 3 // Get info from json file (static) nodes = append(nodes, node{ Firstseen: dev.Overview.CreatedAt.Format(iso8601), Lastseen: dev.Overview.LastSeen.Format(iso8601), IsOnline: isOnline, IsGateway: false, Clients: 0, ClientsWifi24: 0, ClientsWifi5: 0, ClientsOther: 0, RootFSUsage: 0, LoadAVG: details.Overview.CPU / 100, MemoryUsage: details.Overview.RAM / 100, Uptime: dev.Identification.Started.Format(iso8601), GatewayNexthop: currentDevice.GatewayNexthop, Gateway: currentDevice.Gateway, Location: ¤tDevice.Location, NodeID: strings.ReplaceAll(dev.Identification.MAC, ":", ""), MAC: dev.Identification.MAC, Adresses: UnmsGetAddresses(details.IPAddress), Domain: currentDevice.Domain, Hostname: "[RiFu] " + details.Identification.Name, Owner: "Freifunk Rhein-Sieg", Firmware: firmware{ Base: "Ubiquiti - Stock", Release: details.Firmware.Current, }, Autoupdater: autoupdater{ Enabled: false, Branch: "stable", }, NProc: 1, Model: details.Identification.Model, }) } return nodes, links } func processUNMSAPIRouter() []node { // Variables for runtime var nodes []node d := getDevices(conf.Unms.RouterURL) // API CALL 1 log.Println("calling API 1") var u []unifiAPIResponse err := UnmsCallAPI("/devices", &u) if err != nil { log.Fatalln(err) } for i := range d.Devices { var dev unifiAPIResponse var currentDevice device for j := range u { if strings.ToUpper(u[j].Identification.MAC) == strings.ToUpper(d.Devices[i].MAC) { dev = u[j] currentDevice = d.Devices[i] } } var isOnline bool = false if dev.Overview.Status == "active" { isOnline = true } // END OF API CALL 1 // API CALL 2 log.Println("calling API 2 for device", d.Devices[i].Name) var details unifiAPIDetails UnmsCallAPI("/devices/erouters/"+dev.Identification.ID, &details) // END OF API CALL 2 // API CALL 3 STATISTICS! bp, err := client.NewBatchPoints(client.BatchPointsConfig{ Database: "freifunk", Precision: "s", }) if err != nil { log.Fatalln("Error: ", err) } for i := range d.Devices { log.Println("calling API 3 for device", d.Devices[i].Name) var statistics UNMSstatistics UnmsCallAPI("/devices/"+dev.Identification.ID+"/statistics?interval=hour", &statistics) for t := range statistics.CPU { if t > 9 { break } tags := map[string]string{ "hostname": d.Devices[i].Name, "nodeid": strings.ReplaceAll(dev.Identification.MAC, ":", ""), } fields := map[string]interface{}{ "cpu": statistics.CPU[t].Y, "ram": statistics.RAM[t].Y, //hier fehlen noch die interfaces } slice := strconv.Itoa(statistics.CPU[t].X) timeunix, err := strconv.Atoi(slice[:10]) if err != nil { log.Fatalln("Error: ", err) } tm := time.Unix(int64(timeunix), 0) time_local := tm.Add(1 * time.Hour) point, err := client.NewPoint( "node", tags, fields, time_local, ) if err != nil { log.Fatalln("Error: ", err) } bp.AddPoint(point) c := influxDBClient() err = c.Write(bp) if err != nil { log.Fatal(err) } } // ab hier Interfaces for i := range d.Devices { log.Println("calling API 3 for device", d.Devices[i].Name) var statistics UNMSstatistics UnmsCallAPI("/devices/"+dev.Identification.ID+"/statistics?interval=hour", &statistics) for eth := range statistics.Interfaces { for t := range statistics.Interfaces[eth].Transmit { if t > 9 { break } tags := map[string]string{ "hostname": d.Devices[i].Name, "nodeid": strings.ReplaceAll(dev.Identification.MAC, ":", ""), } interface_name_rx := ("traffic.rx.bytes" + "_" + statistics.Interfaces[eth].ID) interface_name_tx := ("traffic.tx.bytes" + "_" + statistics.Interfaces[eth].ID) if statistics.Interfaces[eth].ID == "eth0" { interface_name_rx = "traffic.rx.bytes" interface_name_tx = "traffic.tx.bytes" } fields := map[string]interface{}{ interface_name_rx: statistics.Interfaces[eth].Receive[t].Y * 100, interface_name_tx: statistics.Interfaces[eth].Transmit[t].Y * 100, } slice := strconv.Itoa(statistics.CPU[t].X) timeunix, err := strconv.Atoi(slice[:10]) if err != nil { log.Fatalln("Error: ", err) } tm := time.Unix(int64(timeunix), 0) time_local := tm.Add(1 * time.Hour) point, err := client.NewPoint( "node", tags, fields, time_local, ) if err != nil { log.Fatalln("Error: ", err) } bp.AddPoint(point) c := influxDBClient() err = c.Write(bp) if err != nil { log.Fatal(err) } } } } } // END OF API CALL 3 // Get info from json file (static) nodes = append(nodes, node{ Firstseen: dev.Overview.CreatedAt.Format(iso8601), Lastseen: dev.Overview.LastSeen.Format(iso8601), IsOnline: isOnline, IsGateway: false, Clients: 0, ClientsWifi24: 0, ClientsWifi5: 0, ClientsOther: 0, RootFSUsage: 0, LoadAVG: details.Overview.CPU / 100, MemoryUsage: details.Overview.RAM / 100, Uptime: dev.Identification.Started.Format(iso8601), GatewayNexthop: currentDevice.GatewayNexthop, Gateway: currentDevice.Gateway, Location: ¤tDevice.Location, NodeID: strings.ReplaceAll(dev.Identification.MAC, ":", ""), MAC: dev.Identification.MAC, Adresses: UnmsGetAddresses(details.IPAddress), Domain: currentDevice.Domain, Hostname: "[RiFu] " + details.Identification.Name, Owner: "Freifunk Rhein-Sieg", Firmware: firmware{ Base: "Ubiquiti - Stock", Release: details.Firmware.Current, }, Autoupdater: autoupdater{ Enabled: false, Branch: "stable", }, NProc: 1, Model: details.Identification.Model, }) } return nodes } func influxDBClient() client.Client { c, err := client.NewHTTPClient(client.HTTPConfig{ Addr: "http://statistik.freifunk-troisdorf.de:8886", }) if err != nil { log.Fatalln("Error: ", err) } return c } func UnmsCallAPI(url string, i interface{}) 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)) } request.Header.Set("x-auth-token", conf.Unms.APItoken) client := &http.Client{} response, err := client.Do(request) if err != nil { 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) } data, err := ioutil.ReadAll(response.Body) defer response.Body.Close() if err != nil { return fmt.Errorf("can't read response body: %+v", response.Body) } // no error occurred, unmarshal to struct json.Unmarshal(data, &i) return nil } func UnmsGetAddresses(ip string) []string { var adresses []string adresses = append(adresses, strings.Split(ip, "/")[0]) return adresses } func UnmsAddLink(dev unifiAPIResponse, airmaxes unifiAPIAirmax, links []link) []link { for i := range links { if links[i].SourceAddr == airmaxes.DeviceIdentification.MAC { // link already exists return links } } links = append(links, link{ Type: "wifi", Source: strings.ReplaceAll(dev.Identification.MAC, ":", ""), Target: strings.ReplaceAll(airmaxes.DeviceIdentification.MAC, ":", ""), SourceTQ: airmaxes.Statistics.LinkScore, TargetTQ: airmaxes.Statistics.LinkScore, SourceAddr: dev.Identification.MAC, TargetAddr: airmaxes.DeviceIdentification.MAC, }) return links }