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