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

# Source Code for Module Products.ZenModel.RRDTemplate

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