improve complete code with comments and co (thanks linter)
This commit is contained in:
parent
798db6a063
commit
d855248f6a
|
@ -8,9 +8,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 7 nachkommerstellen sollten genug sein (7cm genau)
|
// GEOROUND : 7 nachkommerstellen sollten genug sein (7cm genau)
|
||||||
// http://blog.3960.org/post/7309573249/genauigkeit-bei-geo-koordinaten
|
// http://blog.3960.org/post/7309573249/genauigkeit-bei-geo-koordinaten
|
||||||
|
|
||||||
const GEOROUND = 0.0000001
|
const GEOROUND = 0.0000001
|
||||||
|
|
||||||
func geoEqual(a, b float64) bool {
|
func geoEqual(a, b float64) bool {
|
||||||
|
@ -20,29 +19,33 @@ func geoEqual(a, b float64) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
type ApiAliases struct {
|
// AliasesAPI struct for API
|
||||||
|
type AliasesAPI struct {
|
||||||
aliases *models.Aliases
|
aliases *models.Aliases
|
||||||
config *models.Config
|
config *models.Config
|
||||||
nodes *models.Nodes
|
nodes *models.Nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAliases Bind to API
|
||||||
func NewAliases(config *models.Config, router *httprouter.Router, prefix string, nodes *models.Nodes) {
|
func NewAliases(config *models.Config, router *httprouter.Router, prefix string, nodes *models.Nodes) {
|
||||||
api := &ApiAliases{
|
api := &AliasesAPI{
|
||||||
aliases: models.NewAliases(config),
|
aliases: models.NewAliases(config),
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
router.GET(prefix, api.GetAll)
|
router.GET(prefix, api.GetAll)
|
||||||
router.GET(prefix+"/ansible", api.AnsibleDiff)
|
router.GET(prefix+"/ansible", api.Ansible)
|
||||||
router.GET(prefix+"/alias/:nodeid", api.GetOne)
|
router.GET(prefix+"/alias/:nodeid", api.GetOne)
|
||||||
router.POST(prefix+"/alias/:nodeid", BasicAuth(api.SaveOne, []byte(config.Webserver.Api.Passphrase)))
|
router.POST(prefix+"/alias/:nodeid", BasicAuth(api.SaveOne, []byte(config.Webserver.API.Passphrase)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *ApiAliases) GetAll(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
// GetAll request for get all aliases
|
||||||
|
func (api *AliasesAPI) GetAll(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||||
jsonOutput(w, r, api.aliases.List)
|
jsonOutput(w, r, api.aliases.List)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *ApiAliases) GetOne(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
// GetOne request for get one alias
|
||||||
|
func (api *AliasesAPI) GetOne(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
if alias := api.aliases.List[ps.ByName("nodeid")]; alias != nil {
|
if alias := api.aliases.List[ps.ByName("nodeid")]; alias != nil {
|
||||||
jsonOutput(w, r, alias)
|
jsonOutput(w, r, alias)
|
||||||
return
|
return
|
||||||
|
@ -50,7 +53,8 @@ func (api *ApiAliases) GetOne(w http.ResponseWriter, r *http.Request, ps httprou
|
||||||
fmt.Fprint(w, "Not found: ", ps.ByName("nodeid"), "\n")
|
fmt.Fprint(w, "Not found: ", ps.ByName("nodeid"), "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *ApiAliases) SaveOne(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
// SaveOne request for save a alias
|
||||||
|
func (api *AliasesAPI) SaveOne(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
var alias models.Alias
|
var alias models.Alias
|
||||||
|
|
||||||
err := json.NewDecoder(r.Body).Decode(&alias)
|
err := json.NewDecoder(r.Body).Decode(&alias)
|
||||||
|
@ -63,7 +67,9 @@ func (api *ApiAliases) SaveOne(w http.ResponseWriter, r *http.Request, ps httpro
|
||||||
fmt.Print("[api] node updated '", ps.ByName("nodeid"), "'\n")
|
fmt.Print("[api] node updated '", ps.ByName("nodeid"), "'\n")
|
||||||
jsonOutput(w, r, alias)
|
jsonOutput(w, r, alias)
|
||||||
}
|
}
|
||||||
func (api *ApiAliases) AnsibleDiff(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|
||||||
|
// Ansible json output
|
||||||
|
func (api *AliasesAPI) Ansible(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||||
fmt.Print("[api] ansible\n")
|
fmt.Print("[api] ansible\n")
|
||||||
jsonOutput(w, r, models.GenerateAnsible(api.nodes, api.aliases.List))
|
jsonOutput(w, r, models.GenerateAnsible(api.nodes, api.aliases.List))
|
||||||
}
|
}
|
||||||
|
|
72
api/lib.go
72
api/lib.go
|
@ -2,15 +2,15 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"strings"
|
|
||||||
"net/http"
|
|
||||||
"encoding/json"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
)
|
)
|
||||||
|
|
||||||
func jsonOutput(w http.ResponseWriter, r *http.Request,data interface{}){
|
func jsonOutput(w http.ResponseWriter, r *http.Request, data interface{}) {
|
||||||
js, err := json.Marshal(data)
|
js, err := json.Marshal(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
@ -22,40 +22,42 @@ func jsonOutput(w http.ResponseWriter, r *http.Request,data interface{}){
|
||||||
w.Header().Set("Access-Control-Allow-Origin", origin)
|
w.Header().Set("Access-Control-Allow-Origin", origin)
|
||||||
}
|
}
|
||||||
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
|
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
|
||||||
w.Header().Set("Access-Control-Allow-Headers","Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
|
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
|
||||||
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||||
w.Write(js)
|
w.Write(js)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BasicAuth for API request
|
||||||
func BasicAuth(h httprouter.Handle, pass []byte) httprouter.Handle {
|
func BasicAuth(h httprouter.Handle, pass []byte) httprouter.Handle {
|
||||||
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
if origin := r.Header.Get("Origin"); origin != "" {
|
if origin := r.Header.Get("Origin"); origin != "" {
|
||||||
w.Header().Set("Access-Control-Allow-Origin", origin)
|
w.Header().Set("Access-Control-Allow-Origin", origin)
|
||||||
}
|
|
||||||
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
|
|
||||||
w.Header().Set("Access-Control-Allow-Headers","Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
|
|
||||||
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
|
||||||
|
|
||||||
const basicAuthPrefix string = "Basic "
|
|
||||||
|
|
||||||
// Get the Basic Authentication credentials
|
|
||||||
auth := r.Header.Get("Authorization")
|
|
||||||
if strings.HasPrefix(auth, basicAuthPrefix) {
|
|
||||||
// Check credentials
|
|
||||||
payload, err := base64.StdEncoding.DecodeString(auth[len(basicAuthPrefix):])
|
|
||||||
if err == nil {
|
|
||||||
pair := bytes.SplitN(payload, []byte(":"), 2)
|
|
||||||
if len(pair) == 2 &&
|
|
||||||
bytes.Equal(pair[1], pass) {
|
|
||||||
|
|
||||||
// Delegate request to the given handle
|
|
||||||
h(w, r, ps)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request Basic Authentication otherwise
|
|
||||||
w.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
|
|
||||||
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
|
||||||
}
|
}
|
||||||
|
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
|
||||||
|
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
|
||||||
|
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||||
|
|
||||||
|
const basicAuthPrefix string = "Basic "
|
||||||
|
|
||||||
|
// Get the Basic Authentication credentials
|
||||||
|
auth := r.Header.Get("Authorization")
|
||||||
|
if strings.HasPrefix(auth, basicAuthPrefix) {
|
||||||
|
// Check credentials
|
||||||
|
payload, err := base64.StdEncoding.DecodeString(auth[len(basicAuthPrefix):])
|
||||||
|
if err == nil {
|
||||||
|
pair := bytes.SplitN(payload, []byte(":"), 2)
|
||||||
|
if len(pair) == 2 &&
|
||||||
|
bytes.Equal(pair[1], pass) {
|
||||||
|
|
||||||
|
// Delegate request to the given handle
|
||||||
|
h(w, r, ps)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request Basic Authentication otherwise
|
||||||
|
w.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
|
||||||
|
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,19 +6,22 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ApiNodes struct {
|
// NodesAPI struct for API
|
||||||
|
type NodesAPI struct {
|
||||||
config *models.Config
|
config *models.Config
|
||||||
nodes *models.Nodes
|
nodes *models.Nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewNodes Bind to API
|
||||||
func NewNodes(config *models.Config, router *httprouter.Router, prefix string, nodes *models.Nodes) {
|
func NewNodes(config *models.Config, router *httprouter.Router, prefix string, nodes *models.Nodes) {
|
||||||
api := &ApiNodes{
|
api := &NodesAPI{
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
router.GET(prefix, api.GetAll)
|
router.GET(prefix, api.GetAll)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *ApiNodes) GetAll(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
// GetAll request for get all nodes
|
||||||
|
func (api *NodesAPI) GetAll(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||||
jsonOutput(w, r, api.nodes.List)
|
jsonOutput(w, r, api.nodes.List)
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,11 +57,11 @@ func main() {
|
||||||
|
|
||||||
if config.Webserver.Enable {
|
if config.Webserver.Enable {
|
||||||
router := httprouter.New()
|
router := httprouter.New()
|
||||||
if config.Webserver.Api.NewNodes {
|
if config.Webserver.API.NewNodes {
|
||||||
api.NewNodes(config, router, "/api/nodes", nodes)
|
api.NewNodes(config, router, "/api/nodes", nodes)
|
||||||
log.Println("api nodes started")
|
log.Println("api nodes started")
|
||||||
}
|
}
|
||||||
if config.Webserver.Api.Aliases {
|
if config.Webserver.API.Aliases {
|
||||||
api.NewAliases(config, router, "/api/aliases", nodes)
|
api.NewAliases(config, router, "/api/aliases", nodes)
|
||||||
log.Println("api aliases started")
|
log.Println("api aliases started")
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Wireless struct
|
||||||
type Wireless struct {
|
type Wireless struct {
|
||||||
TxPower24 uint32 `json:"txpower24,omitempty"`
|
TxPower24 uint32 `json:"txpower24,omitempty"`
|
||||||
Channel24 uint32 `json:"channel24,omitempty"`
|
Channel24 uint32 `json:"channel24,omitempty"`
|
||||||
|
@ -11,30 +12,32 @@ type Wireless struct {
|
||||||
Channel5 uint32 `json:"channel5,omitempty"`
|
Channel5 uint32 `json:"channel5,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WirelessStatistics struct
|
||||||
type WirelessStatistics []*WirelessAirtime
|
type WirelessStatistics []*WirelessAirtime
|
||||||
|
|
||||||
|
// WirelessAirtime struct
|
||||||
type WirelessAirtime struct {
|
type WirelessAirtime struct {
|
||||||
ChanUtil float32 // Channel utilization
|
ChanUtil float32 // Channel utilization
|
||||||
RxUtil float32 // Receive utilization
|
RxUtil float32 // Receive utilization
|
||||||
TxUtil float32 // Transmit utilization
|
TxUtil float32 // Transmit utilization
|
||||||
|
|
||||||
Active_time uint64 `json:"active"`
|
ActiveTime uint64 `json:"active"`
|
||||||
Busy_time uint64 `json:"busy"`
|
BusyTime uint64 `json:"busy"`
|
||||||
Rx_time uint64 `json:"rx"`
|
RxTime uint64 `json:"rx"`
|
||||||
Tx_time uint64 `json:"tx"`
|
TxTime uint64 `json:"tx"`
|
||||||
Noise uint32 `json:"noise"`
|
Noise uint32 `json:"noise"`
|
||||||
Frequency uint32 `json:"frequency"`
|
Frequency uint32 `json:"frequency"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FrequencyName to 11g or 11a
|
||||||
func (airtime WirelessAirtime) FrequencyName() string {
|
func (airtime WirelessAirtime) FrequencyName() string {
|
||||||
if airtime.Frequency < 5000 {
|
if airtime.Frequency < 5000 {
|
||||||
return "11g"
|
return "11g"
|
||||||
} else {
|
|
||||||
return "11a"
|
|
||||||
}
|
}
|
||||||
|
return "11a"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculates the utilization values in regard to the previous values
|
// SetUtilization Calculates the utilization values in regard to the previous values
|
||||||
func (current WirelessStatistics) SetUtilization(previous WirelessStatistics) {
|
func (current WirelessStatistics) SetUtilization(previous WirelessStatistics) {
|
||||||
for _, c := range current {
|
for _, c := range current {
|
||||||
for _, p := range previous {
|
for _, p := range previous {
|
||||||
|
@ -45,21 +48,21 @@ func (current WirelessStatistics) SetUtilization(previous WirelessStatistics) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculates the utilization values in regard to the previous values
|
// SetUtilization Calculates the utilization values in regard to the previous values
|
||||||
func (cur *WirelessAirtime) SetUtilization(prev *WirelessAirtime) {
|
func (airtime *WirelessAirtime) SetUtilization(prev *WirelessAirtime) {
|
||||||
if cur.Active_time <= prev.Active_time {
|
if airtime.ActiveTime <= prev.ActiveTime {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
active := float64(cur.Active_time) - float64(prev.Active_time)
|
active := float64(airtime.ActiveTime) - float64(prev.ActiveTime)
|
||||||
busy := float64(cur.Busy_time) - float64(prev.Busy_time)
|
busy := float64(airtime.BusyTime) - float64(prev.BusyTime)
|
||||||
rx := float64(cur.Tx_time) - float64(prev.Tx_time)
|
rx := float64(airtime.TxTime) - float64(prev.TxTime)
|
||||||
tx := float64(cur.Rx_time) - float64(prev.Rx_time)
|
tx := float64(airtime.RxTime) - float64(prev.RxTime)
|
||||||
|
|
||||||
// Calculate utilizations
|
// Calculate utilizations
|
||||||
if active > 0 {
|
if active > 0 {
|
||||||
cur.ChanUtil = float32(math.Min(100, 100*(busy+rx+tx)/active))
|
airtime.ChanUtil = float32(math.Min(100, 100*(busy+rx+tx)/active))
|
||||||
cur.RxUtil = float32(math.Min(100, 100*rx/active))
|
airtime.RxUtil = float32(math.Min(100, 100*rx/active))
|
||||||
cur.TxUtil = float32(math.Min(100, 100*tx/active))
|
airtime.TxUtil = float32(math.Min(100, 100*tx/active))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,22 +18,22 @@ func TestUtilization(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
t1 := &WirelessAirtime{
|
t1 := &WirelessAirtime{
|
||||||
Active_time: 20,
|
ActiveTime: 20,
|
||||||
Busy_time: 0,
|
BusyTime: 0,
|
||||||
Tx_time: 5,
|
TxTime: 5,
|
||||||
Rx_time: 0,
|
RxTime: 0,
|
||||||
}
|
}
|
||||||
t2 := &WirelessAirtime{
|
t2 := &WirelessAirtime{
|
||||||
Active_time: 120,
|
ActiveTime: 120,
|
||||||
Busy_time: 10,
|
BusyTime: 10,
|
||||||
Tx_time: 25,
|
TxTime: 25,
|
||||||
Rx_time: 15,
|
RxTime: 15,
|
||||||
}
|
}
|
||||||
t3 := &WirelessAirtime{
|
t3 := &WirelessAirtime{
|
||||||
Active_time: 200,
|
ActiveTime: 200,
|
||||||
Busy_time: 40,
|
BusyTime: 40,
|
||||||
Tx_time: 35,
|
TxTime: 35,
|
||||||
Rx_time: 15,
|
RxTime: 15,
|
||||||
}
|
}
|
||||||
|
|
||||||
t1.SetUtilization(t2)
|
t1.SetUtilization(t2)
|
||||||
|
@ -58,23 +58,23 @@ func TestWirelessStatistics(t *testing.T) {
|
||||||
|
|
||||||
stats := WirelessStatistics([]*WirelessAirtime{{
|
stats := WirelessStatistics([]*WirelessAirtime{{
|
||||||
Frequency: 2400,
|
Frequency: 2400,
|
||||||
Active_time: 20,
|
ActiveTime: 20,
|
||||||
Tx_time: 10,
|
TxTime: 10,
|
||||||
}})
|
}})
|
||||||
|
|
||||||
// Different Frequency, should not change anything
|
// Different Frequency, should not change anything
|
||||||
stats.SetUtilization([]*WirelessAirtime{{
|
stats.SetUtilization([]*WirelessAirtime{{
|
||||||
Frequency: 5000,
|
Frequency: 5000,
|
||||||
Active_time: 15,
|
ActiveTime: 15,
|
||||||
Tx_time: 1,
|
TxTime: 1,
|
||||||
}})
|
}})
|
||||||
assert.EqualValues(0, stats[0].ChanUtil)
|
assert.EqualValues(0, stats[0].ChanUtil)
|
||||||
|
|
||||||
// Same Frequency, should set the utilization
|
// Same Frequency, should set the utilization
|
||||||
stats.SetUtilization([]*WirelessAirtime{{
|
stats.SetUtilization([]*WirelessAirtime{{
|
||||||
Frequency: 2400,
|
Frequency: 2400,
|
||||||
Active_time: 10,
|
ActiveTime: 10,
|
||||||
Tx_time: 5,
|
TxTime: 5,
|
||||||
}})
|
}})
|
||||||
assert.EqualValues(50, stats[0].ChanUtil)
|
assert.EqualValues(50, stats[0].ChanUtil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +1,41 @@
|
||||||
package data
|
package data
|
||||||
|
|
||||||
|
// Neighbours struct
|
||||||
type Neighbours struct {
|
type Neighbours struct {
|
||||||
Batadv map[string]BatadvNeighbours `json:"batadv"`
|
Batadv map[string]BatadvNeighbours `json:"batadv"`
|
||||||
LLDP map[string]LLDPNeighbours `json:"lldp"`
|
LLDP map[string]LLDPNeighbours `json:"lldp"`
|
||||||
//WifiNeighbours map[string]WifiNeighbours `json:"wifi"`
|
//WifiNeighbours map[string]WifiNeighbours `json:"wifi"`
|
||||||
NodeId string `json:"node_id"`
|
NodeID string `json:"node_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WifiLink struct
|
||||||
type WifiLink struct {
|
type WifiLink struct {
|
||||||
Inactive int `json:"inactive"`
|
Inactive int `json:"inactive"`
|
||||||
Noise int `json:"nois"`
|
Noise int `json:"nois"`
|
||||||
Signal int `json:"signal"`
|
Signal int `json:"signal"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BatmanLink struct
|
||||||
type BatmanLink struct {
|
type BatmanLink struct {
|
||||||
Lastseen float64 `json:"lastseen"`
|
Lastseen float64 `json:"lastseen"`
|
||||||
Tq int `json:"tq"`
|
Tq int `json:"tq"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LLDPLink struct
|
||||||
type LLDPLink struct {
|
type LLDPLink struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"descr"`
|
Description string `json:"descr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BatadvNeighbours struct
|
||||||
type BatadvNeighbours struct {
|
type BatadvNeighbours struct {
|
||||||
Neighbours map[string]BatmanLink `json:"neighbours"`
|
Neighbours map[string]BatmanLink `json:"neighbours"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WifiNeighbours struct
|
||||||
type WifiNeighbours struct {
|
type WifiNeighbours struct {
|
||||||
Neighbours map[string]WifiLink `json:"neighbours"`
|
Neighbours map[string]WifiLink `json:"neighbours"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LLDPNeighbours struct
|
||||||
type LLDPNeighbours map[string]LLDPLink
|
type LLDPNeighbours map[string]LLDPLink
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
package data
|
package data
|
||||||
|
|
||||||
|
// NodeInfo struct
|
||||||
type NodeInfo struct {
|
type NodeInfo struct {
|
||||||
NodeId string `json:"node_id"`
|
NodeID string `json:"node_id"`
|
||||||
Network Network `json:"network"`
|
Network Network `json:"network"`
|
||||||
Owner *Owner `json:"-"` // Removed for privacy reasons
|
Owner *Owner `json:"-"` // Removed for privacy reasons
|
||||||
System System `json:"system"`
|
System System `json:"system"`
|
||||||
|
@ -12,6 +13,8 @@ type NodeInfo struct {
|
||||||
VPN bool `json:"vpn"`
|
VPN bool `json:"vpn"`
|
||||||
Wireless *Wireless `json:"wireless,omitempty"`
|
Wireless *Wireless `json:"wireless,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BatInterface struct
|
||||||
type BatInterface struct {
|
type BatInterface struct {
|
||||||
Interfaces struct {
|
Interfaces struct {
|
||||||
Wireless []string `json:"wireless,omitempty"`
|
Wireless []string `json:"wireless,omitempty"`
|
||||||
|
@ -20,6 +23,7 @@ type BatInterface struct {
|
||||||
} `json:"interfaces"`
|
} `json:"interfaces"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Network struct
|
||||||
type Network struct {
|
type Network struct {
|
||||||
Mac string `json:"mac"`
|
Mac string `json:"mac"`
|
||||||
Addresses []string `json:"addresses"`
|
Addresses []string `json:"addresses"`
|
||||||
|
@ -27,20 +31,24 @@ type Network struct {
|
||||||
MeshInterfaces []string `json:"mesh_interfaces"`
|
MeshInterfaces []string `json:"mesh_interfaces"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Owner struct
|
||||||
type Owner struct {
|
type Owner struct {
|
||||||
Contact string `json:"contact"`
|
Contact string `json:"contact"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// System struct
|
||||||
type System struct {
|
type System struct {
|
||||||
SiteCode string `json:"site_code"`
|
SiteCode string `json:"site_code"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Location struct
|
||||||
type Location struct {
|
type Location struct {
|
||||||
Longtitude float64 `json:"longitude"`
|
Longtitude float64 `json:"longitude"`
|
||||||
Latitude float64 `json:"latitude"`
|
Latitude float64 `json:"latitude"`
|
||||||
Altitude float64 `json:"altitude,omitempty"`
|
Altitude float64 `json:"altitude,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Software struct
|
||||||
type Software struct {
|
type Software struct {
|
||||||
Autoupdater struct {
|
Autoupdater struct {
|
||||||
Enabled bool `json:"enabled,omitempty"`
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
|
@ -59,10 +67,11 @@ type Software struct {
|
||||||
Release string `json:"release,omitempty"`
|
Release string `json:"release,omitempty"`
|
||||||
} `json:"firmware,omitempty"`
|
} `json:"firmware,omitempty"`
|
||||||
StatusPage struct {
|
StatusPage struct {
|
||||||
Api int `json:"api"`
|
API int `json:"api"`
|
||||||
} `json:"status-page,omitempty"`
|
} `json:"status-page,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hardware struct
|
||||||
type Hardware struct {
|
type Hardware struct {
|
||||||
Nproc int `json:"nproc"`
|
Nproc int `json:"nproc"`
|
||||||
Model string `json:"model"`
|
Model string `json:"model"`
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package data
|
package data
|
||||||
|
|
||||||
|
// ResponseData struct
|
||||||
type ResponseData struct {
|
type ResponseData struct {
|
||||||
Neighbours *Neighbours `json:"neighbours"`
|
Neighbours *Neighbours `json:"neighbours"`
|
||||||
NodeInfo *NodeInfo `json:"nodeinfo"`
|
NodeInfo *NodeInfo `json:"nodeinfo"`
|
||||||
|
|
|
@ -5,8 +5,9 @@ package data
|
||||||
They always return float.
|
They always return float.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
//Statistics struct
|
||||||
type Statistics struct {
|
type Statistics struct {
|
||||||
NodeId string `json:"node_id"`
|
NodeID string `json:"node_id"`
|
||||||
Clients Clients `json:"clients"`
|
Clients Clients `json:"clients"`
|
||||||
RootFsUsage float64 `json:"rootfs_usage,omitempty"`
|
RootFsUsage float64 `json:"rootfs_usage,omitempty"`
|
||||||
LoadAverage float64 `json:"loadavg,omitempty"`
|
LoadAverage float64 `json:"loadavg,omitempty"`
|
||||||
|
@ -30,25 +31,30 @@ type Statistics struct {
|
||||||
Wireless WirelessStatistics `json:"wireless,omitempty"`
|
Wireless WirelessStatistics `json:"wireless,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MeshVPNPeerLink struct
|
||||||
type MeshVPNPeerLink struct {
|
type MeshVPNPeerLink struct {
|
||||||
Established float64 `json:"established"`
|
Established float64 `json:"established"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MeshVPNPeerGroup struct
|
||||||
type MeshVPNPeerGroup struct {
|
type MeshVPNPeerGroup struct {
|
||||||
Peers map[string]*MeshVPNPeerLink `json:"peers"`
|
Peers map[string]*MeshVPNPeerLink `json:"peers"`
|
||||||
Groups map[string]*MeshVPNPeerGroup `json:"groups"`
|
Groups map[string]*MeshVPNPeerGroup `json:"groups"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MeshVPN struct
|
||||||
type MeshVPN struct {
|
type MeshVPN struct {
|
||||||
Groups map[string]*MeshVPNPeerGroup `json:"groups,omitempty"`
|
Groups map[string]*MeshVPNPeerGroup `json:"groups,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Traffic struct
|
||||||
type Traffic struct {
|
type Traffic struct {
|
||||||
Bytes float64 `json:"bytes,omitempty"`
|
Bytes float64 `json:"bytes,omitempty"`
|
||||||
Packets float64 `json:"packets,omitempty"`
|
Packets float64 `json:"packets,omitempty"`
|
||||||
Dropped float64 `json:"dropped,omitempty"`
|
Dropped float64 `json:"dropped,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clients struct
|
||||||
type Clients struct {
|
type Clients struct {
|
||||||
Wifi uint32 `json:"wifi"`
|
Wifi uint32 `json:"wifi"`
|
||||||
Wifi24 uint32 `json:"wifi24"`
|
Wifi24 uint32 `json:"wifi24"`
|
||||||
|
@ -56,6 +62,7 @@ type Clients struct {
|
||||||
Total uint32 `json:"total"`
|
Total uint32 `json:"total"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Memory struct
|
||||||
type Memory struct {
|
type Memory struct {
|
||||||
Cached uint32 `json:"cached"`
|
Cached uint32 `json:"cached"`
|
||||||
Total uint32 `json:"total"`
|
Total uint32 `json:"total"`
|
||||||
|
@ -63,6 +70,7 @@ type Memory struct {
|
||||||
Free uint32 `json:"free"`
|
Free uint32 `json:"free"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SwitchPort struct
|
||||||
type SwitchPort struct {
|
type SwitchPort struct {
|
||||||
Speed uint32 `json:"speed"`
|
Speed uint32 `json:"speed"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ func TestStatistics(t *testing.T) {
|
||||||
obj := &Statistics{}
|
obj := &Statistics{}
|
||||||
testfile("statistics.json", obj)
|
testfile("statistics.json", obj)
|
||||||
|
|
||||||
assert.Equal("f81a67a601ea", obj.NodeId)
|
assert.Equal("f81a67a601ea", obj.NodeID)
|
||||||
assert.Equal("52:54:00:a9:f7:6e", obj.Gateway)
|
assert.Equal("52:54:00:a9:f7:6e", obj.Gateway)
|
||||||
assert.Equal(float64(57861871176), obj.Traffic.Rx.Bytes)
|
assert.Equal(float64(57861871176), obj.Traffic.Rx.Bytes)
|
||||||
assert.Equal(uint32(35), obj.Clients.Total)
|
assert.Equal(uint32(35), obj.Clients.Total)
|
||||||
|
|
|
@ -85,11 +85,12 @@ func (db *DB) AddCounterMap(name string, m models.CounterMap) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add data for a single node
|
// Add data for a single node
|
||||||
func (db *DB) Add(nodeId string, node *models.Node) {
|
func (db *DB) Add(nodeID string, node *models.Node) {
|
||||||
tags, fields := node.ToInflux()
|
tags, fields := node.ToInflux()
|
||||||
db.AddPoint(MeasurementNode, tags, fields, time.Now())
|
db.AddPoint(MeasurementNode, tags, fields, time.Now())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close all connection and clean up
|
||||||
func (db *DB) Close() {
|
func (db *DB) Close() {
|
||||||
close(db.quit)
|
close(db.quit)
|
||||||
close(db.points)
|
close(db.points)
|
||||||
|
|
|
@ -5,21 +5,26 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TimeFormat of JSONTime
|
||||||
const TimeFormat = "2006-01-02T15:04:05-0700"
|
const TimeFormat = "2006-01-02T15:04:05-0700"
|
||||||
|
|
||||||
|
//Time struct of JSONTime
|
||||||
type Time struct {
|
type Time struct {
|
||||||
time time.Time
|
time time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now current Time
|
||||||
func Now() Time {
|
func Now() Time {
|
||||||
return Time{time.Now()}
|
return Time{time.Now()}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//MarshalJSON to bytearray
|
||||||
func (t Time) MarshalJSON() ([]byte, error) {
|
func (t Time) MarshalJSON() ([]byte, error) {
|
||||||
stamp := `"` + t.time.Format(TimeFormat) + `"`
|
stamp := `"` + t.time.Format(TimeFormat) + `"`
|
||||||
return []byte(stamp), nil
|
return []byte(stamp), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON from bytearray
|
||||||
func (t *Time) UnmarshalJSON(data []byte) (err error) {
|
func (t *Time) UnmarshalJSON(data []byte) (err error) {
|
||||||
if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' {
|
if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' {
|
||||||
return errors.New("invalid jsontime")
|
return errors.New("invalid jsontime")
|
||||||
|
@ -29,24 +34,33 @@ func (t *Time) UnmarshalJSON(data []byte) (err error) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTime normal
|
||||||
func (t Time) GetTime() time.Time {
|
func (t Time) GetTime() time.Time {
|
||||||
return t.time
|
return t.time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unix of this time
|
||||||
func (t Time) Unix() int64 {
|
func (t Time) Unix() int64 {
|
||||||
return t.time.Unix()
|
return t.time.Unix()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsZero is time zero?
|
||||||
func (t Time) IsZero() bool {
|
func (t Time) IsZero() bool {
|
||||||
return t.time.IsZero()
|
return t.time.IsZero()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add given Duration to this time
|
||||||
func (t Time) Add(d time.Duration) Time {
|
func (t Time) Add(d time.Duration) Time {
|
||||||
return Time{time: t.time.Add(d)}
|
return Time{time: t.time.Add(d)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// After is this time after the given?
|
||||||
func (t Time) After(u Time) bool {
|
func (t Time) After(u Time) bool {
|
||||||
return t.time.After(u.GetTime())
|
return t.time.After(u.GetTime())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Before is this time before the given?
|
||||||
func (t Time) Before(u Time) bool {
|
func (t Time) Before(u Time) bool {
|
||||||
return t.time.Before(u.GetTime())
|
return t.time.Before(u.GetTime())
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ type Node struct {
|
||||||
Neighbours *data.Neighbours `json:"-"`
|
Neighbours *data.Neighbours `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flags status of node set by collector for the meshviewer
|
||||||
type Flags struct {
|
type Flags struct {
|
||||||
Online bool `json:"online"`
|
Online bool `json:"online"`
|
||||||
Gateway bool `json:"gateway"`
|
Gateway bool `json:"gateway"`
|
||||||
|
@ -36,8 +37,9 @@ type NodesV2 struct {
|
||||||
List []*Node `json:"nodes"` // the current nodemap, as array
|
List []*Node `json:"nodes"` // the current nodemap, as array
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Statistics a meshviewer spezifisch struct, diffrent from respondd
|
||||||
type Statistics struct {
|
type Statistics struct {
|
||||||
NodeId string `json:"node_id"`
|
NodeID string `json:"node_id"`
|
||||||
Clients uint32 `json:"clients"`
|
Clients uint32 `json:"clients"`
|
||||||
RootFsUsage float64 `json:"rootfs_usage,omitempty"`
|
RootFsUsage float64 `json:"rootfs_usage,omitempty"`
|
||||||
LoadAverage float64 `json:"loadavg,omitempty"`
|
LoadAverage float64 `json:"loadavg,omitempty"`
|
||||||
|
@ -59,18 +61,19 @@ type Statistics struct {
|
||||||
} `json:"traffic,omitempty"`
|
} `json:"traffic,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewStatistics transform respond Statistics to meshviewer Statistics
|
||||||
func NewStatistics(stats *data.Statistics) *Statistics {
|
func NewStatistics(stats *data.Statistics) *Statistics {
|
||||||
total := stats.Clients.Total
|
total := stats.Clients.Total
|
||||||
if total == 0 {
|
if total == 0 {
|
||||||
total = stats.Clients.Wifi24 + stats.Clients.Wifi5
|
total = stats.Clients.Wifi24 + stats.Clients.Wifi5
|
||||||
}
|
}
|
||||||
/* The Meshviewer could not handle absolute memory output
|
/* The Meshviewer could not handle absolute memory output
|
||||||
* calc the used memory as a float witch 100% equal 1.0
|
* calc the used memory as a float witch 100% equal 1.0
|
||||||
*/
|
*/
|
||||||
memoryUsage := (float64(stats.Memory.Total) - float64(stats.Memory.Free)) / float64(stats.Memory.Total)
|
memoryUsage := (float64(stats.Memory.Total) - float64(stats.Memory.Free)) / float64(stats.Memory.Total)
|
||||||
|
|
||||||
return &Statistics{
|
return &Statistics{
|
||||||
NodeId: stats.NodeId,
|
NodeID: stats.NodeID,
|
||||||
Gateway: stats.Gateway,
|
Gateway: stats.Gateway,
|
||||||
RootFsUsage: stats.RootFsUsage,
|
RootFsUsage: stats.RootFsUsage,
|
||||||
LoadAverage: stats.LoadAverage,
|
LoadAverage: stats.LoadAverage,
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/FreifunkBremen/respond-collector/data"
|
"github.com/FreifunkBremen/respond-collector/data"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Alias a change request for other nodes
|
||||||
type Alias struct {
|
type Alias struct {
|
||||||
Hostname string `json:"hostname,omitempty"`
|
Hostname string `json:"hostname,omitempty"`
|
||||||
Location *data.Location `json:"location,omitempty"`
|
Location *data.Location `json:"location,omitempty"`
|
||||||
|
@ -17,14 +18,14 @@ type Alias struct {
|
||||||
Owner string `json:"owner,omitempty"`
|
Owner string `json:"owner,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nodes struct: cache DB of Node's structs
|
// Aliases struct: cache DB of Node's structs
|
||||||
type Aliases struct {
|
type Aliases struct {
|
||||||
List map[string]*Alias `json:"nodes"` // the current nodemap, indexed by node ID
|
List map[string]*Alias `json:"nodes"` // the current nodemap, indexed by node ID
|
||||||
config *Config
|
config *Config
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNodes create Nodes structs
|
// NewAliases create Nodes structs
|
||||||
func NewAliases(config *Config) *Aliases {
|
func NewAliases(config *Config) *Aliases {
|
||||||
aliases := &Aliases{
|
aliases := &Aliases{
|
||||||
List: make(map[string]*Alias),
|
List: make(map[string]*Alias),
|
||||||
|
@ -39,6 +40,7 @@ func NewAliases(config *Config) *Aliases {
|
||||||
return aliases
|
return aliases
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update a alias in aliases cache
|
||||||
func (e *Aliases) Update(nodeID string, newalias *Alias) {
|
func (e *Aliases) Update(nodeID string, newalias *Alias) {
|
||||||
e.Lock()
|
e.Lock()
|
||||||
e.List[nodeID] = newalias
|
e.List[nodeID] = newalias
|
||||||
|
@ -51,7 +53,7 @@ func (e *Aliases) load() {
|
||||||
log.Println("loading", path)
|
log.Println("loading", path)
|
||||||
|
|
||||||
if data, err := ioutil.ReadFile(path); err == nil {
|
if data, err := ioutil.ReadFile(path); err == nil {
|
||||||
if err := json.Unmarshal(data, e); err == nil {
|
if err = json.Unmarshal(data, e); err == nil {
|
||||||
log.Println("loaded", len(e.List), "aliases")
|
log.Println("loaded", len(e.List), "aliases")
|
||||||
} else {
|
} else {
|
||||||
log.Println("failed to unmarshal nodes:", err)
|
log.Println("failed to unmarshal nodes:", err)
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
|
// Ansible struct
|
||||||
type Ansible struct {
|
type Ansible struct {
|
||||||
Nodes []string `json:"nodes"`
|
Nodes []string `json:"nodes"`
|
||||||
Meta struct {
|
Meta struct {
|
||||||
HostVars map[string]*AnsibleHostVars `json:"hostvars,omitempty"`
|
HostVars map[string]*AnsibleHostVars `json:"hostvars,omitempty"`
|
||||||
} `json:"_meta"`
|
} `json:"_meta"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AnsibleHostVars new values for a node
|
||||||
type AnsibleHostVars struct {
|
type AnsibleHostVars struct {
|
||||||
Address string `json:"ansible_ssh_host"`
|
Address string `json:"ansible_ssh_host"`
|
||||||
Hostname string `json:"node_name,omitempty"`
|
Hostname string `json:"node_name,omitempty"`
|
||||||
|
@ -18,6 +21,7 @@ type AnsibleHostVars struct {
|
||||||
GeoLongitude float64 `json:"geo_longitude,omitempty"`
|
GeoLongitude float64 `json:"geo_longitude,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenerateAnsible but nodes and aliases together to a ansible change output
|
||||||
func GenerateAnsible(nodes *Nodes, aliases map[string]*Alias) *Ansible {
|
func GenerateAnsible(nodes *Nodes, aliases map[string]*Alias) *Ansible {
|
||||||
ansible := &Ansible{Nodes: make([]string, 0)}
|
ansible := &Ansible{Nodes: make([]string, 0)}
|
||||||
ansible.Meta.HostVars = make(map[string]*AnsibleHostVars)
|
ansible.Meta.HostVars = make(map[string]*AnsibleHostVars)
|
||||||
|
|
|
@ -19,7 +19,7 @@ type Config struct {
|
||||||
Port string `yaml:"port"`
|
Port string `yaml:"port"`
|
||||||
Address string `yaml:"address"`
|
Address string `yaml:"address"`
|
||||||
Webroot string `yaml:"webroot"`
|
Webroot string `yaml:"webroot"`
|
||||||
Api struct {
|
API struct {
|
||||||
Passphrase string `yaml:"passphrase"`
|
Passphrase string `yaml:"passphrase"`
|
||||||
NewNodes bool `yaml:"newnodes"`
|
NewNodes bool `yaml:"newnodes"`
|
||||||
Aliases bool `yaml:"aliases"`
|
Aliases bool `yaml:"aliases"`
|
||||||
|
@ -47,7 +47,7 @@ type Config struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reads a config models by path to a yml file
|
// ReadConfigFile reads a config model from path of a yml file
|
||||||
func ReadConfigFile(path string) *Config {
|
func ReadConfigFile(path string) *Config {
|
||||||
config := &Config{}
|
config := &Config{}
|
||||||
file, _ := ioutil.ReadFile(path)
|
file, _ := ioutil.ReadFile(path)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Graph a struct for all links between the nodes
|
||||||
type Graph struct {
|
type Graph struct {
|
||||||
Version int `json:"version"`
|
Version int `json:"version"`
|
||||||
Batadv struct {
|
Batadv struct {
|
||||||
|
@ -15,10 +16,13 @@ type Graph struct {
|
||||||
} `json:"batadv"`
|
} `json:"batadv"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GraphNode small struct of a node for the graph struct
|
||||||
type GraphNode struct {
|
type GraphNode struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
NodeID string `json:"node_id"`
|
NodeID string `json:"node_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GraphLink a struct for the link between two nodes
|
||||||
type GraphLink struct {
|
type GraphLink struct {
|
||||||
Source int `json:"source"`
|
Source int `json:"source"`
|
||||||
Target int `json:"target"`
|
Target int `json:"target"`
|
||||||
|
@ -27,14 +31,16 @@ type GraphLink struct {
|
||||||
Bidirect bool `json:"bidirect"`
|
Bidirect bool `json:"bidirect"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GraphBuilder struct {
|
// GraphBuilder a temporaty struct during fill the graph from the node neighbours
|
||||||
|
type graphBuilder struct {
|
||||||
macToID map[string]string // mapping from MAC address to node id
|
macToID map[string]string // mapping from MAC address to node id
|
||||||
links map[string]*GraphLink // mapping from $idA-$idB to existing link
|
links map[string]*GraphLink // mapping from $idA-$idB to existing link
|
||||||
vpn map[string]interface{} // IDs/addresses of VPN servers
|
vpn map[string]interface{} // IDs/addresses of VPN servers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BuildGraph transform from nodes (Neighbours) to Graph
|
||||||
func (nodes *Nodes) BuildGraph() *Graph {
|
func (nodes *Nodes) BuildGraph() *Graph {
|
||||||
builder := &GraphBuilder{
|
builder := &graphBuilder{
|
||||||
macToID: make(map[string]string),
|
macToID: make(map[string]string),
|
||||||
links: make(map[string]*GraphLink),
|
links: make(map[string]*GraphLink),
|
||||||
vpn: make(map[string]interface{}),
|
vpn: make(map[string]interface{}),
|
||||||
|
@ -44,11 +50,11 @@ func (nodes *Nodes) BuildGraph() *Graph {
|
||||||
|
|
||||||
graph := &Graph{Version: 1}
|
graph := &Graph{Version: 1}
|
||||||
graph.Batadv.Directed = false
|
graph.Batadv.Directed = false
|
||||||
graph.Batadv.Nodes, graph.Batadv.Links = builder.Extract()
|
graph.Batadv.Nodes, graph.Batadv.Links = builder.extract()
|
||||||
return graph
|
return graph
|
||||||
}
|
}
|
||||||
|
|
||||||
func (builder *GraphBuilder) readNodes(nodes map[string]*Node) {
|
func (builder *graphBuilder) readNodes(nodes map[string]*Node) {
|
||||||
// Fill mac->id map
|
// Fill mac->id map
|
||||||
for sourceID, node := range nodes {
|
for sourceID, node := range nodes {
|
||||||
if nodeinfo := node.Nodeinfo; nodeinfo != nil {
|
if nodeinfo := node.Nodeinfo; nodeinfo != nil {
|
||||||
|
@ -70,7 +76,7 @@ func (builder *GraphBuilder) readNodes(nodes map[string]*Node) {
|
||||||
|
|
||||||
// Iterate over local MAC addresses from LLDP
|
// Iterate over local MAC addresses from LLDP
|
||||||
if neighbours := node.Neighbours; neighbours != nil {
|
if neighbours := node.Neighbours; neighbours != nil {
|
||||||
for sourceAddr, _ := range neighbours.LLDP {
|
for sourceAddr := range neighbours.LLDP {
|
||||||
builder.macToID[sourceAddr] = sourceID
|
builder.macToID[sourceAddr] = sourceID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,7 +96,7 @@ func (builder *GraphBuilder) readNodes(nodes map[string]*Node) {
|
||||||
}
|
}
|
||||||
// LLDP
|
// LLDP
|
||||||
for _, neighbours := range neighbours.LLDP {
|
for _, neighbours := range neighbours.LLDP {
|
||||||
for targetAddress, _ := range neighbours {
|
for targetAddress := range neighbours {
|
||||||
if targetID, found := builder.macToID[targetAddress]; found {
|
if targetID, found := builder.macToID[targetAddress]; found {
|
||||||
builder.addLink(targetID, sourceID, 255)
|
builder.addLink(targetID, sourceID, 255)
|
||||||
}
|
}
|
||||||
|
@ -101,7 +107,7 @@ func (builder *GraphBuilder) readNodes(nodes map[string]*Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (builder *GraphBuilder) Extract() ([]*GraphNode, []*GraphLink) {
|
func (builder *graphBuilder) extract() ([]*GraphNode, []*GraphLink) {
|
||||||
links := make([]*GraphLink, len(builder.links))
|
links := make([]*GraphLink, len(builder.links))
|
||||||
nodes := make([]*GraphNode, len(builder.macToID))
|
nodes := make([]*GraphNode, len(builder.macToID))
|
||||||
idToIndex := make(map[string]int)
|
idToIndex := make(map[string]int)
|
||||||
|
@ -131,7 +137,7 @@ func (builder *GraphBuilder) Extract() ([]*GraphNode, []*GraphLink) {
|
||||||
return nodes, links
|
return nodes, links
|
||||||
}
|
}
|
||||||
|
|
||||||
func (builder *GraphBuilder) isVPN(ids ...string) bool {
|
func (builder *graphBuilder) isVPN(ids ...string) bool {
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
if _, found := builder.vpn[id]; found {
|
if _, found := builder.vpn[id]; found {
|
||||||
return true
|
return true
|
||||||
|
@ -140,7 +146,7 @@ func (builder *GraphBuilder) isVPN(ids ...string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (builder *GraphBuilder) addLink(targetID string, sourceID string, linkTq int) {
|
func (builder *graphBuilder) addLink(targetID string, sourceID string, linkTq int) {
|
||||||
// Sort IDs to generate the key
|
// Sort IDs to generate the key
|
||||||
var key string
|
var key string
|
||||||
if strings.Compare(sourceID, targetID) > 0 {
|
if strings.Compare(sourceID, targetID) > 0 {
|
||||||
|
|
|
@ -22,7 +22,7 @@ type Node struct {
|
||||||
func (node *Node) ToInflux() (tags imodels.Tags, fields imodels.Fields) {
|
func (node *Node) ToInflux() (tags imodels.Tags, fields imodels.Fields) {
|
||||||
stats := node.Statistics
|
stats := node.Statistics
|
||||||
|
|
||||||
tags.SetString("nodeid", stats.NodeId)
|
tags.SetString("nodeid", stats.NodeID)
|
||||||
|
|
||||||
fields = map[string]interface{}{
|
fields = map[string]interface{}{
|
||||||
"load": stats.LoadAverage,
|
"load": stats.LoadAverage,
|
||||||
|
|
|
@ -31,14 +31,15 @@ func NewNodes(config *Config) *Nodes {
|
||||||
if config.Nodes.NodesDynamicPath != "" {
|
if config.Nodes.NodesDynamicPath != "" {
|
||||||
nodes.load()
|
nodes.load()
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Version '-1' because the nodes.json would not be defined,
|
* Version '-1' because the nodes.json would not be defined,
|
||||||
* it would be change with the change of the respondd application on gluon
|
* it would be change with the change of the respondd application on gluon
|
||||||
*/
|
*/
|
||||||
nodes.Version = -1
|
nodes.Version = -1
|
||||||
return nodes
|
return nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Start all services to manage Nodes
|
||||||
func (nodes *Nodes) Start() {
|
func (nodes *Nodes) Start() {
|
||||||
go nodes.worker()
|
go nodes.worker()
|
||||||
}
|
}
|
||||||
|
@ -180,7 +181,7 @@ func (nodes *Nodes) load() {
|
||||||
path := nodes.config.Nodes.NodesDynamicPath
|
path := nodes.config.Nodes.NodesDynamicPath
|
||||||
|
|
||||||
if f, err := os.Open(path); err == nil { // transform data to legacy meshviewer
|
if f, err := os.Open(path); err == nil { // transform data to legacy meshviewer
|
||||||
if err := json.NewDecoder(f).Decode(nodes); err == nil {
|
if err = json.NewDecoder(f).Decode(nodes); err == nil {
|
||||||
log.Println("loaded", len(nodes.List), "nodes")
|
log.Println("loaded", len(nodes.List), "nodes")
|
||||||
} else {
|
} else {
|
||||||
log.Println("failed to unmarshal nodes:", err)
|
log.Println("failed to unmarshal nodes:", err)
|
||||||
|
|
|
@ -79,7 +79,7 @@ func TestToInflux(t *testing.T) {
|
||||||
|
|
||||||
node := Node{
|
node := Node{
|
||||||
Statistics: &data.Statistics{
|
Statistics: &data.Statistics{
|
||||||
NodeId: "foobar",
|
NodeID: "foobar",
|
||||||
LoadAverage: 0.5,
|
LoadAverage: 0.5,
|
||||||
},
|
},
|
||||||
Nodeinfo: &data.NodeInfo{
|
Nodeinfo: &data.NodeInfo{
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
|
// CounterMap to manage multiple values
|
||||||
type CounterMap map[string]uint32
|
type CounterMap map[string]uint32
|
||||||
|
|
||||||
|
// GlobalStats struct
|
||||||
type GlobalStats struct {
|
type GlobalStats struct {
|
||||||
Clients uint32
|
Clients uint32
|
||||||
ClientsWifi uint32
|
ClientsWifi uint32
|
||||||
|
@ -14,7 +16,7 @@ type GlobalStats struct {
|
||||||
Models CounterMap
|
Models CounterMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns global statistics for InfluxDB
|
//NewGlobalStats returns global statistics for InfluxDB
|
||||||
func NewGlobalStats(nodes *Nodes) (result *GlobalStats) {
|
func NewGlobalStats(nodes *Nodes) (result *GlobalStats) {
|
||||||
result = &GlobalStats{
|
result = &GlobalStats{
|
||||||
Firmwares: make(CounterMap),
|
Firmwares: make(CounterMap),
|
||||||
|
@ -24,7 +26,7 @@ func NewGlobalStats(nodes *Nodes) (result *GlobalStats) {
|
||||||
nodes.Lock()
|
nodes.Lock()
|
||||||
for _, node := range nodes.List {
|
for _, node := range nodes.List {
|
||||||
if node.Flags.Online {
|
if node.Flags.Online {
|
||||||
result.Nodes += 1
|
result.Nodes++
|
||||||
if stats := node.Statistics; stats != nil {
|
if stats := node.Statistics; stats != nil {
|
||||||
result.Clients += stats.Clients.Total
|
result.Clients += stats.Clients.Total
|
||||||
result.ClientsWifi24 += stats.Clients.Wifi24
|
result.ClientsWifi24 += stats.Clients.Wifi24
|
||||||
|
@ -32,7 +34,7 @@ func NewGlobalStats(nodes *Nodes) (result *GlobalStats) {
|
||||||
result.ClientsWifi += stats.Clients.Wifi
|
result.ClientsWifi += stats.Clients.Wifi
|
||||||
}
|
}
|
||||||
if node.Flags.Gateway {
|
if node.Flags.Gateway {
|
||||||
result.Gateways += 1
|
result.Gateways++
|
||||||
}
|
}
|
||||||
if info := node.Nodeinfo; info != nil {
|
if info := node.Nodeinfo; info != nil {
|
||||||
result.Models.Increment(info.Hardware.Model)
|
result.Models.Increment(info.Hardware.Model)
|
||||||
|
@ -53,7 +55,7 @@ func (m CounterMap) Increment(key string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns fields for InfluxDB
|
// Fields returns fields for InfluxDB
|
||||||
func (stats *GlobalStats) Fields() map[string]interface{} {
|
func (stats *GlobalStats) Fields() map[string]interface{} {
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
"nodes": stats.Nodes,
|
"nodes": stats.Nodes,
|
||||||
|
|
|
@ -28,7 +28,7 @@ type Collector struct {
|
||||||
stop chan interface{}
|
stop chan interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a Collector struct
|
// NewCollector creates a Collector struct
|
||||||
func NewCollector(db *database.DB, nodes *models.Nodes, iface string) *Collector {
|
func NewCollector(db *database.DB, nodes *models.Nodes, iface string) *Collector {
|
||||||
// Parse address
|
// Parse address
|
||||||
addr, err := net.ResolveUDPAddr("udp", "[::]:0")
|
addr, err := net.ResolveUDPAddr("udp", "[::]:0")
|
||||||
|
@ -140,24 +140,24 @@ func (res *Response) parse() (*data.ResponseData, error) {
|
||||||
|
|
||||||
func (coll *Collector) saveResponse(addr net.UDPAddr, res *data.ResponseData) {
|
func (coll *Collector) saveResponse(addr net.UDPAddr, res *data.ResponseData) {
|
||||||
// Search for NodeID
|
// Search for NodeID
|
||||||
var nodeId string
|
var nodeID string
|
||||||
if val := res.NodeInfo; val != nil {
|
if val := res.NodeInfo; val != nil {
|
||||||
nodeId = val.NodeId
|
nodeID = val.NodeID
|
||||||
} else if val := res.Neighbours; val != nil {
|
} else if val := res.Neighbours; val != nil {
|
||||||
nodeId = val.NodeId
|
nodeID = val.NodeID
|
||||||
} else if val := res.Statistics; val != nil {
|
} else if val := res.Statistics; val != nil {
|
||||||
nodeId = val.NodeId
|
nodeID = val.NodeID
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates nodes if NodeID found
|
// Updates nodes if NodeID found
|
||||||
if len(nodeId) != 12 {
|
if len(nodeID) != 12 {
|
||||||
log.Printf("invalid NodeID '%s' from %s", nodeId, addr.String())
|
log.Printf("invalid NodeID '%s' from %s", nodeID, addr.String())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
node := coll.nodes.Update(nodeId, res)
|
node := coll.nodes.Update(nodeID, res)
|
||||||
|
|
||||||
if coll.db != nil && node.Statistics != nil {
|
if coll.db != nil && node.Statistics != nil {
|
||||||
coll.db.Add(nodeId, node)
|
coll.db.Add(nodeID, node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,5 +23,5 @@ func TestParse(t *testing.T) {
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.NotNil(data)
|
assert.NotNil(data)
|
||||||
|
|
||||||
assert.Equal("f81a67a5e9c1", data.NodeInfo.NodeId)
|
assert.Equal("f81a67a5e9c1", data.NodeInfo.NodeID)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue