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

# Source Code for Module Products.ZenModel.RRDView

      1  ###########################################################################
      2  #
      3  # This program is part of Zenoss Core, an open source monitoring platform.
      4  # Copyright (C) 2007, Zenoss Inc.
      5  #
      6  # This program is free software; you can redistribute it and/or modify it
      7  # under the terms of the GNU General Public License version 2 as published by
      8  # the Free Software Foundation.
      9  #
     10  # For complete information please visit: http://www.zenoss.com/oss/
     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
     32 -def GetRRDPath(deviceOrComponent):
     33      d = deviceOrComponent.device()
     34      if not d:
     35          return "Devices/" + deviceOrComponent.id
     36      skip = len(d.getPrimaryPath()) - 1
     37      return 'Devices/' + '/'.join(deviceOrComponent.getPrimaryPath()[skip:])
     38
     39
     40 -class RRDViewError(Exception): pass
     41
     42
     43 -class RRDView(object):
     44      """
     45      Mixin to provide hooks to RRD management functions
     46      """
     47
     48 -    def getGraphDefUrl(self, graph, drange=None, template=None):
     49          """resolve template and graph names to objects
     50          and pass to graph performance"""
     51          if not drange: drange = self.defaultDateRange
     52          templates = self.getRRDTemplates()
     53          if template:
     54              templates = [template]
     55          if type(graph) in types.StringTypes:
     56              for t in templates:
     57                  if hasattr(t.graphDefs, graph):
     58                      template = t
     59                      graph = getattr(t.graphDefs, graph)
     60                      break
     61          targetpath = self.rrdPath()
     62          objpaq = self.primaryAq()
     63          perfServer = objpaq.device().getPerformanceServer()
     64          if perfServer:
     65              return perfServer.performanceGraphUrl(objpaq, targetpath,
     66                                                    template, graph, drange)
     67
     68 -    def cacheRRDValue(self, dsname, default = "Unknown"):
     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
     99 -    def getRRDDataPoints(self):
    100          result = []
    101          for t in self.getRRDTemplates():
    102              result += t.getRRDDataPoints()
    103          return result
    104
    105
    106 -    def getRRDDataPoint(self, dpName):
    107          result = None
    108          for t in self.getRRDTemplates():
    109              for dp in t.getRRDDataPoints():
    110                  if dp.name() == dpName:
    111                      result = dp
    112                      break
    113          return result
    114
    115
    116 -    def fetchRRDValues(self, dpnames, cf, resolution, start, end=""):
    117          paths = []
    118          for dpname in dpnames:
    119              paths.append(self.getRRDFileName(dpname))
    120          return self.device().getPerformanceServer().fetchValues(paths,
    121              cf, resolution, start, end)
    122
    123
    124 -    def fetchRRDValue(self, dpname, cf, resolution, start, end=""):
    125          r = self.fetchRRDValues([dpname,], cf, resolution, start, end=end)
    126          if r is not None:
    127              return r[0]
    128          return None
    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
    217 -    def getDefaultGraphDefs(self, drange=None):
    218          """get the default graph list for this object"""
    219          graphs = []
    220          for template in self.getRRDTemplates():
    221              for g in template.getGraphDefs():
    222                  graph = {}
    223                  graph['title'] = g.getId()
    224                  try:
    225                      graph['url'] = self.getGraphDefUrl(g, drange, template)
    226                      graphs.append(graph)
    227                  except ConfigurationError:
    228                      pass
    229          return graphs
    230
    231
    232 -    def getGraphDef(self, graphId):
    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
    242 -    def getRRDTemplateName(self):
    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
    249 -    def getRRDFileName(self, dsname):
    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
    259 -    def getRRDNames(self):
    260          return []
    261
    262 -    def getRRDPaths(self):
    263          return map(self.getRRDFileName, self.getRRDNames())
    264
    265 -    def snmpIgnore(self):
    266          """Should this component be monitored for performance using snmp.
    267          """
    268          return False
    269
    270 -    def getRRDTemplates(self):
    271          default = self.getRRDTemplateByName(self.getRRDTemplateName())
    272          if not default:
    273              return []
    274          return [default]
    275
    276 -    def getRRDTemplate(self):
    277          try:
    278              return self.getRRDTemplates()[0]
    279          except IndexError:
    280              return None
    281
    282 -    def getRRDTemplateByName(self, name):
    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
    296 -    def getThresholds(self, templ):
    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
    308 -    def rrdPath(self):
    309          return GetRRDPath(self)
    310
    311
    312 -    def fullRRDPath(self):
    313          from PerformanceConf import performancePath
    314          return performancePath(self.rrdPath())
    315
    316 -    def getRRDContextData(self, context):
    317          return context
    318
    319 -    def getThresholdInstances(self, dsType):
    320          from Products.ZenEvents.Exceptions import pythonThresholdException
    321          result = []
    322          for template in self.getRRDTemplates():
    323              # if the template refers to a data source name of the right type
    324              # include it
    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
    364 -    def makeLocalRRDTemplate(self, templateName=None, REQUEST=None):
    365          """Make a local copy of our RRDTemplate if one doesn't exist.
    366          """
    367          if templateName is None: templateName = self.getRRDTemplateName()
    368          if not self.isLocalName(templateName):
    369              ct = self.getRRDTemplateByName(templateName)._getCopy(self)
    370              ct.id = templateName
    371              self._setObject(ct.id, ct)
    372          if REQUEST:
    373              messaging.IMessageSender(self).sendToBrowser(
    374                  'Template Created',
    375                  'Local copy "%s" created.' % templateName
    376              )
    377              return self.callZenScreen(REQUEST)
    378
    379
    380 -    def removeLocalRRDTemplate(self, templateName=None, REQUEST=None):
    381          """Make a local delete of our RRDTemplate if one doesn't exist.
    382          """
    383          if templateName is None: templateName = self.getRRDTemplateName()
    384          if self.isLocalName(templateName):
    385              self._delObject(templateName)
    386          if REQUEST:
    387              messaging.IMessageSender(self).sendToBrowser(
    388                  'Template Removed',
    389                  'Local copy "%s" removed.' % templateName
    390              )
    391              return self.callZenScreen(REQUEST)
    392
    393
    394 -def updateCache(filenameValues):
    395      _cache.update(dict(filenameValues))
    396