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

# Source Code for Module Products.ZenModel.ThresholdInstance

      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 os
     12
     13  import Globals
     14  import rrdtool
     15  from Products.ZenModel.PerformanceConf import PerformanceConf, performancePath
     16  from Products.ZenModel.MonitorClass import MonitorClass
     17  from Products.ZenUtils.Utils import unused, rrd_daemon_args, rrd_daemon_retry
     18
     19  from twisted.spread import pb
     20
     21  import logging
     22  log = logging.getLogger('zen.ThresholdInstance')
     23
     24  unused(Globals)
     25
     26 -class ThresholdContext(pb.Copyable, pb.RemoteCopy):
     27      """Remember all the little details about a specific data point
     28      within a context.  This is useful for error messages and path
     29      information in the collectors.  It's a copy of the key bits of
     30      information from the Model."""
     31
     32 -    def __init__(self, context):
     33          if isinstance(context, MonitorClass):
     34              self.deviceName = "{context.id} hub".format(context=context)
     35              self.componentName = ''
     36              self.deviceUrl = 'zport/dmd/Monitors/Hub/{context.id}/viewHubPerformance'.format(context=context)
     37              self.devicePath = 'Monitors/Hub/{context.id}'.format(context=context)
     38          if isinstance(context, PerformanceConf):
     39              self.deviceName = "{context.id} collector".format(context=context)
     40              self.componentName = ''
     41              self.deviceUrl = 'zport/dmd/Monitors/Performance/{context.id}/viewDaemonPerformance'.format(context=context)
     42              self.devicePath = 'Monitors/Performance/{context.id}'.format(context=context)
     43          else:
     44              self.deviceName = context.device().id
     45              self.componentName = context.id
     46              if self.componentName == self.deviceName:
     47                  self.componentName = ''
     48
     49          self.rrdPath = context.rrdPath()
     50
     51
     52 -    def key(self):
     53          "Unique data that refers this context"
     54          return self.deviceName, self.componentName
     55
     56
     57 -    def fileKey(self, dataPoint):
     58          "Unique base filename for this context and given dataPoint"
     59          return os.path.join(self.rrdPath, dataPoint)
     60
     61
     62 -    def path(self, dataPoint):
     63          "The full pathname to RRD file that uses a dataPoint"
     64          return performancePath(os.path.join(self.rrdPath, dataPoint)) + '.rrd'
     65
     66  pb.setUnjellyableForClass(ThresholdContext, ThresholdContext)
     67
     68 -class ThresholdInstance(pb.Copyable, pb.RemoteCopy):
     69      """A ThresholdInstance is a threshold to be evaluated in a
     70      collector within a given context."""
     71
     72      # count is unknown if None
     73      count = None
     74
     75 -    def name(self):
     76          "return the name of this threshold (from the ThresholdClass)"
     77
     78 -    def context(self):
     79          "Return the ThresholdContext for this ThresholdInstance"
     80
     81 -    def key(self):
     82          "Unique data that refers to this object within a collector"
     83          return self.name(), self.context().key()
     84
     85 -    def dataPoints(self):
     86          "Returns the names of the datapoints used to compute the threshold"
     87
     88 -    def check(self, dataPoints):
     89          """The given datapoints have been updated, so re-evaluate.
     90          returns events or an empty sequence"""
     91
     92 -    def checkRaw(self, dataPoint, timeOf, value):
     93          """A new datapoint has been collected, use the given _raw_
     94          value to re-evalue the threshold.
     95          returns a sequence of events.
     96          """
     97          unused(timeOf, value)
     98          return self.check([dataPoint])
     99
    100 -    def getGraphElements(self, template, context, gopts, namespace, color,
    101                           legend, relatedGps):
    102          """Produce a visual indication on the graph of where the
    103          threshold applies."""
    104          unused(template, context, gopts, namespace, color, legend, relatedGps)
    105          return []
    106
    107
    108  pb.setUnjellyableForClass(ThresholdInstance, ThresholdInstance)
    109
    110 -class RRDThresholdInstance(ThresholdInstance):
    111
    112 -    def __init__(self, id, context, dpNames, eventClass, severity):
    113          self._context = context
    114          self.id = id
    115          self.eventClass = eventClass
    116          self.severity = severity
    117          self.dataPointNames = dpNames
    118          self._rrdInfoCache = {}
    119
    120 -    def name(self):
    121          "return the name of this threshold (from the ThresholdClass)"
    122          return self.id
    123
    124 -    def context(self):
    125          "Return an identifying context (device, or device and component)"
    126          return self._context
    127
    128 -    def dataPoints(self):
    129          "Returns the names of the datapoints used to compute the threshold"
    130          return self.dataPointNames
    131
    132 -    def check(self, dataPoints):
    133          """The given datapoints have been updated, so re-evaluate.
    134          returns events or an empty sequence"""
    135          unused(dataPoints)
    136          result = []
    137          for dp in self.dataPointNames:
    138              cycleTime, rrdType = self._getRRDType(dp)
    139              result.extend(self._checkImpl(
    140                  dp, self._fetchLastValue(dp, cycleTime)))
    141          return result
    142
    143 -    def checkRaw(self, dataPoint, timeOf, value):
    144          """A new datapoint has been collected, use the given _raw_
    145          value to re-evalue the threshold."""
    146          unused(timeOf)
    147          result = []
    148          if value is None: return result
    149          try:
    150              cycleTime, rrdType = self._getRRDType(dataPoint)
    151          except Exception:
    152              log.exception('Unable to read RRD file for %s' % dataPoint)
    153              return result
    154          if rrdType != 'GAUGE' and value is None:
    155              value = self._fetchLastValue(dataPoint, cycleTime)
    156          result.extend(self._checkImpl(dataPoint, value))
    157          return result
    158
    159 -    def _getRRDType(self, dp):
    160          """
    161          get and cache rrd type inforomation
    162          """
    163          if dp in self._rrdInfoCache:
    164              return self._rrdInfoCache[dp]
    165
    166          @rrd_daemon_retry
    167          def rrdtool_fn():
    168              return rrdtool.info(self.context().path(dp), *rrd_daemon_args())
    169          data = rrdtool_fn()
    170
    171          # handle both old and new style RRD versions
    172          try:
    173              # old style 1.2.x
    174              value = data['step'], data['ds']['ds0']['type']
    175          except KeyError:
    176              # new style 1.3.x
    177              value = data['step'], data['ds[ds0].type']
    178          self._rrdInfoCache[dp] = value
    179          return value
    180
    181
    182 -    def _fetchLastValue(self, dp, cycleTime):
    183          """
    184          Fetch the most recent value for a data point from the RRD file.
    185          """
    186          @rrd_daemon_retry
    187          def rrdtool_fn():
    188              return rrdtool.fetch(self.context().path(dp),
    189                  'AVERAGE', '-s', 'now-%d' % (cycleTime*2), '-e', 'now',
    190                  *rrd_daemon_args())
    191          startStop, names, values = rrdtool_fn()
    192          values = [ v[0] for v in values if v[0] is not None ]
    193          if values: return values[-1]
    194
    195
    196 -    def _checkImpl(self, dataPoint, value):
    197          raise NotImplementedError()
    198
    199  pb.setUnjellyableForClass(RRDThresholdInstance, RRDThresholdInstance)
    200