multi nodes

This commit is contained in:
Martin Geno 2016-06-16 18:03:45 +02:00
parent 83dd82e6d2
commit 67c6031fff
6 changed files with 73 additions and 103 deletions

View File

@ -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
View File

@ -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)))

View File

@ -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"`

View File

@ -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

View File

@ -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)

View File

@ -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)
} }