1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
#!/usr/bin/python
import subprocess
import os
import re
import sys
import json
TINC_NETWORK =os.environ.get("TINC_NETWORK","retiolum")
# is_legacy is the parameter which defines if the tinc config files are handled old fashioned (parse from syslog),
# or if the new and hip tincctl should be used
# Tags and Delimiters
TINC_TAG="tinc.%s" % TINC_NETWORK
BEGIN_NODES = "Nodes:"
END_NODES = "End of nodes."
BEGIN_SUBNET = "Subnet list:"
END_SUBNET = "End of subnet list"
BEGIN_EDGES = "Edges:"
END_EDGES = "End of edges."
def usage():
from sys import argv,exit
print("""usage: %s
This tool dumps all tinc node informations as json
ENVIRONMENT VARIABLES:
TINC_NETWORK The tinc network to dump
(default: retiolum)
LOG_FILE If legacy tinc is used, defines the log file where tinc stats are dumped in
(default: /var/log/everything.log)
""" % argv[0])
exit(1)
def debug(func):
from functools import wraps
@wraps(func)
def with_debug(*args,**kwargs):
print( func.__name__ + " (args: %s | kwargs %s)"% (args,kwargs))
return func(*args,**kwargs)
return with_debug
def get_tinc_log_file():
# TODO parse logfile from somewhere
return os.environ.get("LOG_FILE","/var/log/everything.log")
def parse_tinc_stats():
import subprocess
from time import sleep
from distutils.spawn import find_executable as which
#newest tinc
if which("tinc"):
return parse_new_input("tinc")
#new tinc
elif which("tincctl"):
return parse_new_input("tincctl")
#old tinc
elif which("tincd"):
# TODO refactor me
subprocess.call(["pkill","-SIGUSR2", "tincd"])
sleep(1)
return parse_input(get_tinc_block(get_tinc_log_file()))
#no tinc
else:
raise Exception("no tinc executable found!")
#@debug
def get_tinc_block(log_file):
""" returns an iterateable block from the given log file (syslog)
This function became obsolete with the introduction of tincctl
"""
from BackwardsReader import BackwardsReader
tinc_block = []
in_block = False
bf = BackwardsReader(log_file)
BOL = re.compile(".*tinc.%s\[[0-9]+\]: " % TINC_NETWORK)
while True:
line = bf.readline()
if not line:
raise Exception("end of file at log file? This should not happen!")
line = BOL.sub('',line).strip()
if END_SUBNET in line:
in_block = True
if not in_block:
continue
tinc_block.append(line)
if BEGIN_NODES in line:
break
return reversed(tinc_block)
def parse_new_input(tinc_bin):
nodes = {}
pnodes = subprocess.Popen([tinc_bin,"-n",TINC_NETWORK,"dump","reachable","nodes"], stdout=subprocess.PIPE).communicate()[0]
#pnodes = subprocess.check_output(["tincctl","-n",TINC_NETWORK,"dump","reachable","nodes"])
for line in pnodes.split('\n'):
if not line: continue
l = line.split()
nodes[l[0]]= { 'external-ip': l[2], 'external-port' : l[4] }
psubnets = subprocess.check_output([tinc_bin,"-n",TINC_NETWORK,"dump","subnets"])
for line in psubnets.split('\n'):
if not line: continue
l = line.split()
try:
if not nodes[l[2]].get('internal-ip',False):
nodes[l[2]]['internal-ip'] = []
nodes[l[2]]['internal-ip'].append(l[0].split('#')[0])
except KeyError:
pass # node does not exist (presumably)
pedges = subprocess.check_output([tinc_bin,"-n",TINC_NETWORK,"dump","edges"])
for line in pedges.split('\n'):
if not line: continue
l = line.split()
try:
if not nodes[l[0]].has_key('to') :
nodes[l[0]]['to'] = []
nodes[l[0]]['to'].append(
{'name':l[2],'addr':l[4],'port':l[6],'weight' : l[10] })
except KeyError:
pass #node does not exist
return nodes
#@debug
def parse_input(log_data):
nodes={}
for line in log_data:
if BEGIN_NODES in line :
nodes={}
for line in log_data:
if END_NODES in line :
break
l = line.replace('\n','').split() #TODO unhack me
nodes[l[0]]= { 'external-ip': l[2], 'external-port' : l[4] }
if BEGIN_SUBNET in line :
for line in log_data:
if END_SUBNET in line :
break
l = line.replace('\n','').split()
if not nodes[l[2]].get('internal-ip',False):
nodes[l[2]]['internal-ip'] = []
nodes[l[2]]['internal-ip'].append(l[0].split('#')[0])
if BEGIN_EDGES in line :
edges = {}
for line in log_data:
if END_EDGES in line :
break
l = line.replace('\n','').split()
if not nodes[l[0]].has_key('to') :
nodes[l[0]]['to'] = []
nodes[l[0]]['to'].append(
{'name':l[2],'addr':l[4],'port':l[6],'weight' : l[10] })
return nodes
if __name__ == '__main__':
# TODO refactor me
from sys import argv
if len(argv) > 1:
usage()
else:
print json.dumps(parse_tinc_stats())
|