1
2
3
4
5
6
7
8
9
10
11
12
13
14 import types
15 import time
16
17 import logging
18 log = logging.getLogger("zen.RRDView")
19
20 from Acquisition import aq_chain
21
22 from Products.ZenRRD.RRDUtil import convertToRRDTime
23 from Products.ZenUtils import Map
24 from Products.ZenWidgets import messaging
25
26 from Products.ZenModel.ConfigurationError import ConfigurationError
27
28 CACHE_TIME = 60.
29
30 _cache = Map.Locked(Map.Timed({}, CACHE_TIME))
31
38
39
41
42
44 """
45 Mixin to provide hooks to RRD management functions
46 """
47
67
69 "read an RRDValue with and cache it"
70 filename = self.getRRDFileName(dsname)
71 value = None
72 try:
73 value = _cache[filename]
74 if value is None:
75 return default
76 except KeyError:
77 pass
78 try:
79 value = self.getRRDValue(dsname)
80 except Exception:
81 log.error('Unable to cache value for %s', dsname)
82 _cache[filename] = value
83 if value is None:
84 return default
85 return value
86
87
88 - def getRRDValue(self, dsname, start=None, end=None, function="LAST",
89 format="%.2lf", extraRpn=""):
90 """Return a single rrd value from its file using function.
91 """
92 dsnames = (dsname,)
93 results = self.getRRDValues(
94 dsnames, start, end, function, format, extraRpn)
95 if dsname in results:
96 return results[dsname]
97
98
104
105
114
115
122
123
129
130
131 - def getRRDValues(self, dsnames, start=None, end=None, function="LAST",
132 format="%.2lf", extraRpn=""):
133 """
134 Return a dict of key value pairs where dsnames are the keys.
135 """
136 try:
137 if not start:
138 start = time.time() - self.defaultDateRange
139 gopts = []
140 names = list(dsnames[:])
141 for dsname in dsnames:
142 for dp in self.getRRDDataPoints():
143 if dp.name().find(dsname) > -1:
144 break
145 else:
146 names.remove(dsname)
147 continue
148 filename = self.getRRDFileName(dp.name())
149 rpn = str(dp.rpn)
150 if rpn:
151 rpn = "," + rpn
152 if extraRpn:
153 rpn = rpn + "," + extraRpn
154
155 gopts.append("DEF:%s_r=%s:ds0:AVERAGE" % (dsname,filename))
156 gopts.append("CDEF:%s_c=%s_r%s" % (dsname,dsname,rpn))
157 gopts.append("VDEF:%s=%s_c,%s" % (dsname,dsname,function))
158 gopts.append("PRINT:%s:%s" % (dsname, format))
159 gopts.append("--start=%s" % convertToRRDTime(start))
160 if end:
161 gopts.append("--end=%s" % convertToRRDTime(end))
162 if not names:
163 return {}
164 perfServer = self.device().getPerformanceServer()
165 vals = []
166 if perfServer:
167 vals = perfServer.performanceCustomSummary(gopts)
168 if vals is None:
169 vals = [None] * len(dsnames)
170 def cvt(val):
171 if val is None or val.lower() == "nan":
172 return None
173 return float(val)
174 return dict(zip(names, map(cvt, vals)))
175 except Exception, ex:
176 log.exception(ex)
177
178
179
180 - def getRRDSum(self, points, start=None, end=None, function="LAST"):
181 "Return a some of listed datapoints."
182
183 try:
184 if not start:
185 start = time.time() - self.defaultDateRange
186 if not end:
187 end = time.time()
188 gopts = []
189 for name in points:
190 for dp in self.getRRDDataPoints():
191 if dp.name().find(name) > -1:
192 break
193 else:
194 raise RRDViewError("Unable to find data point %s" % name)
195 filename = self.getRRDFileName(dp.name())
196 rpn = str(dp.rpn)
197 if rpn:
198 rpn = "," + rpn
199 gopts.append("DEF:%s_r=%s:ds0:AVERAGE" % (name, filename))
200 gopts.append("CDEF:%s=%s_r%s" % (name, name, rpn))
201 gopts.append("CDEF:sum=%s%s" % (','.join(points),
202 ',+'*(len(points)-1)))
203 gopts.append("VDEF:agg=sum,%s" % function)
204 gopts.append("PRINT:agg:%.2lf")
205 gopts.append("--start=%d" % start)
206 gopts.append("--end=%d" % end)
207 perfServer = self.device().getPerformanceServer()
208 if perfServer:
209 vals = perfServer.performanceCustomSummary(gopts)
210 if vals is None:
211 return None
212 return float(vals[0])
213 except Exception, ex:
214 log.exception(ex)
215
216
230
231
233 ''' Fetch a graph by id. if not found return None
234 '''
235 for t in self.getRRDTemplates():
236 for g in t.getGraphDefs():
237 if g.id == graphId:
238 return g
239 return None
240
241
243 """Return the target type name of this component. By default meta_type.
244 Override to create custom type selection.
245 """
246 return self.meta_type
247
248
250 """Look up an rrd file based on its data point name"""
251 names = [p.name() for p in self.getRRDDataPoints()
252 if p.name().endswith(dsname)]
253 if names:
254 return '%s/%s.rrd' % (self.rrdPath(), names[0])
255 else:
256 return '%s/%s.rrd' % (self.rrdPath(), dsname)
257
258
261
264
266 """Should this component be monitored for performance using snmp.
267 """
268 return False
269
275
277 try:
278 return self.getRRDTemplates()[0]
279 except IndexError:
280 return None
281
283 "Return the template of the given name."
284 try:
285 return self._getOb(name)
286 except AttributeError:
287 pass
288 for obj in aq_chain(self):
289 try:
290 return obj.rrdTemplates._getOb(name)
291 except AttributeError:
292 pass
293 return None
294
295
297 """Return a dictionary where keys are dsnames and values are thresholds.
298 """
299 result = {}
300 for thresh in templ.thresholds():
301 if not thresh.enabled: continue
302 for dsname in thresh.dsnames:
303 threshdef = result.setdefault(dsname, [])
304 threshdef.append(thresh.getConfig(self))
305 return result
306
307
310
311
315
316 - def getRRDContextData(self, context):
318
320 from Products.ZenEvents.Exceptions import pythonThresholdException
321 result = []
322 for template in self.getRRDTemplates():
323
324
325 names = []
326 for ds in template.getRRDDataSources(dsType):
327 for dp in ds.datapoints():
328 names.append(dp.name())
329 for threshold in template.thresholds():
330 if not threshold.enabled: continue
331 for ds in threshold.dsnames:
332 if ds in names:
333 try:
334 thresh = threshold.createThresholdInstance(self)
335 result.append(thresh)
336 except pythonThresholdException, ex:
337 import transaction
338 trans = transaction.get()
339 threshold.manage_changeProperties(enabled=False)
340 trans.setUser('zenhub')
341 trans.note("Disabled threshold as it has errors.")
342 trans.commit()
343
344 log.warn(ex)
345 log.info("Disabled threshold %s", threshold.id)
346
347 zem = self.primaryAq().getEventManager()
348 import socket
349 device = socket.gethostname()
350 path = template.absolute_url_path()
351 msg = \
352 "The threshold %s in template %s has been disabled." % (threshold.id, path)
353 evt = dict(summary=str(ex), severity=3,
354 component='zenhub', message=msg,
355 dedupid='zenhub|' + str(ex),
356 template=path,
357 threshold=threshold.id,
358 device=device, eventClass="/Status/Update",)
359 zem.sendEvent(evt)
360 break
361 return result
362
363
378
379
392
393
396