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