Modularize global and node rrd definitions and graphings
This commit is contained in:
parent
17fcf10b74
commit
ca2ab676b3
35
GlobalRRD.py
Normal file
35
GlobalRRD.py
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from RRD import RRD, DS, RRA
|
||||||
|
|
||||||
|
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, directory):
|
||||||
|
super().__init__(os.path.join(directory, "nodes.rrd"))
|
||||||
|
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)
|
54
NodeRRD.py
Normal file
54
NodeRRD.py
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from node import Node
|
||||||
|
from RRD import RRD, DS, RRA
|
||||||
|
|
||||||
|
class NodeRRD(RRD):
|
||||||
|
ds_list = [
|
||||||
|
DS('upstate', 'GAUGE', 120, 0, 1),
|
||||||
|
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, 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):
|
||||||
|
super().update({'upstate': 1, 'clients': self.node.clients})
|
||||||
|
|
||||||
|
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)
|
90
rrd.py
90
rrd.py
|
@ -2,7 +2,8 @@
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
from RRD import RRD, DS, RRA
|
from GlobalRRD import GlobalRRD
|
||||||
|
from NodeRRD import NodeRRD
|
||||||
|
|
||||||
class rrd:
|
class rrd:
|
||||||
def __init__( self
|
def __init__( self
|
||||||
|
@ -12,7 +13,7 @@ class rrd:
|
||||||
, displayTimeNode = "1d"
|
, displayTimeNode = "1d"
|
||||||
):
|
):
|
||||||
self.dbPath = databaseDirectory
|
self.dbPath = databaseDirectory
|
||||||
self.globalDb = RRD(databaseDirectory + "/nodes.rrd")
|
self.globalDb = GlobalRRD(self.dbPath)
|
||||||
self.imagePath = imagePath
|
self.imagePath = imagePath
|
||||||
self.displayTimeGlobal = displayTimeGlobal
|
self.displayTimeGlobal = displayTimeGlobal
|
||||||
self.displayTimeNode = displayTimeNode
|
self.displayTimeNode = displayTimeNode
|
||||||
|
@ -25,74 +26,6 @@ class rrd:
|
||||||
except:
|
except:
|
||||||
os.mkdir(self.imagePath)
|
os.mkdir(self.imagePath)
|
||||||
|
|
||||||
def updateGlobalDatabase(self,nodeCount,clientCount):
|
|
||||||
""" Adds a new (#Nodes,#Clients) entry to the global database.
|
|
||||||
"""
|
|
||||||
self.globalDb.ensureSanity(
|
|
||||||
[
|
|
||||||
# Number of nodes available
|
|
||||||
DS('nodes', 'GAUGE', 120, 0, float('NaN')),
|
|
||||||
# Number of client available
|
|
||||||
DS('clients', 'GAUGE', 120, 0, float('NaN')),
|
|
||||||
], [
|
|
||||||
RRA('LAST', 0, 1, 44640),
|
|
||||||
RRA('LAST', 0, 60, 744),
|
|
||||||
RRA('LAST', 0, 1440, 1780),
|
|
||||||
],
|
|
||||||
step=60,
|
|
||||||
)
|
|
||||||
self.globalDb.update({'nodes': nodeCount, 'clients': clientCount})
|
|
||||||
|
|
||||||
def createGlobalGraph(self):
|
|
||||||
nodeGraph = self.imagePath + "/" + "globalGraph.png"
|
|
||||||
args = ["rrdtool", 'graph', nodeGraph, '-s', '-' + self.displayTimeGlobal, '-w', '800', '-h' '400'
|
|
||||||
,'DEF:nodes=' + self.globalDb.filename + ':nodes:AVERAGE', 'LINE1:nodes#F00:nodes\\l'
|
|
||||||
,'DEF:clients=' + self.globalDb.filename + ':clients:AVERAGE','LINE2:clients#00F:clients'
|
|
||||||
]
|
|
||||||
subprocess.check_output(args)
|
|
||||||
|
|
||||||
|
|
||||||
def nodeMACToRRDFile(self,nodeMAC):
|
|
||||||
return self.dbPath + "/" + str(nodeMAC).replace(":","") + ".rrd"
|
|
||||||
|
|
||||||
def nodeMACToPNGFile(self,nodeMAC):
|
|
||||||
return self.imagePath + "/" + str(nodeMAC).replace(":","") + ".png"
|
|
||||||
|
|
||||||
# Call only if node is up
|
|
||||||
def updateNodeDatabase(self,nodePrimaryMAC,clientCount):
|
|
||||||
# TODO check for bad nodeNames
|
|
||||||
nodeFile = self.nodeMACToRRDFile(nodePrimaryMAC)
|
|
||||||
nodeRRD = RRD(nodeFile)
|
|
||||||
nodeRRD.ensureSanity(
|
|
||||||
[
|
|
||||||
DS('upstate', 'GAUGE', 120, 0, 1),
|
|
||||||
DS('clients', 'GAUGE', 120, 0, float('NaN')),
|
|
||||||
], [
|
|
||||||
RRA('LAST', 0, 1, 44640),
|
|
||||||
],
|
|
||||||
step=60,
|
|
||||||
)
|
|
||||||
# Update Global RRDatabase
|
|
||||||
args = ["rrdtool",'updatev', nodeFile
|
|
||||||
# #Upstate #Clients
|
|
||||||
, self.currentTime + ":"+str(1)+":"+str(clientCount)
|
|
||||||
]
|
|
||||||
subprocess.check_output(args)
|
|
||||||
|
|
||||||
def createNodeGraph(self,nodePrimaryMAC):
|
|
||||||
nodeGraph = self.nodeMACToPNGFile(nodePrimaryMAC)
|
|
||||||
nodeFile = self.nodeMACToRRDFile(nodePrimaryMAC)
|
|
||||||
args = ['rrdtool','graph', nodeGraph, '-s', '-' + self.displayTimeNode , '-w', '800', '-h', '400', '-l', '0', '-y', '1:1',
|
|
||||||
'DEF:clients=' + nodeFile + ':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)
|
|
||||||
|
|
||||||
def update_database(self,db):
|
def update_database(self,db):
|
||||||
nodes = {}
|
nodes = {}
|
||||||
clientCount = 0
|
clientCount = 0
|
||||||
|
@ -113,15 +46,19 @@ class rrd:
|
||||||
elif target in nodes and not source in nodes:
|
elif target in nodes and not source in nodes:
|
||||||
nodes[target].clients += 1
|
nodes[target].clients += 1
|
||||||
|
|
||||||
self.updateGlobalDatabase(len(nodes),clientCount)
|
self.globalDb.update(len(nodes), clientCount)
|
||||||
for mac in nodes:
|
for node in nodes.values():
|
||||||
self.updateNodeDatabase(mac,nodes[mac].clients)
|
rrd = NodeRRD(
|
||||||
|
os.path.join(self.dbPath, str(node.id).replace(':', '') + '.rrd'),
|
||||||
|
node
|
||||||
|
)
|
||||||
|
rrd.update()
|
||||||
|
|
||||||
def update_images(self):
|
def update_images(self):
|
||||||
""" Creates a image for every rrd file in the database directory.
|
""" Creates an image for every rrd file in the database directory.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.createGlobalGraph()
|
self.globalDb.graph(os.path.join(self.imagePath, "globalGraph.png"), self.displayTimeGlobal)
|
||||||
|
|
||||||
nodeDbFiles = os.listdir(self.dbPath)
|
nodeDbFiles = os.listdir(self.dbPath)
|
||||||
|
|
||||||
|
@ -131,4 +68,5 @@ class rrd:
|
||||||
|
|
||||||
nodeName = os.path.basename(fileName).split('.')
|
nodeName = os.path.basename(fileName).split('.')
|
||||||
if nodeName[1] == 'rrd' and not nodeName[0] == "nodes":
|
if nodeName[1] == 'rrd' and not nodeName[0] == "nodes":
|
||||||
self.createNodeGraph(nodeName[0])
|
rrd = NodeRRD(os.path.join(self.dbPath, fileName))
|
||||||
|
rrd.graph(self.imagePath, self.displayTimeNode)
|
||||||
|
|
Loading…
Reference in a new issue