early respondc support

respondd
Your Name 2015-08-08 12:49:52 +02:00 committed by Nils Schneider
parent d889c93f28
commit 238aaccabf
4 changed files with 76 additions and 15 deletions

View File

@ -22,6 +22,7 @@ For the script's regular execution add the following to the crontab:
- Python 3 - Python 3
- Python 3 Package [Networkx](https://networkx.github.io/) - Python 3 Package [Networkx](https://networkx.github.io/)
- Python 3 Package dateutil
- [alfred-json](https://github.com/tcatm/alfred-json) - [alfred-json](https://github.com/tcatm/alfred-json)
- rrdtool (if run with `--with-rrd`) - rrdtool (if run with `--with-rrd`)

View File

@ -7,6 +7,7 @@ import argparse
import json import json
import os import os
import sys import sys
import dateutil.parser
from datetime import datetime from datetime import datetime
import networkx as nx import networkx as nx
@ -18,12 +19,29 @@ from lib.batman import Batman
from lib.rrddb import RRD from lib.rrddb import RRD
from lib.nodelist import export_nodelist from lib.nodelist import export_nodelist
from lib.validate import validate_nodeinfos from lib.validate import validate_nodeinfos
from lib.respondc import request
NODES_VERSION = 2 NODES_VERSION = 2
GRAPH_VERSION = 1 GRAPH_VERSION = 1
def recently_lost_nodes(now, nodesdict, maxage=600):
nodes = []
for node in nodesdict.values():
lastseen = dateutil.parser.parse(node['lastseen'])
age = (now - lastseen).total_seconds()
if age < maxage and age != 0:
nodes.append(node)
return nodes
def main(params): def main(params):
def node_to_ips(node):
try:
return node['nodeinfo']['network']['addresses']
except KeyError:
return []
os.makedirs(params['dest_dir'], exist_ok=True) os.makedirs(params['dest_dir'], exist_ok=True)
nodes_fn = os.path.join(params['dest_dir'], 'nodes.json') nodes_fn = os.path.join(params['dest_dir'], 'nodes.json')
@ -68,19 +86,55 @@ def main(params):
# update timestamp and assume all nodes are offline # update timestamp and assume all nodes are offline
nodedb['timestamp'] = now.isoformat() nodedb['timestamp'] = now.isoformat()
for node in nodedb['nodes']:
node['flags']['online'] = False
nodesdict = {} nodesdict = {}
nodesdict, graph = DO(params, nodesdict, graph)
for node in nodedb['nodes']: for node in nodedb['nodes']:
nodesdict[node['nodeinfo']['node_id']] = node nodesdict[node['nodeinfo']['node_id']] = node
# integrate alfred nodeinfo # integrate alfred nodeinfo
for alfred in alfred_instances: for alfred in alfred_instances:
nodeinfo = validate_nodeinfos(alfred.nodeinfo()) nodeinfo = validate_nodeinfos(alfred.nodeinfo())
nodes.import_nodeinfo(nodesdict, nodeinfo, nodes.import_nodeinfo(nodesdict, nodeinfo, now, assume_online=True)
now, assume_online=True)
# acquire data from respondd
responses = list(request('nodeinfo statistics', ['ff02::2:1001'], interface=params['interface']))
nodeinfos = list(map(lambda x: x['nodeinfo'], filter(lambda x: 'nodeinfo' in x, responses)))
nodes.import_nodeinfo(nodesdict, validate_nodeinfos(nodeinfos), now, assume_online=True)
ips = [i[0] for i in map(node_to_ips, recently_lost_nodes(now, nodesdict))]
a = request('nodeinfo statistics', ips, interface=params['interface'], timeout=2)
nodeinfos = list(map(lambda x: x['nodeinfo'], filter(lambda x: 'nodeinfo' in x, a)))
nodes.import_nodeinfo(nodesdict, validate_nodeinfos(nodeinfos), now, assume_online=True)
responses += a
ips = [i[0] for i in map(node_to_ips, recently_lost_nodes(now, nodesdict))]
a = request('nodeinfo statistics', ips, interface=params['interface'], timeout=2)
nodeinfos = list(map(lambda x: x['nodeinfo'], filter(lambda x: 'nodeinfo' in x, a)))
nodes.import_nodeinfo(nodesdict, validate_nodeinfos(nodeinfos), now, assume_online=True)
responses += a
ips = [i[0] for i in map(node_to_ips, recently_lost_nodes(now, nodesdict))]
a = request('nodeinfo statistics', ips, interface=params['interface'], timeout=2)
nodeinfos = list(map(lambda x: x['nodeinfo'], filter(lambda x: 'nodeinfo' in x, a)))
nodes.import_nodeinfo(nodesdict, validate_nodeinfos(nodeinfos), now, assume_online=True)
responses += a
for node in nodesdict.values():
lastseen = dateutil.parser.parse(node['lastseen'])
age = (now - lastseen).total_seconds()
online = age < params['hysteresis']
node['flags']['online'] = online
if not online:
nodes.reset_statistics(node)
# integrate static aliases data # integrate static aliases data
for aliases in params['aliases']: for aliases in params['aliases']:
@ -89,10 +143,11 @@ def main(params):
nodes.import_nodeinfo(nodesdict, nodeinfo, nodes.import_nodeinfo(nodesdict, nodeinfo,
now, assume_online=False) now, assume_online=False)
nodes.reset_statistics(nodesdict)
for alfred in alfred_instances: for alfred in alfred_instances:
nodes.import_statistics(nodesdict, alfred.statistics()) nodes.import_statistics(nodesdict, alfred.statistics())
nodes.import_statistics(nodesdict, list(map(lambda x: x['statistics'], filter(lambda x: 'statistics' in x, responses))))
# acquire visdata for each batman instance # acquire visdata for each batman instance
mesh_info = [] mesh_info = []
for batman in batman_instances: for batman in batman_instances:
@ -104,7 +159,6 @@ def main(params):
for vd in mesh_info: for vd in mesh_info:
nodes.import_mesh_ifs_vis_data(nodesdict, vd) nodes.import_mesh_ifs_vis_data(nodesdict, vd)
nodes.import_vis_clientcount(nodesdict, vd) nodes.import_vis_clientcount(nodesdict, vd)
nodes.mark_vis_data_online(nodesdict, vd, now)
# clear the nodedb from nodes that have not been online in $prune days # clear the nodedb from nodes that have not been online in $prune days
if params['prune']: if params['prune']:
@ -166,10 +220,15 @@ if __name__ == '__main__':
help='Read aliases from FILE', help='Read aliases from FILE',
nargs='+', default=[], metavar='FILE') nargs='+', default=[], metavar='FILE')
parser.add_argument('-m', '--mesh', parser.add_argument('-m', '--mesh',
default=['bat0'], nargs='+', default=[], nargs='+',
help='Use given batman-adv mesh interface(s) (defaults' help='Use given batman-adv mesh interface(s) (defaults'
'to bat0); specify alfred unix socket like ' 'to bat0); specify alfred unix socket like '
'bat0:/run/alfred0.sock.') 'bat0:/run/alfred0.sock.')
parser.add_argument('--hysteresis', default=300,
help='Duration (seconds) after which a node is considered to be offline')
parser.add_argument('-i', '--interface',
help='Interface for contacting respondd',
required=True)
parser.add_argument('-d', '--dest-dir', action='store', parser.add_argument('-d', '--dest-dir', action='store',
help='Write output to destination directory', help='Write output to destination directory',
required=True) required=True)

