multi nodes
This commit is contained in:
parent
83dd82e6d2
commit
67c6031fff
@ -1,6 +1,7 @@
|
|||||||
---
|
---
|
||||||
respondd:
|
respondd:
|
||||||
enable: true
|
enable: true
|
||||||
|
interface: eth0
|
||||||
collectinterval: 15
|
collectinterval: 15
|
||||||
webserver:
|
webserver:
|
||||||
enable: false
|
enable: false
|
||||||
@ -12,7 +13,8 @@ webserver:
|
|||||||
aliases: true
|
aliases: true
|
||||||
nodes:
|
nodes:
|
||||||
enable: true
|
enable: true
|
||||||
nodes_path: /var/www/html/meshviewer/data/nodes.json
|
nodes_path: /var/www/html/meshviewer/data/nodes_all.json
|
||||||
|
nodesmini_path: /var/www/html/meshviewer/data/nodes.json
|
||||||
graphs_path: /var/www/html/meshviewer/data/graph.json
|
graphs_path: /var/www/html/meshviewer/data/graph.json
|
||||||
saveinterval: 5
|
saveinterval: 5
|
||||||
aliases_enable: false
|
aliases_enable: false
|
||||||
|
21
main.go
21
main.go
@ -10,21 +10,21 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/julienschmidt/httprouter"
|
|
||||||
"github.com/NYTimes/gziphandler"
|
"github.com/NYTimes/gziphandler"
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
|
||||||
|
"github.com/FreifunkBremen/respond-collector/api"
|
||||||
"github.com/FreifunkBremen/respond-collector/data"
|
"github.com/FreifunkBremen/respond-collector/data"
|
||||||
"github.com/FreifunkBremen/respond-collector/models"
|
"github.com/FreifunkBremen/respond-collector/models"
|
||||||
"github.com/FreifunkBremen/respond-collector/respond"
|
"github.com/FreifunkBremen/respond-collector/respond"
|
||||||
"github.com/FreifunkBremen/respond-collector/api"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
configFile string
|
configFile string
|
||||||
config *models.Config
|
config *models.Config
|
||||||
collector *respond.Collector
|
collector *respond.Collector
|
||||||
statsDb *StatsDb
|
statsDb *StatsDb
|
||||||
nodes *models.Nodes
|
nodes *models.Nodes
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -39,18 +39,17 @@ func main() {
|
|||||||
|
|
||||||
if config.Respondd.Enable {
|
if config.Respondd.Enable {
|
||||||
collectInterval := time.Second * time.Duration(config.Respondd.CollectInterval)
|
collectInterval := time.Second * time.Duration(config.Respondd.CollectInterval)
|
||||||
collector = respond.NewCollector("nodeinfo statistics neighbours", collectInterval, onReceive)
|
collector = respond.NewCollector("nodeinfo statistics neighbours", collectInterval, onReceive, config.Respondd.Interface)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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")
|
||||||
}
|
}
|
||||||
router.NotFound = gziphandler.GzipHandler(http.FileServer(http.Dir(config.Webserver.Webroot)))
|
router.NotFound = gziphandler.GzipHandler(http.FileServer(http.Dir(config.Webserver.Webroot)))
|
||||||
|
@ -11,32 +11,31 @@ import (
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
Respondd struct {
|
Respondd struct {
|
||||||
Enable bool `yaml:"enable"`
|
Enable bool `yaml:"enable"`
|
||||||
Port string `yaml:"port"`
|
Interface string `yaml:"interface"`
|
||||||
Address string `yaml:"address"`
|
|
||||||
CollectInterval int `yaml:"collectinterval"`
|
CollectInterval int `yaml:"collectinterval"`
|
||||||
} `yaml:"respondd"`
|
} `yaml:"respondd"`
|
||||||
Webserver struct {
|
Webserver struct {
|
||||||
Enable bool `yaml:"enable"`
|
Enable bool `yaml:"enable"`
|
||||||
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"`
|
||||||
} `yaml:"api"`
|
} `yaml:"api"`
|
||||||
} `yaml:"webserver"`
|
} `yaml:"webserver"`
|
||||||
Nodes struct {
|
Nodes struct {
|
||||||
Enable bool `yaml:"enable"`
|
Enable bool `yaml:"enable"`
|
||||||
NodesPath string `yaml:"nodes_path"`
|
NodesPath string `yaml:"nodes_path"`
|
||||||
GraphsPath string `yaml:"graphs_path"`
|
NodesMiniPath string `yaml:"nodesmini_path"`
|
||||||
AliasesPath string `yaml:"aliases_path"`
|
GraphsPath string `yaml:"graphs_path"`
|
||||||
SaveInterval int `yaml:"saveinterval"`
|
AliasesPath string `yaml:"aliases_path"`
|
||||||
VpnAddresses []string `yaml:"vpn_addresses"`
|
SaveInterval int `yaml:"saveinterval"`
|
||||||
} `yaml:"nodes"`
|
} `yaml:"nodes"`
|
||||||
Influxdb struct {
|
Influxdb struct {
|
||||||
Enable bool `yaml:"enable"`
|
Enable bool `yaml:"enable"`
|
||||||
Addr string `yaml:"host"`
|
Addr string `yaml:"host"`
|
||||||
Database string `yaml:"database"`
|
Database string `yaml:"database"`
|
||||||
Username string `yaml:"username"`
|
Username string `yaml:"username"`
|
||||||
Password string `yaml:"password"`
|
Password string `yaml:"password"`
|
||||||
|
@ -8,23 +8,23 @@ import (
|
|||||||
type Graph struct {
|
type Graph struct {
|
||||||
Version int `json:"version"`
|
Version int `json:"version"`
|
||||||
Batadv struct {
|
Batadv struct {
|
||||||
Directed bool `json:"directed"`
|
Directed bool `json:"directed"`
|
||||||
Graph []string `json:"graph"`
|
Graph []string `json:"graph"`
|
||||||
Nodes []*GraphNode `json:"nodes"`
|
Nodes []*GraphNode `json:"nodes"`
|
||||||
Links []*GraphLink `json:"links"`
|
Links []*GraphLink `json:"links"`
|
||||||
} `json:"batadv"`
|
} `json:"batadv"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GraphNode struct {
|
type GraphNode struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
NodeID string `json:"node_id"`
|
NodeID string `json:"node_id"`
|
||||||
}
|
}
|
||||||
type GraphLink struct {
|
type GraphLink struct {
|
||||||
Source interface{} `json:"source"`
|
Source interface{} `json:"source"`
|
||||||
Target interface{} `json:"target"`
|
Target interface{} `json:"target"`
|
||||||
VPN bool `json:"vpn"`
|
VPN bool `json:"vpn"`
|
||||||
TQ float32 `json:"tq"`
|
TQ float32 `json:"tq"`
|
||||||
Bidirect bool `json:"bidirect"`
|
Bidirect bool `json:"bidirect"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GraphBuilder struct {
|
type GraphBuilder struct {
|
||||||
@ -50,30 +50,30 @@ func (nodes *Nodes) BuildGraph() *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 {
|
||||||
// is VPN address?
|
// is VPN address?
|
||||||
if nodeinfo.VPN {
|
if nodeinfo.VPN {
|
||||||
builder.vpn[sourceId] = nil
|
builder.vpn[sourceID] = nil
|
||||||
}
|
}
|
||||||
for _,batinterface := range nodeinfo.Network.Mesh {
|
for _, batinterface := range nodeinfo.Network.Mesh {
|
||||||
interfaces := batinterface.Interfaces
|
interfaces := batinterface.Interfaces
|
||||||
addresses := append(append(interfaces.Other, interfaces.Tunnel...), interfaces.Wireless...)
|
addresses := append(append(interfaces.Other, interfaces.Tunnel...), interfaces.Wireless...)
|
||||||
|
|
||||||
for _, sourceAddress := range addresses {
|
for _, sourceAddress := range addresses {
|
||||||
builder.macToID[sourceAddress] = sourceId
|
builder.macToID[sourceAddress] = sourceID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add links
|
// Add links
|
||||||
for sourceId, node := range nodes {
|
for sourceID, node := range nodes {
|
||||||
if neighbours := node.Neighbours; neighbours != nil {
|
if neighbours := node.Neighbours; neighbours != nil {
|
||||||
for _, batadvNeighbours := range neighbours.Batadv {
|
for _, batadvNeighbours := range neighbours.Batadv {
|
||||||
for targetAddress, link := range batadvNeighbours.Neighbours {
|
for targetAddress, link := range batadvNeighbours.Neighbours {
|
||||||
if targetId, found := builder.macToID[targetAddress]; found {
|
if targetID, found := builder.macToID[targetAddress]; found {
|
||||||
builder.addLink(targetId, sourceId, link.Tq)
|
builder.addLink(targetID, sourceID, link.Tq)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ func (builder *GraphBuilder) readNodes(nodes map[string]*Node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (builder *GraphBuilder) Extract() ([]*GraphNode,[]*GraphLink) {
|
func (builder *GraphBuilder) Extract() ([]*GraphNode, []*GraphLink) {
|
||||||
iNodes := 0
|
iNodes := 0
|
||||||
iLinks := 0
|
iLinks := 0
|
||||||
links := make([]*GraphLink, len(builder.links))
|
links := make([]*GraphLink, len(builder.links))
|
||||||
@ -89,32 +89,32 @@ func (builder *GraphBuilder) Extract() ([]*GraphNode,[]*GraphLink) {
|
|||||||
|
|
||||||
for mac, nodeID := range builder.macToID {
|
for mac, nodeID := range builder.macToID {
|
||||||
nodes[iNodes] = &GraphNode{
|
nodes[iNodes] = &GraphNode{
|
||||||
ID: mac,
|
ID: mac,
|
||||||
NodeID: nodeID,
|
NodeID: nodeID,
|
||||||
}
|
}
|
||||||
iNodes += 1
|
iNodes++
|
||||||
}
|
}
|
||||||
for key, link := range builder.links {
|
for key, link := range builder.links {
|
||||||
linkPart :=strings.Split(key,"-")
|
linkPart := strings.Split(key, "-")
|
||||||
both := 0
|
both := 0
|
||||||
for i,node := range nodes{
|
for i, node := range nodes {
|
||||||
if(linkPart[0] == node.NodeID){
|
if linkPart[0] == node.NodeID {
|
||||||
link.Source = i
|
link.Source = i
|
||||||
both += 1
|
both++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if(linkPart[1]==node.NodeID){
|
if linkPart[1] == node.NodeID {
|
||||||
link.Target = i
|
link.Target = i
|
||||||
both += 1
|
both++
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if both == 2 {
|
if both == 2 {
|
||||||
links[iLinks] = link
|
links[iLinks] = link
|
||||||
iLinks += 1
|
iLinks++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nodes, links[:iLinks]
|
return nodes, links[:iLinks]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (builder *GraphBuilder) isVPN(ids ...string) bool {
|
func (builder *GraphBuilder) isVPN(ids ...string) bool {
|
||||||
@ -126,13 +126,13 @@ 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 {
|
||||||
key = fmt.Sprintf("%s-%s", sourceId, targetId)
|
key = fmt.Sprintf("%s-%s", sourceID, targetID)
|
||||||
} else {
|
} else {
|
||||||
key = fmt.Sprintf("%s-%s", targetId, sourceId)
|
key = fmt.Sprintf("%s-%s", targetID, sourceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
var tq float32
|
var tq float32
|
||||||
@ -142,8 +142,8 @@ func (builder *GraphBuilder) addLink(targetId string, sourceId string, linkTq in
|
|||||||
|
|
||||||
if link, ok := builder.links[key]; !ok {
|
if link, ok := builder.links[key]; !ok {
|
||||||
builder.links[key] = &GraphLink{
|
builder.links[key] = &GraphLink{
|
||||||
VPN: builder.isVPN(sourceId, targetId),
|
VPN: builder.isVPN(sourceID, targetID),
|
||||||
TQ: tq,
|
TQ: tq,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Use lowest of both link qualities
|
// Use lowest of both link qualities
|
||||||
|
@ -44,7 +44,7 @@ func NewNodes(config *Config) *Nodes {
|
|||||||
}
|
}
|
||||||
go nodes.worker()
|
go nodes.worker()
|
||||||
|
|
||||||
nodes.Version = 1
|
nodes.Version = 2
|
||||||
return nodes
|
return nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,9 +89,9 @@ func (nodes *Nodes) Update(nodeID string, res *data.ResponseData) {
|
|||||||
node.Statistics = val
|
node.Statistics = val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (nodes *Nodes) GetMeshviewer() *meshviewer.Nodes {
|
func (nodes *Nodes) GetNodesMini() *meshviewer.Nodes {
|
||||||
meshviewerNodes := &meshviewer.Nodes{
|
meshviewerNodes := &meshviewer.Nodes{
|
||||||
Version: nodes.Version,
|
Version: 1,
|
||||||
List: make(map[string]*meshviewer.Node),
|
List: make(map[string]*meshviewer.Node),
|
||||||
Timestamp: nodes.Timestamp,
|
Timestamp: nodes.Timestamp,
|
||||||
}
|
}
|
||||||
@ -144,7 +144,8 @@ func (nodes *Nodes) worker() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// serialize nodes
|
// serialize nodes
|
||||||
save(nodes.GetMeshviewer(), nodes.config.Nodes.NodesPath)
|
save(nodes, nodes.config.Nodes.NodesPath)
|
||||||
|
save(nodes.GetNodesMini(), nodes.config.Nodes.NodesMiniPath)
|
||||||
|
|
||||||
if path := nodes.config.Nodes.GraphsPath; path != "" {
|
if path := nodes.config.Nodes.GraphsPath; path != "" {
|
||||||
save(nodes.BuildGraph(), path)
|
save(nodes.BuildGraph(), path)
|
||||||
@ -159,39 +160,7 @@ func (nodes *Nodes) load() {
|
|||||||
log.Println("loading", path)
|
log.Println("loading", path)
|
||||||
|
|
||||||
if filedata, err := ioutil.ReadFile(path); err == nil {
|
if filedata, err := ioutil.ReadFile(path); err == nil {
|
||||||
meshviewerNodes := &meshviewer.Nodes{}
|
if err := json.Unmarshal(filedata, nodes); err == nil {
|
||||||
if err := json.Unmarshal(filedata, meshviewerNodes); err == nil {
|
|
||||||
nodes.Version = meshviewerNodes.Version
|
|
||||||
nodes.Timestamp = meshviewerNodes.Timestamp
|
|
||||||
nodes.List = make(map[string]*Node)
|
|
||||||
for nodeID, _ := range meshviewerNodes.List {
|
|
||||||
nodes.Lock()
|
|
||||||
node, _ := nodes.List[nodeID]
|
|
||||||
|
|
||||||
if node == nil {
|
|
||||||
node = &Node{
|
|
||||||
Firstseen: meshviewerNodes.List[nodeID].Firstseen,
|
|
||||||
Lastseen: meshviewerNodes.List[nodeID].Lastseen,
|
|
||||||
Flags: meshviewerNodes.List[nodeID].Flags,
|
|
||||||
Nodeinfo: meshviewerNodes.List[nodeID].Nodeinfo,
|
|
||||||
}
|
|
||||||
nodes.List[nodeID] = node
|
|
||||||
}
|
|
||||||
nodes.Unlock()
|
|
||||||
node.Statistics = &data.Statistics{
|
|
||||||
NodeId: meshviewerNodes.List[nodeID].Statistics.NodeId,
|
|
||||||
Clients: data.Clients{Total: meshviewerNodes.List[nodeID].Statistics.Clients},
|
|
||||||
Gateway: meshviewerNodes.List[nodeID].Statistics.Gateway,
|
|
||||||
RootFsUsage: meshviewerNodes.List[nodeID].Statistics.RootFsUsage,
|
|
||||||
LoadAverage: meshviewerNodes.List[nodeID].Statistics.LoadAverage,
|
|
||||||
Memory: meshviewerNodes.List[nodeID].Statistics.Memory,
|
|
||||||
Uptime: meshviewerNodes.List[nodeID].Statistics.Uptime,
|
|
||||||
Idletime: meshviewerNodes.List[nodeID].Statistics.Idletime,
|
|
||||||
Processes: meshviewerNodes.List[nodeID].Statistics.Processes,
|
|
||||||
MeshVpn: meshviewerNodes.List[nodeID].Statistics.MeshVpn,
|
|
||||||
Traffic: meshviewerNodes.List[nodeID].Statistics.Traffic,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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)
|
||||||
|
@ -19,7 +19,7 @@ type Collector struct {
|
|||||||
queue chan *Response // received responses
|
queue chan *Response // received responses
|
||||||
onReceive OnReceive
|
onReceive OnReceive
|
||||||
msgType reflect.Type
|
msgType reflect.Type
|
||||||
|
intface string
|
||||||
// Ticker and stopper
|
// Ticker and stopper
|
||||||
ticker *time.Ticker
|
ticker *time.Ticker
|
||||||
stop chan interface{}
|
stop chan interface{}
|
||||||
@ -28,7 +28,7 @@ type Collector struct {
|
|||||||
type OnReceive func(net.UDPAddr, *data.ResponseData)
|
type OnReceive func(net.UDPAddr, *data.ResponseData)
|
||||||
|
|
||||||
//NewCollector creates a Collector struct
|
//NewCollector creates a Collector struct
|
||||||
func NewCollector(CollectType string, interval time.Duration, onReceive OnReceive) *Collector {
|
func NewCollector(CollectType string, interval time.Duration, onReceive OnReceive, intface string) *Collector {
|
||||||
// Parse address
|
// Parse address
|
||||||
addr, err := net.ResolveUDPAddr("udp", "[::]:0")
|
addr, err := net.ResolveUDPAddr("udp", "[::]:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -49,6 +49,7 @@ func NewCollector(CollectType string, interval time.Duration, onReceive OnReceiv
|
|||||||
ticker: time.NewTicker(interval),
|
ticker: time.NewTicker(interval),
|
||||||
stop: make(chan interface{}, 1),
|
stop: make(chan interface{}, 1),
|
||||||
onReceive: onReceive,
|
onReceive: onReceive,
|
||||||
|
intface: intface,
|
||||||
}
|
}
|
||||||
|
|
||||||
go collector.receiver()
|
go collector.receiver()
|
||||||
@ -74,7 +75,7 @@ func (coll *Collector) Close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (coll *Collector) sendOnce() {
|
func (coll *Collector) sendOnce() {
|
||||||
coll.sendPacket(net.JoinHostPort(multiCastGroup, port))
|
coll.sendPacket(net.JoinHostPort(multiCastGroup+"%"+coll.intface, port))
|
||||||
log.Println("request", coll.CollectType)
|
log.Println("request", coll.CollectType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user