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