View File

@ -53,7 +53,6 @@ def prune_nodes(nodes, now, days):
def mark_online(node, now): def mark_online(node, now):
node['lastseen'] = now.isoformat() node['lastseen'] = now.isoformat()
node.setdefault('firstseen', now.isoformat()) node.setdefault('firstseen', now.isoformat())
node['flags']['online'] = True
def import_nodeinfo(nodes, nodeinfos, now, assume_online=False): def import_nodeinfo(nodes, nodeinfos, now, assume_online=False):
@ -66,9 +65,8 @@ def import_nodeinfo(nodes, nodeinfos, now, assume_online=False):
mark_online(node, now) mark_online(node, now)
def reset_statistics(nodes): def reset_statistics(node):
for node in nodes.values(): node['statistics'] = {'clients': 0}
node['statistics'] = {'clients': 0}
def import_statistics(nodes, stats): def import_statistics(nodes, stats):

View File

@ -4,18 +4,21 @@ import zlib
import json import json
import sys import sys
def request(ifname, request, target='ff02::2', timeout=0.5, singleshot=False):
def request(request, targets, interface, timeout=0.5, singleshot=False):
try: try:
if_id = socket.if_nametoindex(ifname) if_id = socket.if_nametoindex(interface)
except OSError: except OSError:
print('interface \'{}\' not found'.format(sys.argv[1]), file=sys.stderr) print('interface \'{}\' not found'.format(ifname), file=sys.stderr)
return [] return []
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
# request # request
message = bytes('GET {}'.format(request), 'utf-8') message = bytes('GET {}'.format(request), 'utf-8')
sock.sendto(message, (target, 1001, 0, if_id))
for target in targets:
sock.sendto(message, (target, 1001, 0, if_id))
print('+ {:s}'.format(str(message)), file=sys.stderr) print('+ {:s}'.format(str(message)), file=sys.stderr)