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

# Source Code for Module Products.ZenModel.DeviceClass

      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  __doc__="""DeviceClass
     12  The primary organizer of device objects, managing zProperties and
     13  their acquisition.
     14  """
     15
     16  import time
     17  from cStringIO import StringIO
     18  import transaction
     19  import logging
     20  log = logging.getLogger('zen.DeviceClass')
     21
     22  import DateTime
     23  from zope.event import notify
     24  from zope.container.contained import ObjectMovedEvent
     25  from Globals import DTMLFile
     26  from Globals import InitializeClass
     27  from Acquisition import aq_base, aq_chain
     28  from AccessControl import ClassSecurityInfo
     29  from AccessControl import Permissions as permissions
     30  from ZODB.transact import transact
     31
     32  from Products.AdvancedQuery import MatchGlob, Or, Eq, RankByQueries_Max, And
     33  from Products.CMFCore.utils import getToolByName
     34  from Products.ZenMessaging.ChangeEvents.events import DeviceClassMovedEvent
     35  from Products.ZenModel.ZenossSecurity import *
     36  from Products.ZenRelations.RelSchema import *
     37  from Products.ZenRelations.ZenPropertyManager import Z_PROPERTIES
     38  from Products.ZenUtils.Search import makeCaseInsensitiveFieldIndex, makeCaseInsensitiveFieldIndex, makeCaseSensitiveKeywordIndex
     39  from Products.ZenUtils.Search import makeCaseInsensitiveKeywordIndex
     40  from Products.ZenUtils.Search import makePathIndex, makeMultiPathIndex
     41  from Products.ZenUtils.Utils import importClass, zenPath
     42  from Products.ZenUtils.guid.interfaces import IGlobalIdentifier
     43  from Products.ZenWidgets import messaging
     44  from Products.ZenUtils.FakeRequest import FakeRequest
     45  from Products.Zuul.catalog.events import IndexingEvent
     46  from Products.Zuul.interfaces import ICatalogTool
     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(key=lambda a: a.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      @transact
    190 -    def _moveDevice(self, devname, target, targetClass):
    191          dev = self.findDeviceByIdExact(devname)
    192          if not dev:
    193              return
    194          guid = IGlobalIdentifier(dev).create()
    195          source = dev.deviceClass().primaryAq()
    196
    197          notify(DeviceClassMovedEvent(dev, dev.deviceClass().primaryAq(), target))
    198
    199          exported = False
    200          oldPath = source.absolute_url_path() + '/'
    201          if dev.__class__ != targetClass:
    202              from Products.ZenRelations.ImportRM import NoLoginImportRM
    203
    204              def switchClass(o, module, klass):
    205                  """
    206                  Create an XML string representing the module in a
    207                  new class.
    208
    209                  @param o: file-type object
    210                  @type o: file-type object
    211                  @param module: location in DMD
    212                  @type module: string
    213                  @param klass: class name
    214                  @type klass: string
    215                  @return: XML representation of the class
    216                  @rtype: string
    217                  """
    218                  from xml.dom.minidom import parse
    219
    220                  # Note: strips almost everything out of the move
    221                  #       as the new class may not have the same relations etc.
    222                  #       For example, moving SNMP host to a VMware class.
    223                  o.seek(0)
    224                  dom = parse(o)
    225                  root = dom.childNodes[0]
    226                  root.setAttribute('module', module)
    227                  root.setAttribute('class', klass)
    228                  for obj in root.childNodes:
    229                      if obj.nodeType != obj.ELEMENT_NODE:
    230                          continue # Keep XML-tree baggage
    231
    232                      name = obj.getAttribute('id')
    233                      if obj.tagName == 'property':
    234                          # Only remove modeler plugins, templates
    235                          # and z*Ignore zprops
    236                          if name in ('zCollectorPlugins', 'zDeviceTemplates') or \
    237                             name.endswith('Ignore'):
    238                              root.removeChild(obj)
    239
    240                      elif obj.tagName == 'toone' and \
    241                           name in ('perfServer', 'location'):
    242                          pass # Preserve collector name and location
    243
    244                      elif obj.tagName == 'tomany' and \
    245                           name in ('systems', 'groups'):
    246                          pass # Preserve the Groups and Systems groupings
    247
    248                      elif obj.tagName == 'tomanycont' and \
    249                           name in ('maintenanceWindows',
    250                                    'adminRoles',
    251                                    'userCommands'):
    252                          pass # Preserve maintenance windows, admins, commands
    253
    254                      else:
    255                          log.debug("Removing %s element id='%s'",
    256                                       obj.tagName, name)
    257                          root.removeChild(obj)
    258
    259                  importFile = StringIO()
    260                  dom.writexml(importFile)
    261                  importFile.seek(0)
    262                  return importFile
    263
    264              def devExport(d, module, klass):
    265                  """
    266                  Create an XML string representing the device d
    267                  at the DMD location module of type klass.
    268
    269                  @param module: location in DMD
    270                  @type module: string
    271                  @param klass: class name
    272                  @type klass: string
    273                  @return: XML representation of the class
    274                  @rtype: string
    275                  """
    276                  o = StringIO()
    277                  d.exportXml(o, exportPasswords=True)
    278                  return switchClass(o, module, klass)
    279
    280              def devImport(xmlfile):
    281                  """
    282                  Load a new device from a file.
    283
    284                  @param xmlfile: file type object
    285                  @type xmlfile: file type object
    286                  """
    287                  im = NoLoginImportRM(target.devices)
    288                  im.loadObjectFromXML(xmlfile)
    289                  im.processLinks()
    290
    291              module = target.zPythonClass
    292              if module:
    293                  klass = target.zPythonClass.split('.')[-1]
    294              else:
    295                  module = 'Products.ZenModel.Device'
    296                  klass = 'Device'
    297              log.debug('Exporting device %s from %s', devname, source)
    298              xmlfile = devExport(dev, module, klass)
    299              log.debug('Removing device %s from %s', devname, source)
    300              source.devices._delObject(devname)
    301              log.debug('Importing device %s to %s', devname, target)
    302              devImport(xmlfile)
    303              exported = True
    304          else:
    305              dev._operation = 1
    306              source.devices._delObject(devname)
    307              target.devices._setObject(devname, dev)
    308          dev = target.devices._getOb(devname)
    309          IGlobalIdentifier(dev).guid = guid
    310          dev.setLastChange()
    311          dev.setAdminLocalRoles()
    312          dev.index_object()
    313          notify(IndexingEvent(dev, idxs=('path', 'searchKeywords'),
    314                               update_metadata=True))
    315
    316          return exported
    317
    318 -    def moveDevices(self, moveTarget, deviceNames=None, REQUEST=None):
    319          """
    320          Override default moveDevices because this is a contained relation.
    321          If the Python class bound to a DeviceClass is different we convert to
    322          the new Python class adding / removing relationships as needed.
    323
    324          @param moveTarget: organizer in DMD path
    325          @type moveTarget: string
    326          @param deviceNames: devices to move
    327          @type deviceNames: list of stringa
    328          @param REQUEST: Zope REQUEST object
    329          @type REQUEST: Zope REQUEST object
    330          """
    331          if not moveTarget or not deviceNames: return self()
    332          target = self.getDmdRoot(self.dmdRootName).getOrganizer(moveTarget)
    333          if isinstance(deviceNames, basestring): deviceNames = (deviceNames,)
    334          targetClass = target.getPythonDeviceClass()
    335          numExports = 0
    336          for devname in deviceNames:
    337              devicewasExported = self._moveDevice(devname, target, targetClass)
    338              if devicewasExported:
    339                  numExports += 1
    340          return numExports
    341
    342
    343      security.declareProtected(ZEN_DELETE_DEVICE, 'removeDevices')
    344 -    def removeDevices(self, deviceNames=None, deleteStatus=False,
    345                      deleteHistory=False, deletePerf=False,REQUEST=None):
    346          """
    347          See IManageDevice overrides DeviceManagerBase.removeDevices
    348          """
    349          if not deviceNames: return self()
    350          if isinstance(deviceNames, basestring): deviceNames = (deviceNames,)
    351          for devname in deviceNames:
    352              dev = self.findDevice(devname)
    353              dev.deleteDevice(deleteStatus=deleteStatus,
    354                          deleteHistory=deleteHistory, deletePerf=deletePerf)
    355          if REQUEST:
    356              messaging.IMessageSender(self).sendToBrowser(
    357                  'Devices Deleted',
    358                  "Devices were deleted: %s." % ', '.join(deviceNames)
    359              )
    360              if REQUEST.has_key('oneKeyValueSoInstanceIsntEmptyAndEvalToFalse'):
    361                  return 'Devices were deleted: %s.' % ', '.join(deviceNames)
    362              else:
    363                  return self.callZenScreen(REQUEST)
    364
    365
    366      security.declareProtected('View', 'getEventDeviceInfo')
    367 -    def getEventDeviceInfo(self):
    368          """
    369          getEventDeviceInfo() -> return the info for NcoEventPopulator
    370          """
    371          deviceInfo = {}
    372          for device in self.getSubDevices():
    373              systemNames = []
    374              for sys in device.systems.objectValuesAll():
    375                  systemNames.append(sys.getOrganizerName())
    376              systemNames = "|".join(systemNames)
    377              location = device.getLocationName()
    378              if not location: location = "Unknown"
    379              deviceInfo[device.id] = (systemNames, location,
    380                                      device.productionState,
    381                                      device.getDeviceClassPath())
    382          return deviceInfo
    383
    384
    385      security.declareProtected('View', 'getDeviceWinInfo')
    386 -    def getDeviceWinInfo(self, lastPoll=0, eventlog=False):
    387          """
    388          Return list of (devname,user,passwd,url) for each device.
    389          user and passwd are used to connect via wmi.
    390          """
    391          ffunc = None
    392          starttime = time.time()
    393          if lastPoll > 0:
    394              lastPoll = DateTime.DateTime(lastPoll)
    395              ffunc = lambda x: x.getSnmpLastCollection() > lastPoll
    396          if eventlog:
    397              ffunc = lambda x: x.getProperty('zWinEventlog', False)
    398          devinfo = []
    399          for dev in self.getSubDevices(devfilter=ffunc):
    400              if not dev.monitorDevice(): continue
    401              if dev.getProperty('zWmiMonitorIgnore', False): continue
    402              user = dev.getProperty('zWinUser','')
    403              passwd = dev.getProperty( 'zWinPassword', '')
    404              sev = dev.getProperty( 'zWinEventlogMinSeverity', '')
    405              devinfo.append((dev.id, str(user), str(passwd), sev, dev.absolute_url()))
    406          return starttime, devinfo
    407
    408
    409 -    def getWinServices(self):
    410          """
    411          Return a list of (devname, user, passwd, {'EvtSys':0,'Exchange':0})
    412          """
    413          svcinfo = []
    414          allsvcs = {}
    415          for s in self.getSubComponents("WinService"):
    416              svcs=allsvcs.setdefault(s.hostname(),{})
    417              name = s.name()
    418              if isinstance(name, unicode):
    419                  name = name.encode(s.zCollectorDecoding)
    420              svcs[name] = (s.getStatus(), s.getAqProperty('zFailSeverity'))
    421          for dev in self.getSubDevices():
    422              if not dev.monitorDevice(): continue
    423              if dev.getProperty( 'zWmiMonitorIgnore', False): continue
    424              svcs = allsvcs.get(dev.getId(), {})
    425              if not svcs and not dev.getProperty('zWinEventlog', False): continue
    426              user = dev.getProperty('zWinUser','')
    427              passwd = dev.getProperty( 'zWinPassword', '')
    428              svcinfo.append((dev.id, str(user), str(passwd), svcs))
    429          return svcinfo
    430
    431
    432      security.declareProtected('View', 'searchDeviceSummary')
    433 -    def searchDeviceSummary(self, query):
    434          """
    435          Search device summary index and return device objects
    436          """
    437          if not query: return []
    438          zcatalog = self._getCatalog()
    439          if not zcatalog: return []
    440          results = zcatalog({'summary':query})
    441          return self._convertResultsToObj(results)
    442
    443
    444      security.declareProtected('View', 'searchInterfaces')
    445 -    def searchInterfaces(self, query):
    446          """
    447          Search interfaces index and return interface objects
    448          """
    449          if not query: return []
    450          zcatalog = getattr(self, 'interfaceSearch', None)
    451          if not zcatalog: return []
    452          results = zcatalog(query)
    453          return self._convertResultsToObj(results)
    454
    455
    456 -    def _convertResultsToObj(self, results):
    457          devices = []
    458          for brain in results:
    459              try:
    460                  devobj = self.getObjByPath(brain.getPrimaryId)
    461                  devices.append(devobj)
    462              except KeyError:
    463                  log.warn("bad path '%s' in index" % brain.getPrimaryId)
    464
    465          return devices
    466
    467 -    def _findDevice(self, devicename, useTitle=True):
    468          """
    469          Returns all devices whose ip/id/title match devicename.
    470          ip/id matches are at the front of the list.
    471
    472          @rtype: list of brains
    473          """
    474          idIpQuery = Or( MatchGlob('id', devicename),
    475                          Eq('getDeviceIp', devicename) )
    476          if useTitle:
    477              titleOrIdQuery = MatchGlob('titleOrId', devicename)
    478              query = Or( idIpQuery, titleOrIdQuery )
    479              rankSort = RankByQueries_Max( ( idIpQuery, 16 ),
    480                                            ( titleOrIdQuery, 8 ) )
    481              devices = self._getCatalog().evalAdvancedQuery(query, (rankSort,))
    482          else:
    483              devices = self._getCatalog().evalAdvancedQuery(idIpQuery)
    484          return devices
    485
    486 -    def findDevicePath(self, devicename):
    487          """
    488          Look up a device and return its path
    489          """
    490          ret = self._findDevice(devicename)
    491          if not ret: return ""
    492          return ret[0].getPrimaryId
    493
    494 -    def findDevice(self, devicename):
    495          """
    496          Returns the first device whose ip/id matches devicename.  If
    497          there is no ip/id match, return the first device whose title
    498          matches devicename.
    499          """
    500          ret = self._findDevice(devicename)
    501          if ret: return ret[0].getObject()
    502
    503 -    def findDeviceByIdOrIp(self, devicename):
    504          """
    505          Returns the first device that has an ip/id that matches devicename
    506          """
    507          ret = self._findDevice( devicename, False )
    508          if ret: return ret[0].getObject()
    509
    510 -    def findDeviceByIdExact(self, devicename):
    511          """
    512          Look up device in catalog and return it.  devicename
    513          must match device id exactly
    514          """
    515          for brains in self._getCatalog()(id=devicename):
    516              dev = brains.getObject()
    517              if dev.id == devicename:
    518                  return dev
    519
    520 -    def findDevicePingStatus(self, devicename):
    521          """
    522          look up device in catalog and return its pingStatus
    523          """
    524          dev = self.findDevice(devicename)
    525          if dev: return dev.getPingStatusNumber()
    526
    527
    528 -    def getSubComponents(self, meta_type="", monitored=True):
    529          """
    530          Return generator of components, by meta_type if specified
    531          """
    532          catalog = ICatalogTool(self)
    533          COMPONENT = 'Products.ZenModel.DeviceComponent.DeviceComponent'
    534          monitorq, typeq = None, None
    535          if monitored:
    536              monitorq = Eq('monitored', '1')
    537          if meta_type:
    538              typeq = Eq('meta_type', meta_type)
    539          queries = filter(None, (monitorq, typeq))
    540          if queries:
    541              query = And(*queries) if len(queries) > 1 else queries[0]
    542          else:
    543              query = None
    544          for brain in catalog.search(COMPONENT, query=query):
    545              try:
    546                  yield brain.getObject()
    547              except KeyError:
    548                  log.warn("bad path '%s' in global catalog", brain.getPath())
    549
    550
    551      security.declareProtected("ZenCommon", "getMonitoredComponents")
    552 -    def getMonitoredComponents(self):
    553          """
    554          Return monitored components for devices within this DeviceDeviceClass
    555          """
    556          return self.getSubComponents()
    557
    558
    559      security.declareProtected('View', 'getRRDTemplates')
    560 -    def getRRDTemplates(self, context=None):
    561          """
    562          Return the actual RRDTemplate instances.
    563          """
    564          templates = {}
    565          if not context: context = self
    566          mychain = aq_chain(context)
    567          mychain.reverse()
    568          for obj in mychain:
    569              try:
    570                  templates.update(dict((t.id, t) for t in obj.rrdTemplates()))
    571              except AttributeError:
    572                  pass
    573          return templates.values()
    574
    575
    576 -    def getAvailableTemplates(self):
    577          """
    578          Returns all available templates
    579          """
    580          pdc = self.getPythonDeviceClass()
    581          templates = filter(lambda t: issubclass(pdc, t.getTargetPythonClass()),
    582                              self.getRRDTemplates())
    583          return sorted(templates, key=lambda a: a.id.lower())
    584
    585
    586 -    def bindTemplates(self, ids=(), REQUEST=None):
    587          """
    588          This will bind available templates to the zDeviceTemplates
    589          """
    590          return self.setZenProperty('zDeviceTemplates', ids, REQUEST)
    591
    592 -    def removeZDeviceTemplates(self, REQUEST=None):
    593          """
    594          Deletes the local zProperty, zDeviceTemplates
    595          """
    596          if self.getPrimaryPath()[-2:] == ('dmd', 'Devices'):
    597              self.setZenProperty('zDeviceTemplates', ['Device'])
    598          else:
    599              self.deleteZenProperty('zDeviceTemplates')
    600          messaging.IMessageSender(self).sendToBrowser(
    601              'Bindings Reset',
    602              'Template bindings for this class were reset.'
    603          )
    604          return self.callZenScreen(REQUEST)
    605
    606
    607 -    def getAllRRDTemplates(self, rrdts=None):
    608          """
    609          Return all RRDTemplates at this level and below in the object tree.
    610          If rrdts is provided then it must be a list of RRDTemplates which
    611          will be extended with the templates from here and returned.
    612
    613          The original getAllRRDTemplates() method has been renamed
    614          getAllRRDTemplatesPainfully().  It walks the object tree looking
    615          for templates which is a very slow way of going about things.
    616          The newer RRDTemplate.YieldAllRRDTemplate() method uses the
    617          searchRRDTemplates catalog to speed things up dramatically.
    618          YieldAllRRDTemplates is smart enough to revert to
    619          getAllRRDTemplatesPainfully if the catalog is not present.
    620
    621          The searchRRDTemplates catalog was added in 2.2
    622          """
    623          if rrdts is None:
    624              rrdts = []
    625          rrdts.extend(RRDTemplate.YieldAllRRDTemplates(self))
    626          return rrdts
    627
    628
    629 -    def getAllRRDTemplatesPainfully(self, rrdts=None):
    630          """
    631          RRDTemplate.YieldAllRRDTemplates() is probably what you want.
    632          It takes advantage of the searchRRDTemplates catalog to get
    633          much better performance.  This method iterates over objects looking
    634          for templates which is a slow, painful process.
    635          """
    636          if rrdts is None: rrdts = []
    637          rrdts.extend(self.rrdTemplates())
    638          for dev in self.devices():
    639              rrdts += dev.objectValues('RRDTemplate')
    640              for comps in dev.getDeviceComponents():
    641                  rrdts += comps.objectValues('RRDTemplate')
    642          for child in self.children():
    643              child.getAllRRDTemplatesPainfully(rrdts)
    644          return rrdts
    645
    646
    647      security.declareProtected('Add DMD Objects', 'manage_addRRDTemplate')
    648 -    def manage_addRRDTemplate(self, id, REQUEST=None):
    649          """
    650          Add an RRDTemplate to this DeviceClass.
    651          """
    652          if not id: return self.callZenScreen(REQUEST)
    653          id = self.prepId(id)
    654          org = RRDTemplate.RRDTemplate(id)
    655          self.rrdTemplates._setObject(org.id, org)
    656          if REQUEST:
    657              messaging.IMessageSender(self).sendToBrowser(
    658                  'Template Added',
    659                  'The "%s" template has been created.' % id
    660              )
    661              return self.callZenScreen(REQUEST)
    662
    663
    664      security.declareProtected(ZEN_EDIT_LOCAL_TEMPLATES,
    665                                'manage_copyRRDTemplates')
    666 -    def manage_copyRRDTemplates(self, ids=(), REQUEST=None):
    667          """
    668          Put a reference to the objects named in ids in the clip board
    669          """
    670          if not ids: return self.callZenScreen(REQUEST)
    671          ids = [ id for id in ids if self.rrdTemplates._getOb(id, None) is not None]
    672          if not ids: return self.callZenScreen(REQUEST)
    673          cp = self.rrdTemplates.manage_copyObjects(ids)
    674          if REQUEST:
    675              resp=REQUEST['RESPONSE']
    676              resp.setCookie('__cp', cp, path='/zport/dmd')
    677              REQUEST['__cp'] = cp
    678              messaging.IMessageSender(self).sendToBrowser(
    679                  'Templates Copied',
    680                  'Templates have been copied: %s' % ', '.join(ids)
    681              )
    682              return self.callZenScreen(REQUEST)
    683          return cp
    684
    685
    686      security.declareProtected(ZEN_EDIT_LOCAL_TEMPLATES,
    687                                'manage_pasteRRDTemplates')
    688 -    def manage_pasteRRDTemplates(self, moveTarget=None, cb_copy_data=None, REQUEST=None):
    689          """
    690          Paste RRDTemplates that have been copied before.
    691          """
    692          cp = None
    693          if cb_copy_data: cp = cb_copy_data
    694          elif REQUEST:
    695              cp = REQUEST.get("__cp",None)
    696
    697          if cp:
    698              if moveTarget:
    699                  target = self.getDmdRoot(self.dmdRootName).getOrganizer(moveTarget)
    700              else:
    701                  target = self
    702              target.rrdTemplates.manage_pasteObjects(cp)
    703          else:
    704              target = None
    705
    706          if REQUEST:
    707              REQUEST['RESPONSE'].setCookie('__cp', 'deleted', path='/zport/dmd',
    708                              expires='Wed, 31-Dec-97 23:59:59 GMT')
    709              REQUEST['__cp'] = None
    710              if target:
    711                  message = "Template(s) copied to %s" % moveTarget
    712              else:
    713                  message = None
    714              messaging.IMessageSender(self).sendToBrowser(
    715                  'Template(s) Copied',
    716                  message
    717              )
    718              if not isinstance(REQUEST, FakeRequest):
    719                  url = target.getPrimaryUrlPath() + '/perfConfig'
    720                  if message:
    721                      url += '?message=%s' % message
    722                  REQUEST['RESPONSE'].redirect(url)
    723              else:
    724                  return self.callZenScreen(REQUEST)
    725
    726
    727      security.declareProtected(ZEN_EDIT_LOCAL_TEMPLATES,
    728                                'manage_copyAndPasteRRDTemplates')
    729 -    def manage_copyAndPasteRRDTemplates(self, ids=(), copyTarget=None, REQUEST=None):
    730          """
    731          Copy the selected templates into the specified device class.
    732          """
    733          if not ids:
    734              messaging.IMessageSender(self).sendToBrowser(
    735                  'Invalid',
    736                  'No templates were selected.',
    737                  priority=messaging.WARNING
    738              )
    739              return self.callZenScreen(REQUEST)
    740          if copyTarget is None:
    741              messaging.IMessageSender(self).sendToBrowser(
    742                  'Invalid',
    743                  'No target was selected.',
    744                  priority=messaging.WARNING
    745              )
    746              return self.callZenScreen(REQUEST)
    747          cp = self.manage_copyRRDTemplates(ids)
    748          return self.manage_pasteRRDTemplates(copyTarget, cp, REQUEST)
    749
    750
    751      security.declareProtected(ZEN_EDIT_LOCAL_TEMPLATES,
    752                                'manage_deleteRRDTemplates')
    753 -    def manage_deleteRRDTemplates(self, ids=(), paths=(), REQUEST=None):
    754          """
    755          Delete RRDTemplates from this DeviceClass
    756          (skips ones in other Classes)
    757          """
    758          if not ids and not paths:
    759              return self.callZenScreen(REQUEST)
    760          for id in ids:
    761              if (getattr(aq_base(self), 'rrdTemplates', False)
    762                  and getattr(aq_base(self.rrdTemplates),id,False)):
    763                  self.rrdTemplates._delObject(id)
    764          for path in paths:
    765              temp = self.dmd.getObjByPath(path)
    766              if temp.deviceClass():
    767                  temp.deviceClass().rrdTemplates._delObject(temp.id)
    768              else:
    769                  temp.device()._delObject(temp.id)
    770          if REQUEST:
    771              messaging.IMessageSender(self).sendToBrowser(
    772                  'Templates Deleted',
    773                  'Templates were deleted: %s' % ", ".join(ids)
    774              )
    775              return self.callZenScreen(REQUEST)
    776
    777
    778 -    def createCatalog(self):
    779          """
    780          Make the catalog for device searching
    781          """
    782          from Products.ZCatalog.ZCatalog import manage_addZCatalog
    783
    784          # Make catalog for Devices
    785          manage_addZCatalog(self, self.default_catalog,
    786              self.default_catalog)
    787          zcat = self._getOb(self.default_catalog)
    788          cat = zcat._catalog
    789          for idxname in ['id',
    790              'getDeviceIp','getDeviceClassPath','getProdState','titleOrId']:
    791              cat.addIndex(idxname, makeCaseInsensitiveFieldIndex(idxname))
    792          cat.addIndex('getPhysicalPath', makePathIndex('getPhysicalPath'))
    793          cat.addIndex('path', makeMultiPathIndex('path'))
    794          zcat.addColumn('getPrimaryId')
    795          zcat.addColumn('id')
    796          zcat.addColumn('path')
    797
    798 -    def reIndex(self):
    799          """
    800          Go through all devices in this tree and reindex them.
    801          """
    802          zcat = getToolByName(self, self.default_catalog)
    803          zcat.manage_catalogClear()
    804          for dev in self.getSubDevicesGen_recursive():
    805              if dev.hasObject('componentSearch'):
    806                  dev._delObject('componentSearch')
    807              dev._create_componentSearch()
    808              dev.index_object()
    809              notify(IndexingEvent(dev))
    810              for comp in dev.getDeviceComponentsNoIndexGen():
    811                  notify(IndexingEvent(comp))
    812
    813
    814 -    def buildDeviceTreeProperties(self):
    815          """
    816          Create a new device tree with a default configuration
    817          """
    818          devs = self.getDmdRoot("Devices")
    819          for id, value, type in Z_PROPERTIES:
    820              if not devs.hasProperty(id):
    821                  devs._setProperty(id, value, type)
    822
    823 -    def zenPropertyOptions(self, propname):
    824          """
    825          Provide a set of default options for a zProperty
    826
    827          @param propname: zProperty name
    828          @type propname: string
    829          @return: list of zProperty options
    830          @rtype: list
    831          """
    832          if propname == 'zCollectorPlugins':
    833              from Products.DataCollector.Plugins import loadPlugins
    834              return sorted(ldr.pluginName for ldr in loadPlugins(self.dmd))
    835          if propname == 'zCommandProtocol':
    836              return ['ssh', 'telnet']
    837          if propname == 'zSnmpVer':
    838              return ['v1', 'v2c', 'v3']
    839          if propname == 'zSnmpAuthType':
    840              return ['', 'MD5', 'SHA']
    841          if propname == 'zSnmpPrivType':
    842              return ['', 'DES', 'AES']
    843          return DeviceOrganizer.zenPropertyOptions(self, propname)
    844
    845
    846 -    def pushConfig(self, REQUEST=None):
    847          """
    848          This will result in a push of all the devices to live collectors
    849
    850          @param REQUEST: Zope REQUEST object
    851          @type REQUEST: Zope REQUEST object
    852          """
    853          self._p_changed = True
    854          if REQUEST:
    855              messaging.IMessageSender(self).sendToBrowser(
    856                  'Pushed Changes',
    857                  'Changes to %s were pushed to collectors.' % self.id
    858              )
    859              return self.callZenScreen(REQUEST)
    860
    861
    862      security.declareProtected('Change Device', 'setLastChange')
    863 -    def setLastChange(self, value=None):
    864          """
    865          Set the changed datetime for this device.
    866
    867          @param value: changed datetime. Default is now.
    868          @type value: number
    869          """
    870          if value is None:
    871              value = time.time()
    872          self._lastChange = float(value)
    873
    874 -    def register_devtype(self, description, protocol):
    875          """
    876          Define this class in terms of a description of the devices it should
    877          contain and the protocol by which they would normally be monitored.
    878          """
    879          t = (description, protocol)
    880          if not self.isLocal('devtypes'):
    881              self._setProperty('devtypes', [], 'lines')
    882          if t not in self.devtypes:
    883              self.devtypes.append(t)
    884              self._p_changed = True
    885
    886 -    def unregister_devtype(self, description, protocol):
    887          t = (description, protocol)
    888          if hasattr(self, 'devtypes'):
    889              if t in self.devtypes:
    890                  self.devtypes.remove(t)
    891                  self._p_changed = True
    892
    893
    894  InitializeClass(DeviceClass)
    895