Package flumotion :: Package admin :: Package rrdmon :: Module rrdmon
[hide private]

Source Code for Module flumotion.admin.rrdmon.rrdmon

  1  # -*- Mode: Python -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3  # 
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2004,2005,2006,2007 Fluendo, S.L. (www.fluendo.com). 
  6  # All rights reserved. 
  7   
  8  # This file may be distributed and/or modified under the terms of 
  9  # the GNU General Public License version 2 as published by 
 10  # the Free Software Foundation. 
 11  # This file is distributed without any warranty; without even the implied 
 12  # warranty of merchantability or fitness for a particular purpose. 
 13  # See "LICENSE.GPL" in the source distribution for more information. 
 14   
 15  # Licensees having purchased or holding a valid Flumotion Advanced 
 16  # Streaming Server license may use this file in accordance with the 
 17  # Flumotion Advanced Streaming Server Commercial License Agreement. 
 18  # See "LICENSE.Flumotion" in the source distribution for more information. 
 19   
 20  # Headers in this file shall remain intact. 
 21   
 22  """RRD resource poller daemon for Flumotion. 
 23   
 24  Makes periodic observations on components' UI states, recording them to 
 25  RRD files. One can then extract graphs using rrdtool graph. For example, 
 26  to show a stream bandwidth graph for the last 30 minutes with the 
 27  example configuration file, in the source tree as 
 28  conf/rrdmon/default.xml, the following command makes a graph: 
 29   
 30    rrdtool graph --end now --start end-30min --width 400 out.png \ 
 31       DEF:ds0=/tmp/stream-bitrate.rrd:http-streamer:AVERAGE \ 
 32       AREA:ds0#0000FF:"Stream bandwidth (bytes/sec)" 
 33   
 34  It would be possible to expose these graphs via HTTP, but I don't know 
 35  how useful this might be. 
 36   
 37  See L{flumotion.admin.rrdmon.config} for information on how to configure 
 38  the RRD resource poller. 
 39  """ 
 40   
 41  import os 
 42  import random 
 43  import rrdtool 
 44  import datetime 
 45  import time 
 46   
 47  from flumotion.admin import multi 
 48  from flumotion.common import log, common 
 49  from flumotion.common.eventcalendar import LOCAL 
 50  from flumotion.component.base import scheduler 
 51   
 52  # register the unjellyable 
 53  from flumotion.common import componentui 
 54   
 55  componentui # pyflakes 
 56   
 57  __version__ = "$Rev: 6995 $" 
 58   
59 -def sourceGetFileName(source):
60 return source['rrd-file']
61
62 -def sourceGetName(source):
63 return source['name']
64
65 -def sourceGetSampleFrequency(source):
66 return source['sample-frequency']
67
68 -def sourceGetDS(source):
69 def makeDS(): 70 if source['is-gauge']: 71 return 'DS:%s:GAUGE:%d:U:U' % (source['name'], 72 2*source['sample-frequency']) 73 else: 74 return 'DS:%s:DERIVE:%d:0:U' % (source['name'], 75 2*source['sample-frequency'])
76 return source['rrd-ds-spec'] or makeDS() 77
78 -def sourceGetRRAList(source):
79 def archiveGetRRA(archive): 80 return 'RRA:' + archive['rra-spec']
81 return [archiveGetRRA(archive) for archive in source['archives']] 82
83 -def sourceGetConnectionInfo(source):
84 return source['manager']
85
86 -def sourceGetComponentId(source):
87 return source['component-id']
88
89 -def sourceGetUIStateKey(source):
90 return source['ui-state-key']
91 92
93 -class RRDMonitor(log.Loggable):
94 logName = 'rrdmon' 95
96 - def __init__(self, sources):
97 self.debug('started rrd monitor') 98 self.multi = multi.MultiAdminModel() 99 self.scheduler = scheduler.Scheduler() 100 self.ensureRRDFiles(sources) 101 self.connectToManagers(sources) 102 self.startScheduler(sources)
103
104 - def ensureRRDFiles(self, sources):
105 for source in sources: 106 rrdfile = sourceGetFileName(source) 107 if not os.path.exists(rrdfile): 108 try: 109 self.info('Creating RRD file %s', rrdfile) 110 rrdtool.create(rrdfile, 111 "-s", str(sourceGetSampleFrequency(source)), 112 sourceGetDS(source), 113 *sourceGetRRAList(source)) 114 except rrdtool.error, e: 115 self.warning('Could not create RRD file %s', 116 rrdfile) 117 self.debug('Failure reason: %s', 118 log.getExceptionMessage(e))
119
120 - def connectToManagers(self, sources):
121 for source in sources: 122 connectionInfo = sourceGetConnectionInfo(source) 123 self.multi.addManager(connectionInfo, tenacious=True)
124
125 - def startScheduler(self, sources):
126 r = random.Random() 127 now = datetime.datetime.now(LOCAL) 128 129 def eventStarted(event): 130 self.pollData(*event.content)
131 def eventStopped(event): 132 pass
133 134 self.scheduler.subscribe(eventStarted, eventStopped) 135 136 for source in sources: 137 freq = sourceGetSampleFrequency(source) 138 139 # randomly offset the polling 140 offset = datetime.timedelta(seconds=r.randint(0,freq)) 141 142 data = (str(sourceGetConnectionInfo(source)), 143 sourceGetComponentId(source), 144 sourceGetUIStateKey(source), 145 sourceGetName(source), 146 sourceGetFileName(source)) 147 148 self.scheduler.addEvent(now.isoformat(), now+offset, 149 now+offset+datetime.timedelta(seconds=1), 150 data, 151 datetime.timedelta(seconds=freq)) 152
153 - def pollData(self, managerId, componentId, uiStateKey, dsName, 154 rrdFile):
155 def stateListToDict(l): 156 return dict([(x.get('name'), x) for x in l])
157 158 if managerId in self.multi.admins: 159 admin = self.multi.admins[managerId] 160 161 flowName, componentName = common.parseComponentId(componentId) 162 163 flows = stateListToDict(admin.planet.get('flows')) 164 if flowName not in flows: 165 self.warning('not polling %s%s:%s: no such flow %s', 166 managerId, componentId, uiStateKey, 167 flowName) 168 return 169 170 components = stateListToDict(flows[flowName].get('components')) 171 if componentName not in components: 172 self.warning('not polling %s%s:%s: no such component %s', 173 managerId, componentId, uiStateKey, 174 componentId) 175 return 176 177 state = components[componentName] 178 179 def gotUIState(uiState): 180 if not uiState.hasKey(uiStateKey): 181 self.warning('while polling %s%s:%s: uiState has no ' 182 'key %s', managerId, componentId, 183 uiStateKey, uiStateKey) 184 else: 185 try: 186 value = '%d:%s' % (int(time.time()), 187 uiState.get(uiStateKey)) 188 self.log("polled %s%s:%s, updating ds %s = %s", 189 managerId, componentId, uiStateKey, 190 dsName, value) 191 rrdtool.update(rrdFile, "-t", dsName, value) 192 except rrdtool.error, e: 193 self.warning('error updating rrd file %s for ' 194 '%s%s:%s', rrdFile, managerId, 195 componentId, uiStateKey) 196 self.debug('error reason: %s', 197 log.getExceptionMessage(e)) 198 199 def errback(failure): 200 self.warning('not polling %s%s:%s: failed to get ui ' 201 'state') 202 self.debug('reason: %s', log.getFailureMessage(failure)) 203 204 d = admin.componentCallRemote(state, 'getUIState') 205 d.addCallbacks(gotUIState, errback) 206