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 import eventcalendar
50 from flumotion.component.base import scheduler
51
52
53 from flumotion.common import componentui
54
55 componentui
56
57 __version__ = "$Rev: 7587 $"
58
59
62
63
66
67
69 return source['sample-frequency']
70
71
73
74 def makeDS():
75 if source['is-gauge']:
76 return 'DS:%s:GAUGE:%d:U:U' % (source['name'],
77 2*source['sample-frequency'])
78 else:
79 return 'DS:%s:DERIVE:%d:0:U' % (source['name'],
80 2*source['sample-frequency'])
81 return source['rrd-ds-spec'] or makeDS()
82
83
85
86 def archiveGetRRA(archive):
87 return 'RRA:' + archive['rra-spec']
88 return [archiveGetRRA(archive) for archive in source['archives']]
89
90
93
94
96 return source['component-id']
97
98
100 return source['ui-state-key']
101
102
104 logName = 'rrdmon'
105
113
129
134
136 r = random.Random()
137 now = datetime.datetime.now(eventcalendar.LOCAL)
138
139 def eventInstanceStarted(eventInstance):
140 self.pollData(*eventInstance.event.content)
141
142 def eventStopped(eventInstance):
143 pass
144
145 self.scheduler.subscribe(eventInstanceStarted, eventInstanceStopped)
146
147 for source in sources:
148 freq = sourceGetSampleFrequency(source)
149
150
151 offset = datetime.timedelta(seconds=r.randint(0, freq))
152
153 data = (str(sourceGetConnectionInfo(source)),
154 sourceGetComponentId(source),
155 sourceGetUIStateKey(source),
156 sourceGetName(source),
157 sourceGetFileName(source))
158
159
160
161 calendar = eventcalendar.Calendar()
162 calendar.addEvent(now.isoformat(),
163 now + offset, now + offset + datetime.timedelta(seconds=1),
164 data, rrule=datetime.timedelta(seconds=freq))
165 self.scheduler.setCalendar(calendar)
166
167 - def pollData(self, managerId, componentId, uiStateKey, dsName,
168 rrdFile):
169
170 def stateListToDict(l):
171 return dict([(x.get('name'), x) for x in l])
172
173 if managerId in self.multi.admins:
174 admin = self.multi.admins[managerId]
175
176 flowName, componentName = common.parseComponentId(componentId)
177
178 flows = stateListToDict(admin.planet.get('flows'))
179 if flowName not in flows:
180 self.warning('not polling %s%s:%s: no such flow %s',
181 managerId, componentId, uiStateKey,
182 flowName)
183 return
184
185 components = stateListToDict(flows[flowName].get('components'))
186 if componentName not in components:
187 self.warning('not polling %s%s:%s: no such component %s',
188 managerId, componentId, uiStateKey,
189 componentId)
190 return
191
192 state = components[componentName]
193
194 def gotUIState(uiState):
195 if not uiState.hasKey(uiStateKey):
196 self.warning('while polling %s%s:%s: uiState has no '
197 'key %s', managerId, componentId,
198 uiStateKey, uiStateKey)
199 else:
200 try:
201 value = '%d:%s' % (int(time.time()),
202 uiState.get(uiStateKey))
203 self.log("polled %s%s:%s, updating ds %s = %s",
204 managerId, componentId, uiStateKey,
205 dsName, value)
206 rrdtool.update(rrdFile, "-t", dsName, value)
207 except rrdtool.error, e:
208 self.warning('error updating rrd file %s for '
209 '%s%s:%s', rrdFile, managerId,
210 componentId, uiStateKey)
211 self.debug('error reason: %s',
212 log.getExceptionMessage(e))
213
214 def errback(failure):
215 self.warning('not polling %s%s:%s: failed to get ui '
216 'state')
217 self.debug('reason: %s', log.getFailureMessage(failure))
218
219 d = admin.componentCallRemote(state, 'getUIState')
220 d.addCallbacks(gotUIState, errback)
221