1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
53 from flumotion.common import componentui
54
55 componentui
56
57 __version__ = "$Rev: 6995 $"
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
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
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