1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import os
24 import random
25 import rrdtool
26 import datetime
27 import time
28
29 from dateutil import rrule
30
31 from flumotion.admin import multi
32 from flumotion.common import log, common
33 from flumotion.component.base import scheduler
34
35
36 from flumotion.common import componentui
37
38
39 """RRD resource poller daemon for Flumotion.
40
41 Makes periodic observations on components' UI states, recording them to
42 RRD files. One can then extract graphs using rrdtool graph. For example,
43 to show a stream bandwidth graph for the last 30 minutes with the
44 example configuration file, in the source tree as
45 conf/rrdmon/default.xml, the following command makes a graph:
46
47 rrdtool graph --end now --start end-30min --width 400 out.png \
48 DEF:ds0=/tmp/stream-bitrate.rrd:http-streamer:AVERAGE \
49 AREA:ds0#0000FF:"Stream bandwidth (bytes/sec)"
50
51 It would be possible to expose these graphs via HTTP, but I don't know
52 how useful this might be.
53
54 See L{flumotion.admin.rrdmon.config} for information on how to configure
55 the RRD resource poller.
56 """
57
58
61
64
66 return source['sample-frequency']
67
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
79 def archiveGetRRA(archive):
80 return 'RRA:' + archive['rra-spec']
81 return [archiveGetRRA(archive) for archive in source['archives']]
82
85
87 return source['component-id']
88
90 return source['ui-state-key']
91
92
94 logName = 'rrdmon'
95
103
119
124
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
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+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