aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan-Philipp Litza <janphilipp@litza.de>2014-02-11 00:12:10 +0100
committerJan-Philipp Litza <janphilipp@litza.de>2014-02-16 16:54:10 +0100
commitca2ab676b39ff07a447f01b77c3d7692fa2aba0d (patch)
tree0f95c29f448356ef58f44831a6da7765ad2cbc3f
parent17fcf10b74fbda384e26ecb480b77c46a1a3dbc5 (diff)
Modularize global and node rrd definitions and graphings
-rw-r--r--GlobalRRD.py35
-rw-r--r--NodeRRD.py54
-rwxr-xr-xrrd.py90
3 files changed, 103 insertions, 76 deletions
diff --git a/GlobalRRD.py b/GlobalRRD.py
new file mode 100644
index 0000000..f3f3960
--- /dev/null
+++ b/GlobalRRD.py
@@ -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)
diff --git a/NodeRRD.py b/NodeRRD.py
new file mode 100644
index 0000000..f53cad6
--- /dev/null
+++ b/NodeRRD.py
@@ -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)
diff --git a/rrd.py b/rrd.py
index b28b2ea..5c3330d 100755
--- a/rrd.py
+++ b/rrd.py
@@ -2,7 +2,8 @@
import subprocess
import time
import os
-from RRD import RRD, DS, RRA
+from GlobalRRD import GlobalRRD
+from NodeRRD import NodeRRD
class rrd:
def __init__( self
@@ -12,7 +13,7 @@ class rrd:
, displayTimeNode = "1d"
):
self.dbPath = databaseDirectory
- self.globalDb = RRD(databaseDirectory + "/nodes.rrd")
+ self.globalDb = GlobalRRD(self.dbPath)
self.imagePath = imagePath
self.displayTimeGlobal = displayTimeGlobal
self.displayTimeNode = displayTimeNode
@@ -25,74 +26,6 @@ class rrd:
except:
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):
nodes = {}
clientCount = 0
@@ -113,15 +46,19 @@ class rrd:
elif target in nodes and not source in nodes:
nodes[target].clients += 1
- self.updateGlobalDatabase(len(nodes),clientCount)
- for mac in nodes:
- self.updateNodeDatabase(mac,nodes[mac].clients)
+ self.globalDb.update(len(nodes), clientCount)
+ for node in nodes.values():
+ rrd = NodeRRD(
+ os.path.join(self.dbPath, str(node.id).replace(':', '') + '.rrd'),
+ node
+ )
+ rrd.update()
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)
@@ -131,4 +68,5 @@ class rrd:
nodeName = os.path.basename(fileName).split('.')
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)