116 lines
4.4 KiB
Python
116 lines
4.4 KiB
Python
|
import os
|
||
|
import subprocess
|
||
|
from ffmap.node import Node
|
||
|
from . import RRD, DS, RRA
|
||
|
|
||
|
class NodeRRD(RRD):
|
||
|
ds_list = [
|
||
|
DS('upstate', 'GAUGE', 120, 0, 1),
|
||
|
DS('clients', 'GAUGE', 120, 0, float('NaN')),
|
||
|
DS('neighbors', 'GAUGE', 120, 0, float('NaN')),
|
||
|
DS('vpn_neighbors', 'GAUGE', 120, 0, float('NaN')),
|
||
|
DS('loadavg', 'GAUGE', 120, 0, float('NaN')),
|
||
|
DS('rx_bytes', 'DERIVE', 120, 0, float('NaN')),
|
||
|
DS('rx_packets', 'DERIVE', 120, 0, float('NaN')),
|
||
|
DS('tx_bytes', 'DERIVE', 120, 0, float('NaN')),
|
||
|
DS('tx_packets', 'DERIVE', 120, 0, float('NaN')),
|
||
|
DS('mgmt_rx_bytes', 'DERIVE', 120, 0, float('NaN')),
|
||
|
DS('mgmt_rx_packets', 'DERIVE', 120, 0, float('NaN')),
|
||
|
DS('mgmt_tx_bytes', 'DERIVE', 120, 0, float('NaN')),
|
||
|
DS('mgmt_tx_packets', 'DERIVE', 120, 0, float('NaN')),
|
||
|
DS('forward_bytes', 'DERIVE', 120, 0, float('NaN')),
|
||
|
DS('forward_packets', 'DERIVE', 120, 0, float('NaN')),
|
||
|
]
|
||
|
rra_list = [
|
||
|
RRA('AVERAGE', 0.5, 1, 120), # 2 hours of 1 minute samples
|
||
|
RRA('AVERAGE', 0.5, 5, 1440), # 5 days of 5 minute samples
|
||
|
RRA('AVERAGE', 0.5, 60, 720), # 30 days of 1 hour samples
|
||
|
RRA('AVERAGE', 0.5, 720, 730), # 1 year of 12 hour samples
|
||
|
]
|
||
|
|
||
|
def __init__(self, filename, node = None):
|
||
|
"""
|
||
|
Create a new RRD for a given node.
|
||
|
|
||
|
If the RRD isn't supposed to be updated, the node can be omitted.
|
||
|
"""
|
||
|
self.node = node
|
||
|
super().__init__(filename)
|
||
|
self.ensureSanity(self.ds_list, self.rra_list, step=60)
|
||
|
|
||
|
@property
|
||
|
def imagename(self):
|
||
|
return os.path.basename(self.filename).rsplit('.', 2)[0] + ".png"
|
||
|
|
||
|
def update(self):
|
||
|
values = {
|
||
|
'upstate': 1,
|
||
|
'clients': float(len(self.node.get('clients', []))),
|
||
|
'neighbors': float(len(self.node.get('neighbors', []))),
|
||
|
'vpn_neighbors': float(len(self.node.vpn_neighbors)),
|
||
|
'loadavg': float(self.node['statistics']['loadavg']),
|
||
|
}
|
||
|
for item in ('rx', 'tx', 'mgmt_rx', 'mgmt_tx', 'forward'):
|
||
|
try:
|
||
|
values[item + '_bytes'] = int(self.node['statistics']['traffic'][item]['bytes'])
|
||
|
except TypeError:
|
||
|
pass
|
||
|
try:
|
||
|
values[item + '_packets'] = int(self.node['statistics']['traffic'][item]['packets'])
|
||
|
except TypeError:
|
||
|
pass
|
||
|
super().update(values)
|
||
|
|
||
|
def graph(self, directory, timeframe):
|
||
|
"""
|
||
|
Create a graph in the given directory. The file will be named
|
||
|
basename.png if the RRD file is named basename.rrd
|
||
|
"""
|
||
|
args = ['rrdtool','graph', os.path.join(directory, self.imagename),
|
||
|
'-s', '-' + timeframe ,
|
||
|
'-w', '800',
|
||
|
'-h', '400',
|
||
|
'-l', '0',
|
||
|
'-y', '1:1',
|
||
|
'DEF:clients=' + self.filename + ':clients:AVERAGE',
|
||
|
'VDEF:maxc=clients,MAXIMUM',
|
||
|
'CDEF:c=0,clients,ADDNAN',
|
||
|
'CDEF:d=clients,UN,maxc,UN,1,maxc,IF,*',
|
||
|
'AREA:c#0F0:up\\l',
|
||
|
'AREA:d#F00:down\\l',
|
||
|
'LINE1:c#00F:clients connected\\l',
|
||
|
]
|
||
|
subprocess.check_output(args)
|
||
|
|
||
|
class GlobalRRD(RRD):
|
||
|
ds_list = [
|
||
|
# Number of nodes available
|
||
|
DS('nodes', 'GAUGE', 120, 0, float('NaN')),
|
||
|
# Number of client available
|
||
|
DS('clients', 'GAUGE', 120, 0, float('NaN')),
|
||
|
]
|
||
|
rra_list = [
|
||
|
RRA('AVERAGE', 0.5, 1, 120), # 2 hours of 1 minute samples
|
||
|
RRA('AVERAGE', 0.5, 60, 744), # 31 days of 1 hour samples
|
||
|
RRA('AVERAGE', 0.5, 1440, 1780),# ~5 years of 1 day samples
|
||
|
]
|
||
|
|
||
|
def __init__(self, filepath):
|
||
|
super().__init__(filepath)
|
||
|
self.ensureSanity(self.ds_list, self.rra_list, step=60)
|
||
|
|
||
|
def update(self, nodeCount, clientCount):
|
||
|
super().update({'nodes': nodeCount, 'clients': clientCount})
|
||
|
|
||
|
def graph(self, filename, timeframe):
|
||
|
args = ["rrdtool", 'graph', filename,
|
||
|
'-s', '-' + timeframe,
|
||
|
'-w', '800',
|
||
|
'-h' '400',
|
||
|
'DEF:nodes=' + self.filename + ':nodes:AVERAGE',
|
||
|
'LINE1:nodes#F00:nodes\\l',
|
||
|
'DEF:clients=' + self.filename + ':clients:AVERAGE',
|
||
|
'LINE2:clients#00F:clients',
|
||
|
]
|
||
|
subprocess.check_output(args)
|