Package Products :: Package ZenModel :: Module RRDView
[hide private]
[frames] | no frames]

Source Code for Module Products.ZenModel.RRDView

  1  ############################################################################## 
  2  #  
  3  # Copyright (C) Zenoss, Inc. 2007, all rights reserved. 
  4  #  
  5  # This content is made available according to terms specified in 
  6  # License.zenoss under the directory where your Zenoss product is installed. 
  7  #  
  8  ############################################################################## 
  9   
 10   
 11  import time 
 12   
 13  import logging 
 14  log = logging.getLogger("zen.RRDView") 
 15   
 16  from Acquisition import aq_chain 
 17   
 18  from Products.ZenRRD.RRDUtil import convertToRRDTime 
 19  from Products.ZenUtils import Map 
 20  from Products.ZenWidgets import messaging 
 21   
 22  from Products.ZenModel.ConfigurationError import ConfigurationError 
 23   
 24  CACHE_TIME = 60. 
 25   
 26  _cache = Map.Locked(Map.Timed({}, CACHE_TIME)) 
 27   
28 -def GetRRDPath(deviceOrComponent):
29 d = deviceOrComponent.device() 30 if not d: 31 return "Devices/" + deviceOrComponent.id 32 skip = len(d.getPrimaryPath()) - 1 33 return 'Devices/' + '/'.join(deviceOrComponent.getPrimaryPath()[skip:])
34 35
36 -class RRDViewError(Exception): pass
37 38
39 -class RRDView(object):
40 """ 41 Mixin to provide hooks to RRD management functions 42 """ 43
44 - def getGraphDefUrl(self, graph, drange=None, template=None):
45 """resolve template and graph names to objects 46 and pass to graph performance""" 47 if not drange: drange = self.defaultDateRange 48 templates = self.getRRDTemplates() 49 if template: 50 templates = [template] 51 if isinstance(graph, basestring): 52 for t in templates: 53 if hasattr(t.graphDefs, graph): 54 template = t 55 graph = getattr(t.graphDefs, graph) 56 break 57 targetpath = self.rrdPath() 58 objpaq = self.primaryAq() 59 perfServer = objpaq.device().getPerformanceServer() 60 if perfServer: 61 return perfServer.performanceGraphUrl(objpaq, targetpath, 62 template, graph, drange)
63
64 - def cacheRRDValue(self, dsname, default = "Unknown"):
65 """ 66 Cache RRD values for up to CACHE_TIME seconds. 67 """ 68 # Notes: 69 # * _cache takes care of the time-limited-offer bits 70 # * rrdcached does cache results, but the first query 71 # could potentially cause a flush() 72 # * Remote collectors need this call to prevent extra 73 # calls across the network 74 filename = self.getRRDFileName(dsname) 75 try: 76 value = _cache[filename] 77 except KeyError: 78 try: 79 # Grab rrdcached value locally or from network 80 value = self.getRRDValue(dsname) 81 except Exception, ex: 82 # Generally a remote collector issue 83 # We'll cache this for a minute and then try again 84 value = None 85 log.error('Unable to get RRD value for %s: %s', dsname, ex) 86 _cache[filename] = value 87 88 return value if value is not None else default
89 90
91 - def getRRDValue(self, dsname, start=None, end=None, function="LAST", 92 format="%.2lf", extraRpn="", cf="AVERAGE"):
93 """Return a single rrd value from its file using function. 94 """ 95 dsnames = (dsname,) 96 results = self.getRRDValues( 97 dsnames, start, end, function, format, extraRpn, cf=cf) 98 if results and dsname in results: 99 return results[dsname]
100
101 - def _getRRDDataPointsGen(self):
102 for t in self.getRRDTemplates(): 103 for dp in t.getRRDDataPoints(): 104 yield dp
105
106 - def getRRDDataPoints(self):
107 return list(self._getRRDDataPointsGen())
108
109 - def getRRDDataPoint(self, dpName):
110 return next((dp for dp in self._getRRDDataPointsGen() 111 if dp.name() == dpName), None)
112
113 - def fetchRRDValues(self, dpnames, cf, resolution, start, end=""):
114 paths = [self.getRRDFileName(dpname) for dpname in dpnames] 115 return self.device().getPerformanceServer().fetchValues(paths, 116 cf, resolution, start, end)
117 118
119 - def fetchRRDValue(self, dpname, cf, resolution, start, end=""):
120 r = self.fetchRRDValues([dpname,], cf, resolution, start, end=end) 121 if r: 122 return r[0] 123 return None
124 125
126 - def getRRDValues(self, dsnames, start=None, end=None, function="LAST", 127 format="%.2lf", extraRpn="", cf="AVERAGE"):
128 """ 129 Return a dict of key value pairs where dsnames are the keys. 130 """ 131 try: 132 if not start: 133 start = time.time() - self.defaultDateRange 134 gopts = [] 135 # must copy dsnames into mutable list 136 names = list(dsnames) 137 for dsname in dsnames: 138 dp = next((d for d in self._getRRDDataPointsGen() 139 if dsname in d.name()), None) 140 if dp is None: 141 names.remove(dsname) 142 continue 143 filename = self.getRRDFileName(dp.name()) 144 rpn = str(dp.rpn) 145 if rpn: 146 rpn = "," + rpn 147 if extraRpn: 148 rpn = rpn + "," + extraRpn 149 150 gopts.append("DEF:%s_r=%s:ds0:%s" % (dsname,filename,cf)) 151 gopts.append("CDEF:%s_c=%s_r%s" % (dsname,dsname,rpn)) 152 gopts.append("VDEF:%s=%s_c,%s" % (dsname,dsname,function)) 153 gopts.append("PRINT:%s:%s" % (dsname, format)) 154 gopts.append("--start=%s" % convertToRRDTime(start)) 155 if end: 156 gopts.append("--end=%s" % convertToRRDTime(end)) 157 if not names: 158 return {} 159 perfServer = self.device().getPerformanceServer() 160 vals = [] 161 if perfServer: 162 vals = perfServer.performanceCustomSummary(gopts) 163 if vals is None: 164 vals = [None] * len(dsnames) 165 def cvt(val): 166 if val is None or val.lower() == "nan": 167 return None 168 return float(val)
169 return dict(zip(names, map(cvt, vals))) 170 except Exception, ex: 171 log.exception("Unable to collect RRD Values for %s" % self.getPrimaryId())
172 173 174
175 - def getRRDSum(self, points, start=None, end=None, function="LAST"):
176 "Return a some of listed datapoints." 177 178 try: 179 if not start: 180 start = time.time() - self.defaultDateRange 181 if not end: 182 end = time.time() 183 gopts = [] 184 for name in points: 185 dp = next((dp_ for dp_ in self._getRRDDataPointsGen() 186 if name in dp_.name()), None) 187 if dp is None: 188 raise RRDViewError("Unable to find data point %s" % name) 189 190 filename = self.getRRDFileName(dp.name()) 191 rpn = str(dp.rpn) 192 if rpn: 193 rpn = "," + rpn 194 gopts.append("DEF:%s_r=%s:ds0:AVERAGE" % (name, filename)) 195 gopts.append("CDEF:%s=%s_r%s" % (name, name, rpn)) 196 gopts.append("CDEF:sum=%s%s" % (','.join(points), 197 ',+'*(len(points)-1))) 198 gopts.append("VDEF:agg=sum,%s" % function) 199 gopts.append("PRINT:agg:%.2lf") 200 gopts.append("--start=%d" % start) 201 gopts.append("--end=%d" % end) 202 perfServer = self.device().getPerformanceServer() 203 if perfServer: 204 vals = perfServer.performanceCustomSummary(gopts) 205 if vals is None: 206 return None 207 return float(vals[0]) 208 except Exception, ex: 209 log.exception(ex)
210 211
212 - def getDefaultGraphDefs(self, drange=None):
213 """get the default graph list for this object""" 214 graphs = [] 215 for template in self.getRRDTemplates(): 216 for g in template.getGraphDefs(): 217 graph = {} 218 graph['title'] = g.getId() 219 try: 220 graph['url'] = self.getGraphDefUrl(g, drange, template) 221 graphs.append(graph) 222 except ConfigurationError: 223 pass 224 return graphs
225 226
227 - def getGraphDef(self, graphId):
228 ''' Fetch a graph by id. if not found return None 229 ''' 230 return next((g for t in self.getRRDTemplates() 231 for g in t.getGraphDefs() 232 if g.id == graphId), 233 None)
234
235 - def getRRDTemplateName(self):
236 """Return the target type name of this component. By default meta_type. 237 Override to create custom type selection. 238 """ 239 return self.meta_type
240 241
242 - def getRRDFileName(self, dsname):
243 """Look up an rrd file based on its data point name""" 244 nm = next((p.name() for p in self._getRRDDataPointsGen() 245 if p.name().endswith(dsname)), dsname) 246 return '%s/%s.rrd' % (self.rrdPath(), nm)
247 248
249 - def getRRDNames(self):
250 return []
251
252 - def getRRDPaths(self):
253 return map(self.getRRDFileName, self.getRRDNames())
254
255 - def snmpIgnore(self):
256 """Should this component be monitored for performance using snmp. 257 """ 258 return False
259
260 - def getRRDTemplates(self):
261 default = self.getRRDTemplateByName(self.getRRDTemplateName()) 262 if not default: 263 return [] 264 return [default]
265
266 - def getRRDTemplate(self):
267 try: 268 return self.getRRDTemplates()[0] 269 except IndexError: 270 return None
271
272 - def getRRDTemplateByName(self, name):
273 "Return the template of the given name." 274 try: 275 return self._getOb(name) 276 except AttributeError: 277 pass 278 for obj in aq_chain(self): 279 try: 280 return obj.rrdTemplates._getOb(name) 281 except AttributeError: 282 pass 283 return None
284 285
286 - def getThresholds(self, templ):
287 """Return a dictionary where keys are dsnames and values are thresholds. 288 """ 289 result = {} 290 for thresh in templ.thresholds(): 291 if not thresh.enabled: continue 292 for dsname in thresh.dsnames: 293 threshdef = result.setdefault(dsname, []) 294 threshdef.append(thresh.getConfig(self)) 295 return result
296
297 - def rrdPath(self):
298 return GetRRDPath(self)
299 300
301 - def fullRRDPath(self):
302 from PerformanceConf import performancePath 303 return performancePath(self.rrdPath())
304
305 - def getRRDContextData(self, context):
306 return context
307
308 - def getThresholdInstances(self, dsType):
309 from Products.ZenEvents.Exceptions import pythonThresholdException 310 result = [] 311 for template in self.getRRDTemplates(): 312 # if the template refers to a data source name of the right type 313 # include it 314 names = set(dp.name() for ds in template.getRRDDataSources(dsType) 315 for dp in ds.datapoints()) 316 for threshold in template.thresholds(): 317 if not threshold.enabled: continue 318 for ds in threshold.dsnames: 319 if ds in names: 320 try: 321 thresh = threshold.createThresholdInstance(self) 322 result.append(thresh) 323 except pythonThresholdException, ex: 324 log.warn(ex) 325 zem = self.primaryAq().getEventManager() 326 import socket 327 device = socket.gethostname() 328 path = template.absolute_url_path() 329 msg = \ 330 "The threshold %s in template %s has caused an exception." % (threshold.id, path) 331 evt = dict(summary=str(ex), severity=3, 332 component='zenhub', message=msg, 333 dedupid='zenhub|' + str(ex), 334 template=path, 335 threshold=threshold.id, 336 device=device, eventClass="/Status/Update",) 337 zem.sendEvent(evt) 338 break 339 return result
340 341
342 - def makeLocalRRDTemplate(self, templateName=None, REQUEST=None):
343 """Make a local copy of our RRDTemplate if one doesn't exist. 344 """ 345 if templateName is None: templateName = self.getRRDTemplateName() 346 if not self.isLocalName(templateName): 347 ct = self.getRRDTemplateByName(templateName)._getCopy(self) 348 ct.id = templateName 349 self._setObject(ct.id, ct) 350 if REQUEST: 351 messaging.IMessageSender(self).sendToBrowser( 352 'Template Created', 353 'Local copy "%s" created.' % templateName 354 ) 355 return self.callZenScreen(REQUEST)
356 357
358 - def removeLocalRRDTemplate(self, templateName=None, REQUEST=None):
359 """Make a local delete of our RRDTemplate if one doesn't exist. 360 """ 361 if templateName is None: templateName = self.getRRDTemplateName() 362 if self.isLocalName(templateName): 363 self._delObject(templateName) 364 if REQUEST: 365 messaging.IMessageSender(self).sendToBrowser( 366 'Template Removed', 367 'Local copy "%s" removed.' % templateName 368 ) 369 return self.callZenScreen(REQUEST)
370 371
372 -def updateCache(filenameValues):
373 _cache.update(dict(filenameValues))
374