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

# Source Code for Module Products.ZenModel.DeviceClass

      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  __doc__="""DeviceClass
     15  The primary organizer of device objects, managing zProperties and
     16  their acquisition.
     17  """
     18
     19  import types
     20  import time
     21  import transaction
     22  import logging
     23  log = logging.getLogger('zen.DeviceClass')
     24
     25  import DateTime
     26  from zope.event import notify
     27  from zope.app.container.contained import ObjectMovedEvent
     28  from Globals import DTMLFile
     29  from Globals import InitializeClass
     30  from Acquisition import aq_base, aq_chain
     31  from AccessControl import ClassSecurityInfo
     32  from AccessControl import Permissions as permissions
     33
     34  from Products.AdvancedQuery import MatchGlob, Or, Eq, RankByQueries_Max
     35  from Products.CMFCore.utils import getToolByName
     36
     37  from Products.ZenModel.ZenossSecurity import *
     38  from Products.ZenRelations.RelSchema import *
     39  from Products.ZenRelations.ZenPropertyManager import Z_PROPERTIES
     40  from Products.ZenUtils.Search import makeCaseInsensitiveFieldIndex
     41  from Products.ZenUtils.Search import makeCaseInsensitiveKeywordIndex
     42  from Products.ZenUtils.Search import makePathIndex, makeMultiPathIndex
     43  from Products.ZenUtils.Utils import importClass, zenPath
     44  from Products.ZenWidgets import messaging
     45  from Products.ZenUtils.FakeRequest import FakeRequest
     46  from Products.Zuul.catalog.events import IndexingEvent
     47
     48  import RRDTemplate
     49  from DeviceOrganizer import DeviceOrganizer
     50  from ZenPackable import ZenPackable
     51  from TemplateContainer import TemplateContainer
     52
     53  _marker = "__MARKER___"
     54
     55 -def manage_addDeviceClass(context, id, title = None, REQUEST = None):
     56      """make a device class"""
     57      dc = DeviceClass(id, title)
     58      context._setObject(id, dc)
     59      if REQUEST is not None:
     60          REQUEST['RESPONSE'].redirect(context.absolute_url() + '/manage_main')
     61
     62
     63  addDeviceClass = DTMLFile('dtml/addDeviceClass',globals())
     64
     65
     66 -class DeviceClass(DeviceOrganizer, ZenPackable, TemplateContainer):
     67      """
     68      DeviceClass is a device organizer that manages the primary classification
     69      of device objects within the Zenoss system.  It manages properties
     70      that are inherited through acquisition that modify the behavior of
     71      many different sub systems within Zenoss.
     72      It also handles the creation of new devices in the system.
     73      """
     74
     75      # Organizer configuration
     76      dmdRootName = "Devices"
     77
     78      manageDeviceSearch = DTMLFile('dtml/manageDeviceSearch',globals())
     79      manageDeviceSearchResults = DTMLFile('dtml/manageDeviceSearchResults',
     80                                              globals())
     81
     82      portal_type = meta_type = event_key = "DeviceClass"
     83
     84      default_catalog = 'deviceSearch'
     85
     86      _properties = DeviceOrganizer._properties + (
     87                      {'id':'devtypes', 'type':'lines', 'mode':'w'},
     88                     )
     89
     90      _relations = DeviceOrganizer._relations + ZenPackable._relations + \
     91                  TemplateContainer._relations + (
     92          ("devices", ToManyCont(ToOne,"Products.ZenModel.Device","deviceClass")),
     93          )
     94
     95      # Screen action bindings (and tab definitions)
     96      factory_type_information = (
     97          {
     98              'id'             : 'DeviceClass',
     99              'meta_type'      : 'DeviceClass',
    100              'description'    : """Base class for all devices""",
    101              'icon'           : 'DeviceClass_icon.gif',
    102              'product'        : 'ZenModel',
    103              'factory'        : 'manage_addDeviceClass',
    104              'immediate_view' : 'deviceOrganizerStatus',
    105              'actions'        :
    106              (
    107                  { 'name'          : 'Classes'
    108                  , 'action'        : 'deviceOrganizerStatus'
    109                  , 'permissions'   : ( permissions.view, )
    110                  },
    111                  { 'name'          : 'Events'
    112                  , 'action'        : 'viewEvents'
    113                  , 'permissions'   : (  permissions.view, )
    114                  },
    115                  { 'name'          : 'Configuration Properties'
    116                  , 'action'        : 'zPropertyEdit'
    117                  , 'permissions'   : (permissions.view,)
    118                  },
    119                  { 'name'          : 'Templates'
    120                  , 'action'        : 'perfConfig'
    121                  , 'permissions'   : ('Manage DMD',)
    122                  },
    123              )
    124           },
    125          )
    126
    127      security = ClassSecurityInfo()
    128
    129 -    def getPeerDeviceClassNames(self, pyclass=None):
    130          """
    131          Return a list of all device paths that have the Python class pyclass
    132
    133          @param pyclass: Python class (default is this class)
    134          @type pyclass: Python class
    135          @return: list of device paths
    136          @rtype: list of strings
    137          """
    138          dcnames = []
    139          if pyclass == None:
    140              pyclass = self.getPythonDeviceClass()
    141          dclass = self.getDmdRoot("Devices")
    142          for orgname in dclass.getOrganizerNames():
    143              org = dclass.getOrganizer(orgname)
    144              if issubclass(org.getPythonDeviceClass(), pyclass):
    145                  dcnames.append(orgname)
    146          dcnames.sort(lambda a, b: cmp(a.lower(), b.lower()))
    147          return dcnames
    148
    149      deviceMoveTargets = getPeerDeviceClassNames
    150      childMoveTargets = getPeerDeviceClassNames
    151
    152
    153 -    def createInstance(self, id):
    154          """
    155          Create an instance based on its location in the device tree
    156          walk up the primary aq path looking for a python instance class that
    157          matches the name of the closest node in the device tree.
    158
    159          @param id: id in DMD path
    160          @type id: string
    161          @return: new device object
    162          @rtype: device object
    163          """
    164          pyClass = self.getPythonDeviceClass()
    165          dev = pyClass(id)
    166          self.devices._setObject(id, dev)
    167          return self.devices._getOb(id)
    168
    169
    170 -    def getPythonDeviceClass(self):
    171          """
    172          Return the Python class object to be used for device instances in this
    173          device class.  This is done by walking up the aq_chain of a deviceclass
    174          to find a node that has the same name as a Python class or has an
    175          attribute named zPythonClass that matches a Python class.
    176
    177          @return: device class
    178          @rtype: device class
    179          """
    180          from Device import Device
    181          cname = getattr(self, "zPythonClass", None)
    182          if cname:
    183              try:
    184                  return importClass(cname)
    185              except ImportError:
    186                  log.exception("Unable to import class " + cname)
    187          return Device
    188
    189
    190 -    def moveDevices(self, moveTarget, deviceNames=None, REQUEST=None):
    191          """
    192          Override default moveDevices because this is a contained relation.
    193          If the Python class bound to a DeviceClass is different we convert to
    194          the new Python class adding / removing relationships as needed.
    195
    196          @param moveTarget: organizer in DMD path
    197          @type moveTarget: string
    198          @param deviceNames: devices to move
    199          @type deviceNames: list of stringa
    200          @param REQUEST: Zope REQUEST object
    201          @type REQUEST: Zope REQUEST object
    202          """
    203          if not moveTarget or not deviceNames: return self()
    204          target = self.getDmdRoot(self.dmdRootName).getOrganizer(moveTarget)
    205          if type(deviceNames) == types.StringType: deviceNames = (deviceNames,)
    206          newPath = target.absolute_url_path() + '/'
    207          for devname in deviceNames:
    208              dev = self.findDeviceByIdExact(devname)
    209              if not dev: continue
    210              source = dev.deviceClass().primaryAq()
    211              oldPath = source.absolute_url_path() + '/'
    212              if dev.__class__ != target.getPythonDeviceClass():
    213                  import StringIO
    214                  from Products.ZenRelations.ImportRM import NoLoginImportRM
    215
    216                  def switchClass(o, module, klass):
    217                      """
    218                      Create an XML string representing the module in a
    219                      new class.
    220
    221                      @param o: file-type object
    222                      @type o: file-type object
    223                      @param module: location in DMD
    224                      @type module: string
    225                      @param klass: class name
    226                      @type klass: string
    227                      @return: XML representation of the class
    228                      @rtype: string
    229                      """
    230                      o.seek(0)
    231                      l = o.readline()
    232                      al = l[1:-2].split()
    233                      for i in range(len(al)):
    234                          if al[i].startswith('module'):
    235                              al[i] = "module='%s'" % module
    236                          elif al[i].startswith('class'):
    237                              al[i] = "class='%s'" % klass
    238                      nl = "<" + " ".join(al) + ">\n"
    239                      o.seek(0)
    240                      nf = ["<objects>", nl]
    241                      data = [line.replace(oldPath, newPath) \
    242                                 for line in o.readlines()[1:]]
    243                      nf.extend(data)
    244                      nf.append('</objects>')
    245                      return StringIO.StringIO("".join(nf))
    246
    247                  def devExport(d, module, klass):
    248                      """
    249                      Create an XML string representing the device d
    250                      at the DMD location module of type klass.
    251
    252                      @param module: location in DMD
    253                      @type module: string
    254                      @param klass: class name
    255                      @type klass: string
    256                      @return: XML representation of the class
    257                      @rtype: string
    258                      """
    259                      o = StringIO.StringIO()
    260                      d.exportXml(o)
    261                      return switchClass(o, module, klass)
    262
    263                  def devImport(xmlfile):
    264                      """
    265                      Load a new device from a file.
    266
    267                      @param xmlfile: file type object
    268                      @type xmlfile: file type object
    269                      """
    270                      im = NoLoginImportRM(target.devices)
    271                      im.loadObjectFromXML(xmlfile)
    272
    273                  module = target.zPythonClass
    274                  if module:
    275                      klass = target.zPythonClass.split('.')[-1]
    276                  else:
    277                      module = 'Products.ZenModel.Device'
    278                      klass = 'Device'
    279                  xmlfile = devExport(dev, module, klass)
    280                  log.info('Removing device %s from %s', devname, source)
    281                  source.devices._delObject(devname)
    282                  devImport(xmlfile)
    283              else:
    284                  dev._operation = 1
    285                  source.devices._delObject(devname)
    286                  target.devices._setObject(devname, dev)
    287              dev = target.devices._getOb(devname)
    288              dev.setLastChange()
    289              dev.setAdminLocalRoles()
    290              dev.index_object()
    291              transaction.commit()
    292
    293
    294      security.declareProtected(ZEN_DELETE_DEVICE, 'removeDevices')
    295 -    def removeDevices(self, deviceNames=None, deleteStatus=False,
    296                      deleteHistory=False, deletePerf=False,REQUEST=None):
    297          """
    298          See IManageDevice overrides DeviceManagerBase.removeDevices
    299          """
    300          if not deviceNames: return self()
    301          if type(deviceNames) in types.StringTypes: deviceNames = (deviceNames,)
    302          for devname in deviceNames:
    303              dev = self.findDevice(devname)
    304              dev.deleteDevice(deleteStatus=deleteStatus,
    305                          deleteHistory=deleteHistory, deletePerf=deletePerf)
    306          if REQUEST:
    307              messaging.IMessageSender(self).sendToBrowser(
    308                  'Devices Deleted',
    309                  "Devices were deleted: %s." % ', '.join(deviceNames)
    310              )
    311              if REQUEST.has_key('oneKeyValueSoInstanceIsntEmptyAndEvalToFalse'):
    312                  return 'Devices were deleted: %s.' % ', '.join(deviceNames)
    313              else:
    314                  return self.callZenScreen(REQUEST)
    315
    316
    317      security.declareProtected('View', 'getEventDeviceInfo')
    318 -    def getEventDeviceInfo(self):
    319          """
    320          getEventDeviceInfo() -> return the info for NcoEventPopulator
    321          """
    322          deviceInfo = {}
    323          for device in self.getSubDevices():
    324              systemNames = []
    325              for sys in device.systems.objectValuesAll():
    326                  systemNames.append(sys.getOrganizerName())
    327              systemNames = "|".join(systemNames)
    328              location = device.getLocationName()
    329              if not location: location = "Unknown"
    330              deviceInfo[device.id] = (systemNames, location,
    331                                      device.productionState,
    332                                      device.getDeviceClassPath())
    333          return deviceInfo
    334
    335
    336      security.declareProtected('View', 'getDeviceWinInfo')
    337 -    def getDeviceWinInfo(self, lastPoll=0, eventlog=False):
    338          """
    339          Return list of (devname,user,passwd,url) for each device.
    340          user and passwd are used to connect via wmi.
    341          """
    342          ffunc = None
    343          starttime = time.time()
    344          if lastPoll > 0:
    345              lastPoll = DateTime.DateTime(lastPoll)
    346              ffunc = lambda x: x.getSnmpLastCollection() > lastPoll
    347          if eventlog:
    348              ffunc = lambda x: x.zWinEventlog
    349          devinfo = []
    350          for dev in self.getSubDevices(devfilter=ffunc):
    351              if not dev.monitorDevice(): continue
    352              if dev.getProperty('zWmiMonitorIgnore', False): continue
    353              user = dev.getProperty('zWinUser','')
    354              passwd = dev.getProperty( 'zWinPassword', '')
    355              sev = dev.getProperty( 'zWinEventlogMinSeverity', '')
    356              devinfo.append((dev.id, str(user), str(passwd), sev, dev.absolute_url()))
    357          return starttime, devinfo
    358
    359
    360 -    def getWinServices(self):
    361          """
    362          Return a list of (devname, user, passwd, {'EvtSys':0,'Exchange':0})
    363          """
    364          svcinfo = []
    365          allsvcs = {}
    366          for s in self.getSubComponents("WinService"):
    367              svcs=allsvcs.setdefault(s.hostname(),{})
    368              name = s.name()
    369              if type(name) == type(u''):
    370                  name = name.encode(s.zCollectorDecoding)
    371              svcs[name] = (s.getStatus(), s.getAqProperty('zFailSeverity'))
    372          for dev in self.getSubDevices():
    373              if not dev.monitorDevice(): continue
    374              if dev.getProperty( 'zWmiMonitorIgnore', False): continue
    375              svcs = allsvcs.get(dev.getId(), {})
    376              if not svcs and not dev.zWinEventlog: continue
    377              user = dev.getProperty('zWinUser','')
    378              passwd = dev.getProperty( 'zWinPassword', '')
    379              svcinfo.append((dev.id, str(user), str(passwd), svcs))
    380          return svcinfo
    381
    382
    383      security.declareProtected('View', 'searchDeviceSummary')
    384 -    def searchDeviceSummary(self, query):
    385          """
    386          Search device summary index and return device objects
    387          """
    388          if not query: return []
    389          zcatalog = self._getCatalog()
    390          if not zcatalog: return []
    391          results = zcatalog({'summary':query})
    392          return self._convertResultsToObj(results)
    393
    394
    395      security.declareProtected('View', 'searchInterfaces')
    396 -    def searchInterfaces(self, query):
    397          """
    398          Search interfaces index and return interface objects
    399          """
    400          if not query: return []
    401          zcatalog = getattr(self, 'interfaceSearch', None)
    402          if not zcatalog: return []
    403          results = zcatalog(query)
    404          return self._convertResultsToObj(results)
    405
    406
    407 -    def _convertResultsToObj(self, results):
    408          devices = []
    409          for brain in results:
    410              try:
    411                  devobj = self.getObjByPath(brain.getPrimaryId)
    412                  devices.append(devobj)
    413              except KeyError:
    414                  log.warn("bad path '%s' in index" % brain.getPrimaryId)
    415
    416          return devices
    417
    418 -    def _findDevice(self, devicename, useTitle=True):
    419          """
    420          Returns all devices whose ip/id/title match devicename.
    421          ip/id matches are at the front of the list.
    422
    423          @rtype: list of brains
    424          """
    425          idIpQuery = Or( MatchGlob('id', devicename),
    426                          Eq('getDeviceIp', devicename) )
    427          if useTitle:
    428              titleOrIdQuery = MatchGlob('titleOrId', devicename)
    429              query = Or( idIpQuery, titleOrIdQuery )
    430              rankSort = RankByQueries_Max( ( idIpQuery, 16 ),
    431                                            ( titleOrIdQuery, 8 ) )
    432              devices = self._getCatalog().evalAdvancedQuery(query, (rankSort,))
    433          else:
    434              devices = self._getCatalog().evalAdvancedQuery(idIpQuery)
    435          return devices
    436
    437 -    def findDevicePath(self, devicename):
    438          """
    439          Look up a device and return its path
    440          """
    441          ret = self._findDevice(devicename)
    442          if not ret: return ""
    443          return ret[0].getPrimaryId
    444
    445 -    def findDevice(self, devicename):
    446          """
    447          Returns the first device whose ip/id matches devicename.  If
    448          there is no ip/id match, return the first device whose title
    449          matches devicename.
    450          """
    451          ret = self._findDevice(devicename)
    452          if ret: return ret[0].getObject()
    453
    454 -    def findDeviceByIdOrIp(self, devicename):
    455          """
    456          Returns the first device that has an ip/id that matches devicename
    457          """
    458          ret = self._findDevice( devicename, False )
    459          if ret: return ret[0].getObject()
    460
    461 -    def findDeviceByIdExact(self, devicename):
    462          """
    463          Look up device in catalog and return it.  devicename
    464          must match device id exactly
    465          """
    466          for brains in self._getCatalog()(id=devicename):
    467              dev = brains.getObject()
    468              if dev.id == devicename:
    469                  return dev
    470
    471 -    def findDevicePingStatus(self, devicename):
    472          """
    473          look up device in catalog and return its pingStatus
    474          """
    475          dev = self.findDevice(devicename)
    476          if dev: return dev.getPingStatusNumber()
    477
    478
    479 -    def getSubComponents(self, meta_type="", monitored=True):
    480          """
    481          Return generator of components, by meta_type if specified
    482          """
    483          zcat = self.componentSearch
    484          res = zcat({'meta_type': meta_type, 'monitored': monitored})
    485          for b in res:
    486              try:
    487                  c = self.getObjByPath(b.getPrimaryId)
    488                  if self.checkRemotePerm("View", c):
    489                      yield c
    490              except KeyError:
    491                  log.warn("bad path '%s' in index 'componentSearch'",
    492                              b.getPrimaryId)
    493
    494
    495      security.declareProtected("ZenCommon", "getMonitoredComponents")
    496 -    def getMonitoredComponents(self):
    497          """
    498          Return monitored components for devices within this DeviceDeviceClass
    499          """
    500          return self.getSubComponents()
    501
    502
    503      security.declareProtected('View', 'getRRDTemplates')
    504 -    def getRRDTemplates(self, context=None):
    505          """
    506          Return the actual RRDTemplate instances.
    507          """
    508          templates = {}
    509          if not context: context = self
    510          mychain = aq_chain(context)
    511          mychain.reverse()
    512          for obj in mychain:
    513              try:
    514                  templates.update(dict([(t.id, t) for t in obj.rrdTemplates()]))
    515              except AttributeError:
    516                  pass
    517          return templates.values()
    518
    519
    520 -    def getAvailableTemplates(self):
    521          """
    522          Returns all available templates
    523          """
    524          def cmpTemplates(a, b):
    525              return cmp(a.id.lower(), b.id.lower())
    526          templates = self.getRRDTemplates()
    527          templates.sort(cmpTemplates)
    528          pdc = self.getPythonDeviceClass()
    529          return [ t for t in templates
    530              if issubclass(pdc, t.getTargetPythonClass()) ]
    531
    532
    533 -    def bindTemplates(self, ids=(), REQUEST=None):
    534          """
    535          This will bind available templates to the zDeviceTemplates
    536          """
    537          return self.setZenProperty('zDeviceTemplates', ids, REQUEST)
    538
    539 -    def removeZDeviceTemplates(self, REQUEST=None):
    540          """
    541          Deletes the local zProperty, zDeviceTemplates
    542          """
    543          if self.getPrimaryPath()[-2:] == ('dmd', 'Devices'):
    544              self.setZenProperty('zDeviceTemplates', ['Device'])
    545          else:
    546              self.deleteZenProperty('zDeviceTemplates')
    547          messaging.IMessageSender(self).sendToBrowser(
    548              'Bindings Reset',
    549              'Template bindings for this class were reset.'
    550          )
    551          return self.callZenScreen(REQUEST)
    552
    553
    554 -    def getAllRRDTemplates(self, rrdts=None):
    555          """
    556          Return all RRDTemplates at this level and below in the object tree.
    557          If rrdts is provided then it must be a list of RRDTemplates which
    558          will be extended with the templates from here and returned.
    559
    560          The original getAllRRDTemplates() method has been renamed
    561          getAllRRDTemplatesPainfully().  It walks the object tree looking
    562          for templates which is a very slow way of going about things.
    563          The newer RRDTemplate.YieldAllRRDTemplate() method uses the
    564          searchRRDTemplates catalog to speed things up dramatically.
    565          YieldAllRRDTemplates is smart enough to revert to
    566          getAllRRDTemplatesPainfully if the catalog is not present.
    567
    568          The searchRRDTemplates catalog was added in 2.2
    569          """
    570          if rrdts == None:
    571              rrdts = []
    572          rrdts.extend(RRDTemplate.YieldAllRRDTemplates(self))
    573          return rrdts
    574
    575
    576 -    def getAllRRDTemplatesPainfully(self, rrdts=None):
    577          """
    578          RRDTemplate.YieldAllRRDTemplates() is probably what you want.
    579          It takes advantage of the searchRRDTemplates catalog to get
    580          much better performance.  This method iterates over objects looking
    581          for templates which is a slow, painful process.
    582          """
    583          if rrdts is None: rrdts = []
    584          rrdts.extend(self.rrdTemplates())
    585          for dev in self.devices():
    586              rrdts += dev.objectValues('RRDTemplate')
    587              for comps in dev.getDeviceComponents():
    588                  rrdts += comps.objectValues('RRDTemplate')
    589          for child in self.children():
    590              child.getAllRRDTemplatesPainfully(rrdts)
    591          return rrdts
    592
    593
    594      security.declareProtected('Add DMD Objects', 'manage_addRRDTemplate')
    595 -    def manage_addRRDTemplate(self, id, REQUEST=None):
    596          """
    597          Add an RRDTemplate to this DeviceClass.
    598          """
    599          if not id: return self.callZenScreen(REQUEST)
    600          id = self.prepId(id)
    601          org = RRDTemplate.RRDTemplate(id)
    602          self.rrdTemplates._setObject(org.id, org)
    603          if REQUEST:
    604              messaging.IMessageSender(self).sendToBrowser(
    605                  'Template Added',
    606                  'The "%s" template has been created.' % id
    607              )
    608              return self.callZenScreen(REQUEST)
    609
    610
    611      security.declareProtected(ZEN_EDIT_LOCAL_TEMPLATES,
    612                                'manage_copyRRDTemplates')
    613 -    def manage_copyRRDTemplates(self, ids=(), REQUEST=None):
    614          """
    615          Put a reference to the objects named in ids in the clip board
    616          """
    617          if not ids: return self.callZenScreen(REQUEST)
    618          ids = [ id for id in ids if self.rrdTemplates._getOb(id, None) != None]
    619          if not ids: return self.callZenScreen(REQUEST)
    620          cp = self.rrdTemplates.manage_copyObjects(ids)
    621          if REQUEST:
    622              resp=REQUEST['RESPONSE']
    623              resp.setCookie('__cp', cp, path='/zport/dmd')
    624              REQUEST['__cp'] = cp
    625              messaging.IMessageSender(self).sendToBrowser(
    626                  'Templates Copied',
    627                  'Templates have been copied: %s' % ', '.join(ids)
    628              )
    629              return self.callZenScreen(REQUEST)
    630          return cp
    631
    632
    633      security.declareProtected(ZEN_EDIT_LOCAL_TEMPLATES,
    634                                'manage_pasteRRDTemplates')
    635 -    def manage_pasteRRDTemplates(self, moveTarget=None, cb_copy_data=None, REQUEST=None):
    636          """
    637          Paste RRDTemplates that have been copied before.
    638          """
    639          cp = None
    640          if cb_copy_data: cp = cb_copy_data
    641          elif REQUEST:
    642              cp = REQUEST.get("__cp",None)
    643
    644          if cp:
    645              if moveTarget:
    646                  target = self.getDmdRoot(self.dmdRootName).getOrganizer(moveTarget)
    647              else:
    648                  target = self
    649              target.rrdTemplates.manage_pasteObjects(cp)
    650          else:
    651              target = None
    652
    653          if REQUEST:
    654              REQUEST['RESPONSE'].setCookie('__cp', 'deleted', path='/zport/dmd',
    655                              expires='Wed, 31-Dec-97 23:59:59 GMT')
    656              REQUEST['__cp'] = None
    657              if target:
    658                  message = "Template(s) copied to %s" % moveTarget
    659              else:
    660                  message = None
    661              messaging.IMessageSender(self).sendToBrowser(
    662                  'Template(s) Copied',
    663                  message
    664              )
    665              if not isinstance(REQUEST, FakeRequest):
    666                  url = target.getPrimaryUrlPath() + '/perfConfig'
    667                  if message:
    668                      url += '?message=%s' % message
    669                  REQUEST['RESPONSE'].redirect(url)
    670              else:
    671                  return self.callZenScreen(REQUEST)
    672
    673
    674      security.declareProtected(ZEN_EDIT_LOCAL_TEMPLATES,
    675                                'manage_copyAndPasteRRDTemplates')
    676 -    def manage_copyAndPasteRRDTemplates(self, ids=(), copyTarget=None, REQUEST=None):
    677          """
    678          Copy the selected templates into the specified device class.
    679          """
    680          if not ids:
    681              messaging.IMessageSender(self).sendToBrowser(
    682                  'Invalid',
    683                  'No templates were selected.',
    684                  priority=messaging.WARNING
    685              )
    686              return self.callZenScreen(REQUEST)
    687          if copyTarget is None:
    688              messaging.IMessageSender(self).sendToBrowser(
    689                  'Invalid',
    690                  'No target was selected.',
    691                  priority=messaging.WARNING
    692              )
    693              return self.callZenScreen(REQUEST)
    694          cp = self.manage_copyRRDTemplates(ids)
    695          return self.manage_pasteRRDTemplates(copyTarget, cp, REQUEST)
    696
    697
    698      security.declareProtected(ZEN_EDIT_LOCAL_TEMPLATES,
    699                                'manage_deleteRRDTemplates')
    700 -    def manage_deleteRRDTemplates(self, ids=(), paths=(), REQUEST=None):
    701          """
    702          Delete RRDTemplates from this DeviceClass
    703          (skips ones in other Classes)
    704          """
    705          if not ids and not paths:
    706              return self.callZenScreen(REQUEST)
    707          for id in ids:
    708              if (getattr(aq_base(self), 'rrdTemplates', False)
    709                  and getattr(aq_base(self.rrdTemplates),id,False)):
    710                  self.rrdTemplates._delObject(id)
    711          for path in paths:
    712              temp = self.dmd.getObjByPath(path)
    713              if temp.deviceClass():
    714                  temp.deviceClass().rrdTemplates._delObject(temp.id)
    715              else:
    716                  temp.device()._delObject(temp.id)
    717          if REQUEST:
    718              messaging.IMessageSender(self).sendToBrowser(
    719                  'Templates Deleted',
    720                  'Templates were deleted: %s' % ", ".join(ids)
    721              )
    722              return self.callZenScreen(REQUEST)
    723
    724
    725 -    def createCatalog(self):
    726          """
    727          Make the catalog for device searching
    728          """
    729          from Products.ZCatalog.ZCatalog import manage_addZCatalog
    730
    731          # Make catalog for Devices
    732          manage_addZCatalog(self, self.default_catalog,
    733              self.default_catalog)
    734          zcat = self._getOb(self.default_catalog)
    735          cat = zcat._catalog
    736          for idxname in ['id',
    737              'getDeviceIp','getDeviceClassPath','getProdState','titleOrId']:
    738              cat.addIndex(idxname, makeCaseInsensitiveFieldIndex(idxname))
    739          cat.addIndex('getPhysicalPath', makePathIndex('getPhysicalPath'))
    740          cat.addIndex('path', makeMultiPathIndex('path'))
    741          zcat.addColumn('getPrimaryId')
    742          zcat.addColumn('id')
    743          zcat.addColumn('path')
    744
    745          # make catalog for device components
    746          manage_addZCatalog(self, "componentSearch", "componentSearch")
    747          zcat = self._getOb("componentSearch")
    748          cat = zcat._catalog
    749          cat.addIndex('meta_type', makeCaseInsensitiveFieldIndex('meta_type'))
    750          cat.addIndex('getParentDeviceName',
    751              makeCaseInsensitiveFieldIndex('getParentDeviceName'))
    752          cat.addIndex('getCollectors',
    753              makeCaseInsensitiveKeywordIndex('getCollectors'))
    754          # XXX still using regular FieldIndex here for now, since this contains
    755          # binary information
    756          zcat.addIndex('monitored', 'FieldIndex')
    757          zcat.addColumn('getPrimaryId')
    758          zcat.addColumn('meta_type')
    759
    760
    761 -    def reIndex(self):
    762          """
    763          Go through all devices in this tree and reindex them.
    764          """
    765          zcat = getToolByName(self, self.default_catalog)
    766          zcat.manage_catalogClear()
    767          self.componentSearch.manage_catalogClear()
    768          transaction.savepoint()
    769          for dev in self.getSubDevicesGen_recursive():
    770              dev.index_object()
    771              notify(IndexingEvent(dev))
    772              for comp in dev.getDeviceComponentsNoIndexGen():
    773                  comp.index_object()
    774                  notify(IndexingEvent(comp))
    775              transaction.savepoint()
    776
    777
    778 -    def buildDeviceTreeProperties(self):
    779          """
    780          Create a new device tree with a default configuration
    781          """
    782          devs = self.getDmdRoot("Devices")
    783          for id, value, type in Z_PROPERTIES:
    784              if not devs.hasProperty(id):
    785                  devs._setProperty(id, value, type)
    786
    787 -    def zenPropertyOptions(self, propname):
    788          """
    789          Provide a set of default options for a zProperty
    790
    791          @param propname: zProperty name
    792          @type propname: string
    793          @return: list of zProperty options
    794          @rtype: list
    795          """
    796          if propname == 'zCollectorPlugins':
    797              from Products.DataCollector.Plugins import loadPlugins
    798              names = [ldr.pluginName for ldr in loadPlugins(self.dmd)]
    799              names.sort()
    800              return names
    801          if propname == 'zCommandProtocol':
    802              return ['ssh', 'telnet']
    803          if propname == 'zSnmpVer':
    804              return ['v1', 'v2c', 'v3']
    805          if propname == 'zSnmpAuthType':
    806              return ['', 'MD5', 'SHA']
    807          if propname == 'zSnmpPrivType':
    808              return ['', 'DES', 'AES']
    809          return DeviceOrganizer.zenPropertyOptions(self, propname)
    810
    811
    812 -    def pushConfig(self, REQUEST=None):
    813          """
    814          This will result in a push of all the devices to live collectors
    815
    816          @param REQUEST: Zope REQUEST object
    817          @type REQUEST: Zope REQUEST object
    818          """
    819          self._p_changed = True
    820          if REQUEST:
    821              messaging.IMessageSender(self).sendToBrowser(
    822                  'Pushed Changes',
    823                  'Changes to %s were pushed to collectors.' % self.id
    824              )
    825              return self.callZenScreen(REQUEST)
    826
    827
    828      security.declareProtected('Change Device', 'setLastChange')
    829 -    def setLastChange(self, value=None):
    830          """
    831          Set the changed datetime for this device.
    832
    833          @param value: changed datetime. Default is now.
    834          @type value: number
    835          """
    836          if value is None:
    837              value = time.time()
    838          self._lastChange = float(value)
    839
    840 -    def register_devtype(self, description, protocol):
    841          """
    842          Define this class in terms of a description of the devices it should
    843          contain and the protocol by which they would normally be monitored.
    844          """
    845          t = (description, protocol)
    846          if not hasattr(self, 'devtypes'):
    847              self._setProperty('devtypes', [], 'lines')
    848          if t not in self.devtypes:
    849              self.devtypes.append(t)
    850              self._p_changed = True
    851
    852 -    def unregister_devtype(self, description, protocol):
    853          t = (description, protocol)
    854          if hasattr(self, 'devtypes'):
    855              if t in self.devtypes:
    856                  self.devtypes.remove(t)
    857                  self._p_changed = True
    858
    859
    860  InitializeClass(DeviceClass)
    861