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

# Source Code for Module Products.ZenModel.RRDTemplate

      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 sys
     15  from Globals import DTMLFile
     16  from Globals import InitializeClass
     17  from AccessControl import ClassSecurityInfo, Permissions
     18  from Products.ZenModel.ZenossSecurity import *
     19  from zope.interface import implements
     20  from Acquisition import aq_parent
     21  from ZenModelRM import ZenModelRM
     22  from Products.ZenModel.interfaces import IIndexed
     23
     24  from Products.ZenRelations.RelSchema import *
     25  from Products.ZenModel.RRDDataSource import SimpleRRDDataSource
     26  from Products.ZenModel.BasicDataSource import BasicDataSource
     27  from Products.ZenModel.BuiltInDS import BuiltInDS
     28  from Products.ZenModel.PingDataSource import PingDataSource
     29  from Products.ZenModel.ConfigurationError import ConfigurationError
     30  from Products.ZenUtils.Utils import importClass
     31  from Products.ZenWidgets import messaging
     32  from RRDDataPoint import SEPARATOR
     33  from ZenPackable import ZenPackable
     34
     35  import logging
     36  log = logging.getLogger('zen.RRDTemplate')
     37
     38  RRDTEMPLATE_CATALOG = 'searchRRDTemplates'
     39
     40
     41 -def CreateRRDTemplatesCatalog(dmd, rebuild=False):
     42      """
     43      Create the searchRRDTemplates catalog if it does not already exist.
     44      Return the catalog.
     45      """
     46      from Products.ZCatalog.ZCatalog import manage_addZCatalog
     47      from Products.ZenUtils.Search import makeCaseSensitiveFieldIndex, \
     48                                              makePathIndex
     49      zcat = getattr(dmd, RRDTEMPLATE_CATALOG, None)
     50      if zcat and rebuild:
     51          dmd._delObject(RRDTEMPLATE_CATALOG)
     52          zcat = None
     53      if zcat is None:
     54          manage_addZCatalog(dmd, RRDTEMPLATE_CATALOG, RRDTEMPLATE_CATALOG)
     55          zcat = dmd._getOb(RRDTEMPLATE_CATALOG)
     56          cat = zcat._catalog
     57          cat.addIndex('id', makeCaseSensitiveFieldIndex('id'))
     58          cat.addIndex('getPhysicalPath', makePathIndex('getPhysicalPath'))
     59      return zcat
     60
     61
     62 -def YieldAllRRDTemplates(root, criteria=None):
     63      """
     64      Yield all templates in the searchRRDTemplates catalog which fall under
     65      the given root and match the given criteria.  To get all RRDTemplates
     66      pass dmd in as root.  If criteria contains a
     67      value for getPhysicalRoot then the root parameter will be ignored.
     68
     69      If the searchRRDTemplates catalog is not present then fall back to using
     70      DeviceClass.getAllRRDTemplatesPainfully().  In this case root must
     71      be a DeviceClass and criteria is ignored. (This is compatible with
     72      previous DeviceClass.getAllRRDTemplates usage.)
     73
     74      The searchRRDTemplates catalog was added in 2.2
     75      """
     76      zcat = getattr(root, RRDTEMPLATE_CATALOG, None)
     77      if zcat is not None:
     78          criteria = criteria or {}
     79          criteria.setdefault('getPhysicalPath', root.getPrimaryId())
     80          brains = zcat(criteria)
     81          for result in brains:
     82              yield result.getObject()
     83      else:
     84          for t in root.getAllRRDTemplatesPainfully():
     85              yield t
     86
     87
     88 -def manage_addRRDTemplate(context, id, REQUEST = None):
     89      """make a RRDTemplate"""
     90      tt = RRDTemplate(id)
     91      context._setObject(tt.id, tt)
     92      if REQUEST is not None:
     93          REQUEST['RESPONSE'].redirect(context.absolute_url()+'/manage_main')
     94
     95
     96  addRRDTemplate = DTMLFile('dtml/addRRDTemplate',globals())
     97
     98
     99 -def crumbspath(templ, crumbs, idx=-1):
    100      """Create the crumbs path for sub objects of an RRDTemplate.
    101      """
    102      return crumbs
    103
    104
    105 -class RRDTemplate(ZenModelRM, ZenPackable):
    106
    107      implements(IIndexed)
    108      meta_type = 'RRDTemplate'
    109
    110      default_catalog = RRDTEMPLATE_CATALOG
    111
    112      security = ClassSecurityInfo()
    113
    114      description = ""
    115      targetPythonClass = "Products.ZenModel.Device"
    116
    117      _properties = (
    118          {'id':'description', 'type':'text', 'mode':'w'},
    119          {'id':'targetPythonClass', 'type':'string', 'mode':'w'},
    120          )
    121
    122      # The graphs relationship can be removed post 2.1.  It is needed
    123      # by the graphDefinitionAndFriends migrate script for 2.1
    124
    125      _relations =  ZenPackable._relations + (
    126          ("deviceClass", ToOne(
    127              ToManyCont,"Products.ZenModel.TemplateContainer", "rrdTemplates")),
    128          ("datasources", ToManyCont(
    129              ToOne,"Products.ZenModel.RRDDataSource", "rrdTemplate")),
    130          ("graphs", ToManyCont(
    131              ToOne,"Products.ZenModel.RRDGraph", "rrdTemplate")),
    132          ("thresholds", ToManyCont(
    133              ToOne,"Products.ZenModel.ThresholdClass", "rrdTemplate")),
    134          ("graphDefs", ToManyCont(
    135              ToOne,"Products.ZenModel.GraphDefinition", "rrdTemplate")),
    136          )
    137
    138
    139      # Screen action bindings (and tab definitions)
    140      factory_type_information = (
    141      {
    142          'immediate_view' : 'viewRRDTemplate',
    143          'actions'        :
    144          (
    145              { 'id'            : 'overview'
    146              , 'name'          : 'Performance Template'
    147              , 'action'        : 'viewRRDTemplate'
    148              , 'permissions'   : ( Permissions.view, )
    149              },
    150          )
    151      },
    152      )
    153
    154 -    def breadCrumbs(self, terminator='dmd'):
    155          """Return the breadcrumb links for this object add ActionRules list.
    156          [('url','id'), ...]
    157          """
    158          crumbs = super(RRDTemplate, self).breadCrumbs(terminator)
    159          return crumbspath(self, crumbs)
    160
    161
    162 -    def isEditable(self, context):
    163          """Is this template editable in context.
    164          """
    165          return ((context == self or context.isLocalName(self.id))
    166                  and self.checkRemotePerm(ZEN_CHANGE_DEVICE, self))
    167
    168
    169 -    def getGraphDefs(self):
    170          ''' Return an ordered list of the graph definitions
    171          '''
    172          def cmpGraphDefs(a, b):
    173              try: a = int(a.sequence)
    174              except ValueError: a = sys.maxint
    175              try: b = int(b.sequence)
    176              except ValueError: b = sys.maxint
    177              return cmp(a, b)
    178          graphDefs =  [g for g in self.graphDefs()]
    179          graphDefs.sort(cmpGraphDefs)
    180          return graphDefs
    181
    182
    183 -    def getRRDPath(self):
    184          """Return the path on which this template is defined.
    185          """
    186          return self.getPrimaryParent().getPrimaryDmdId(subrel="rrdTemplates")
    187
    188
    189 -    def getGraphableThresholds(self):
    190          ''' Return a list of names of graphable thresholds
    191          '''
    192          return [t for t in self.thresholds()]
    193
    194
    195 -    def getRRDDataPointNames(self):
    196          """Return the list of all datapoint names.
    197          """
    198          # We check for the presence of datapoints on the datasources
    199          # to better handle situation where the datasource is broken
    200          # (usually because of a missing zenpack.)
    201          datasources = [ds for ds in self.datasources()
    202                          if hasattr(ds, 'datapoints')]
    203          return [dp.name() for ds in datasources for dp in ds.datapoints()]
    204
    205
    206 -    def getRRDDataSources(self, dsType=None):
    207          """Return a list of all datapoints on this template.
    208          """
    209          if dsType is None: return self.datasources()
    210          return [ds for ds in self.datasources()
    211                  if ds.sourcetype == dsType
    212                  or (dsType=='COMMAND' and ds.useZenCommand())]
    213
    214
    215 -    def getRRDDataPoints(self):
    216          """Return a list of all datapoints on this template.
    217          """
    218          result = []
    219          for s in self.datasources():
    220              result.extend(s.datapoints())
    221          return result
    222
    223
    224 -    def getRRDDataPoint(self, name):
    225          """Return a datapoint based on its name.
    226          """
    227          source = name
    228          point = name
    229          if name.find(SEPARATOR) >= 0:
    230              source, point = name.split(SEPARATOR, 1)
    231          ds = self.datasources._getOb(source, None)
    232          if ds is None:
    233              results = []
    234              for ds in self.datasources():
    235                  for dp in ds.datapoints():
    236                      if dp.name() == name:
    237                          results.append(dp)
    238              if len(results) == 1:
    239                  return results[0]
    240          else:
    241              return ds.datapoints._getOb(point)
    242          raise ConfigurationError('Unknown data point "%s"' % name)
    243
    244
    245      security.declareProtected('Add DMD Objects', 'manage_addRRDDataSource')
    246 -    def manage_addRRDDataSource(self, id, dsOption, REQUEST=None):
    247          """Add an RRDDataSource to this DeviceClass.
    248          """
    249          ds = None
    250          if id and dsOption:
    251              ds = self.getDataSourceInstance(id, dsOption)
    252              self.datasources._setObject(ds.id, ds)
    253              ds = self.datasources._getOb(ds.id)
    254              if ds:
    255                  ds.addDataPoints()
    256          if REQUEST:
    257              if ds:
    258                  messaging.IMessageSender(self).sendToBrowser(
    259                      'Datasource Added',
    260                      "Data source %s added" % ds.id
    261                  )
    262                  url = '%s/datasources/%s' % (self.getPrimaryUrlPath(), ds.id)
    263                  return REQUEST['RESPONSE'].redirect(url)
    264              else:
    265                  return self.callZenScreen(REQUEST)
    266          return ds
    267
    268
    269 -    def getTargetPythonClass(self):
    270          """
    271          Returns the python class object that this template can be bound to.
    272          """
    273          from Products.ZenModel.Device import Device
    274          cname = getattr(self, "targetPythonClass", None)
    275          if cname:
    276              try:
    277                  return importClass(cname)
    278              except ImportError:
    279                  log.exception("Unable to import class " + cname)
    280          return Device
    281
    282
    283      security.declareProtected(ZEN_MANAGE_DMD, 'manage_deleteRRDDataSources')
    284 -    def manage_deleteRRDDataSources(self, ids=(), REQUEST=None):
    285          """Delete RRDDataSources from this DeviceClass
    286          """
    287          def clean(rel, id):
    288              for obj in rel():
    289                  if id in obj.dsnames:
    290                      obj.dsnames.remove(id)
    291                      if not obj.dsnames:
    292                          rel._delObject(obj.id)
    293
    294          if not ids: return self.callZenScreen(REQUEST)
    295          for id in ids:
    296              self._p_changed = True
    297              if getattr(self.datasources,id,False):
    298                  if getattr(self, 'device', False):
    299                      perfConf = self.device().getPerformanceServer()
    300                      if perfConf:
    301                          perfConf.deleteRRDFiles(device=self.device().id,
    302                                                  datasource=id)
    303                  else:
    304                      for d in self.deviceClass.obj.getSubDevicesGen():
    305                          perfConf = d.getPerformanceServer()
    306                          if perfConf:
    307                              perfConf.deleteRRDFiles(device=d, datasource=id)
    308
    309                  self.datasources._delObject(id)
    310                  clean(self.graphs, id)
    311                  clean(self.thresholds, id)
    312
    313          if REQUEST:
    314              messaging.IMessageSender(self).sendToBrowser(
    315                  'Datasources Deleted',
    316                  'Datasource%s %s deleted.' % ('' if len(ids)==1 else 's',
    317                                                ', '.join(ids))
    318              )
    319              return self.callZenScreen(REQUEST)
    320
    321
    322      security.declareProtected('Add DMD Objects', 'manage_addRRDThreshold')
    323 -    def manage_addRRDThreshold(self, id, thresholdClassName, REQUEST=None):
    324          """Add an RRDThreshold to this DeviceClass.
    325          """
    326          if not id: return self.callZenScreen(REQUEST)
    327          org = self.getThresholdClass(id, thresholdClassName)
    328          self.thresholds._setObject(org.id, org)
    329          org = self.thresholds._getOb(org.id)
    330          if REQUEST:
    331              if org:
    332                  messaging.IMessageSender(self).sendToBrowser(
    333                      'Threshold Added',
    334                      'Threshold "%s" added' % org.id
    335                  )
    336                  url = '%s/thresholds/%s' % (self.getPrimaryUrlPath(), org.id)
    337                  return REQUEST['RESPONSE'].redirect(url)
    338              else:
    339                  return self.callZenScreen(REQUEST)
    340          return org
    341
    342
    343      security.declareProtected(ZEN_MANAGE_DMD, 'manage_deleteRRDThresholds')
    344 -    def manage_deleteRRDThresholds(self, ids=(), REQUEST=None):
    345          """Delete RRDThresholds from this DeviceClass
    346          """
    347          if not ids: return self.callZenScreen(REQUEST)
    348          for id in ids:
    349              if getattr(self.thresholds,id,False):
    350                  self.thresholds._delObject(id)
    351          if REQUEST:
    352              messaging.IMessageSender(self).sendToBrowser(
    353                  'Thresholds Deleted',
    354                  'Threshold%s %s deleted.' % ('' if len(ids)==1 else 's',
    355                                                ', '.join(ids))
    356              )
    357              return self.callZenScreen(REQUEST)
    358
    359
    360      security.declareProtected(ZEN_MANAGE_DMD, 'manage_addGraphDefinition')
    361 -    def manage_addGraphDefinition(self, new_id, REQUEST=None):
    362          """Add a GraphDefinition to our RRDTemplate.
    363          """
    364          from GraphDefinition import GraphDefinition
    365          self.getGraphDefs()
    366          graph = None
    367          graph = GraphDefinition(new_id)
    368          graph.sequence = len(self.graphDefs())
    369          self.graphDefs._setObject(graph.id, graph)
    370          graph = self.graphDefs._getOb(graph.id)
    371          if REQUEST:
    372              messaging.IMessageSender(self).sendToBrowser(
    373                  'Graph Added',
    374                  'Graph "%s" added' % graph.id
    375              )
    376              url = '%s/graphDefs/%s' % (self.getPrimaryUrlPath(), graph.id)
    377              return REQUEST['RESPONSE'].redirect(url)
    378          return graph
    379
    380
    381      security.declareProtected(ZEN_MANAGE_DMD, 'manage_deleteGraphDefinitions')
    382 -    def manage_deleteGraphDefinitions(self, ids=(), REQUEST=None):
    383          """Remove GraphDefinitions from this RRDTemplate.
    384          """
    385          for id in ids:
    386              self.graphDefs._delObject(id)
    387              self.manage_resequenceGraphDefs()
    388          if REQUEST:
    389              messaging.IMessageSender(self).sendToBrowser(
    390                  'Graphs Deleted',
    391                  'Graph%s %s deleted.' % ('' if len(ids)==1 else 's',
    392                                                ', '.join(ids))
    393              )
    394              return self.callZenScreen(REQUEST)
    395
    396
    397      security.declareProtected(ZEN_MANAGE_DMD, 'manage_resequenceGraphDefs')
    398 -    def manage_resequenceGraphDefs(self, seqmap=(), origseq=(), REQUEST=None):
    399          """Reorder the sequence of the GraphDefinitions.
    400          """
    401          from Products.ZenUtils.Utils import resequence
    402          return resequence(self, self.getGraphDefs(),
    403                              seqmap, origseq, REQUEST)
    404
    405
    406      security.declareProtected(ZEN_MANAGE_DMD, 'manage_addDataSourcesToGraphs')
    407 -    def manage_addDataSourcesToGraphs(self, ids=(), graphIds=(), REQUEST=None):
    408          """
    409          Create GraphPoints for all datapoints in the given datasources (ids)
    410          in each of the graphDefs (graphIds.)
    411          If a graphpoint already exists for a datapoint in a graphDef then
    412          don't create a 2nd one.
    413          """
    414          newGraphPoints = []
    415          for dsId in ids:
    416              ds = self.datasources._getOb(dsId, None)
    417              if ds:
    418                  newGraphPoints += ds.manage_addDataPointsToGraphs(
    419                      [dp.id for dp in ds.datapoints()],
    420                      graphIds)
    421          numAdded = len(newGraphPoints)
    422          if REQUEST:
    423              messaging.IMessageSender(self).sendToBrowser(
    424                  'Graph Points Added',
    425                  'Added %s GraphPoint%s' % (numAdded, numAdded != 1 and 's' or '')
    426              )
    427              return self.callZenScreen(REQUEST)
    428          return newGraphPoints
    429
    430
    431      security.declareProtected(ZEN_MANAGE_DMD, 'manage_addDataSourcesToGraphs')
    432 -    def manage_addThresholdsToGraphs(self, ids=(), graphIds=(), REQUEST=None):
    433          """
    434          Create GraphPoints for all given thresholds that are not already
    435          graphed. in the given datasources (ids)
    436          """
    437          newGps = []
    438          for graphId in graphIds:
    439              graphDef = self.graphDefs._getOb(graphId, None)
    440              if graphDef:
    441                  for threshId in ids:
    442                      thresh = self.thresholds._getOb(threshId, None)
    443                      if thresh and not graphDef.isThresholdGraphed(thresh.id):
    444                          newGps += graphDef.manage_addThresholdGraphPoints(
    445                                                                  [thresh.id])
    446          if REQUEST:
    447              numAdded = len(newGps)
    448              messaging.IMessageSender(self).sendToBrowser(
    449                  'Graph Points Added',
    450                  'Added %s GraphPoint%s' % (numAdded, numAdded != 1 and 's' or '')
    451              )
    452              return self.callZenScreen(REQUEST)
    453          return newGps
    454
    455
    456 -    def getDataSourceClasses(self):
    457          dsClasses = [BasicDataSource, BuiltInDS, PingDataSource]
    458          for zp in self.dmd.ZenPackManager.packs():
    459              dsClasses += zp.getDataSourceClasses()
    460          return dsClasses
    461
    462
    463 -    def getDataSourceOptions(self):
    464          ''' Returns a list of the available datasource options as a list
    465          of (display name, dsOption)
    466          '''
    467          dsTypes = []
    468          for dsClass in self.getDataSourceClasses():
    469              dsTypes += [(t, '%s.%s' % (dsClass.__name__, t))
    470                              for t in dsClass.sourcetypes]
    471          return dsTypes
    472
    473
    474 -    def getDataSourceInstance(self, id, dsOption):
    475          ''' Given one of the dsOptions returned by getDataSourceOptions)
    476          return an instance of the that RRDDataSource subclass.
    477          '''
    478          dsClassName, dsType = dsOption.split('.')
    479          for c in self.getDataSourceClasses():
    480              if dsClassName == c.__name__:
    481                  ds = c(id)
    482                  ds.sourcetype = dsType
    483                  break
    484          else:
    485              raise ConfigurationError('Cannot find datasource class'
    486                          ' for %s' % dsOption)
    487          return ds
    488
    489
    490 -    def getThresholdClasses(self):
    491          from Products.ZenModel.MinMaxThreshold import MinMaxThreshold
    492          thresholdClasses = [MinMaxThreshold]
    493          for zp in self.dmd.ZenPackManager.packs():
    494              thresholdClasses += zp.getThresholdClasses()
    495          return map(lambda x: (x, x.__name__), thresholdClasses)
    496
    497
    498 -    def getThresholdClass(self, id, thresholdClassName):
    499          ''' Given one of the dsOptions returned by getDataSourceOptions)
    500          return an instance of the that RRDDataSource subclass.
    501          '''
    502          for c, name in self.getThresholdClasses():
    503              if thresholdClassName == c.__name__:
    504                  return c(id)
    505          raise ConfigurationError('Cannot find threshold class %s' %
    506                                   thresholdClassName)
    507
    508
    509 -    def getEventClassNames(self):
    510          """
    511          Get a list of all event class names within the permission scope.
    512          """
    513          return self.primaryAq().Events.getOrganizerNames()
    514
    515
    516 -    def getUIPath(self, separator='/'):
    517          """
    518          Given a separator and a template this method returns the UI path that we display
    519          to the user.
    520          @param RRDTemplate template
    521          @param String separator e.g. '/'
    522          @returns String e.g. '/Devices' or '/Server'
    523          """
    524          obj = self.deviceClass()
    525          if obj is None:
    526              # this template is in a Device
    527              obj = aq_parent(self)
    528              path = list(obj.getPrimaryPath())
    529              # remove the "devices" relationship
    530              path.pop(-2)
    531          else:
    532              # this template is in a DeviceClass.rrdTemplates relationship
    533              path = list(obj.getPrimaryPath())
    534          parts = path[4:-1]
    535          parts.append(obj.titleOrId())
    536          return separator + separator.join(parts)
    537
    538
    539  InitializeClass(RRDTemplate)
    540