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

# Source Code for Module Products.ZenModel.ZDeviceLoader

      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__="""ZDeviceLoader.py
     15
     16  load devices from a GUI screen in the ZMI
     17
     18  $Id: ZDeviceLoader.py,v 1.19 2004/04/22 02:14:12 edahl Exp $"""
     19
     20  __version__ = "$Revision: 1.19 $"[11:-2]
     21
     22  import socket
     23  from logging import StreamHandler, Formatter, getLogger
     24  log = getLogger("zen.DeviceLoader")
     25
     26  import transaction
     27  from zope.interface import implements
     28  from AccessControl import ClassSecurityInfo
     29  from AccessControl import Permissions as permissions
     30
     31  from OFS.SimpleItem import SimpleItem
     32
     33  from Products.ZenUtils.Utils import isXmlRpc, setupLoggingHeader
     34  from Products.ZenUtils.Utils import binPath, clearWebLoggingStream
     35  from Products.ZenUtils.Exceptions import ZentinelException
     36  from Products.ZenModel.Exceptions import DeviceExistsError, NoSnmp
     37  from Products.ZenModel.Device import manage_createDevice
     38  from Products.ZenWidgets import messaging
     39  from Products.Jobber.interfaces import IJobStatus
     40  from Products.Jobber.jobs import ShellCommandJob
     41  from Products.Jobber.status import SUCCESS, FAILURE
     42  from ZenModelItem import ZenModelItem
     43  from zExceptions import BadRequest
     44  from Products.ZenModel.interfaces import IDeviceLoader
     45
     46
     47 -def manage_addZDeviceLoader(context, id="", REQUEST = None):
     48      """make a DeviceLoader"""
     49      if not id: id = "DeviceLoader"
     50      d = ZDeviceLoader(id)
     51      context._setObject(id, d)
     52
     53      if REQUEST is not None:
     54          REQUEST['RESPONSE'].redirect(context.absolute_url()
     55                                       +'/manage_main')
     56
     57 -class BaseDeviceLoader(object):
     58      implements(IDeviceLoader)
     59
     60      context = None
     61      request = None
     62      deviceobj = None
     63
     64 -    def __init__(self, context):
     65          self.context = context
     66
     67 -    def run_zendisc(self, deviceName, devicePath, performanceMonitor):
     68          """
     69          Various ways of doing this should be implemented in subclasses.
     70          """
     71          raise NotImplementedError
     72
     73 -    def cleanup(self):
     74          """
     75          Delete the device object, presumably because discovery failed.
     76          """
     77          if self.deviceobj is not None:
     78              try:
     79                  self.deviceobj._p_jar.sync()
     80              except AttributeError:
     81                  pass
     82              else:
     83                  if self.deviceobj.isTempDevice():
     84                      # Flag's still True, so discovery failed somehow.  Clean up
     85                      # the device object.
     86                      self.deviceobj.deleteDevice(True, True, True)
     87                      self.deviceobj = None
     88
     89 -    def load_device(self, deviceName, devicePath='/Discovered',
     90                      discoverProto='snmp', performanceMonitor='localhost',
     91                      manageIp="", zProperties=None, deviceProperties=None):
     92          """
     93          Load a single device into the database.
     94          """
     95          # Make the config dictionaries the proper type
     96          try:
     97              if zProperties is None:
     98                  zProperties = {}
     99              if deviceProperties is None:
    100                  deviceProperties = {}
    101
    102              # Remove spaces from the name
    103              deviceName = deviceName.replace(' ', '')
    104              manageIp = manageIp.replace(' ', '')
    105
    106              # If we're not discovering and we have no IP, attempt the IP lookup
    107              # locally
    108              if discoverProto=='none':
    109                  if not manageIp:
    110                      try:
    111                          manageIp = socket.gethostbyname(deviceName)
    112                      except socket.error:
    113                          pass
    114
    115              # move the zProperties required by manage_createDevice to
    116              # deviceProperties
    117              for key in 'zSnmpCommunity', 'zSnmpPort', 'zSnmpVer':
    118                  if zProperties.has_key(key):
    119                      deviceProperties[key] = zProperties.pop(key)
    120
    121              # Make a device object in the database
    122              self.deviceobj = manage_createDevice(self.context, deviceName,
    123                                   devicePath,
    124                                   performanceMonitor=performanceMonitor,
    125                                   manageIp=manageIp,
    126                                   zProperties=zProperties,
    127                                   **deviceProperties)
    128
    129              # Flag this device as temporary. If discovery goes well, zendisc will
    130              # flip this to False.
    131              self.deviceobj._temp_device = True
    132
    133              # If we're not discovering, we're done
    134              if discoverProto=='none':
    135                  return self.deviceobj
    136
    137              # Otherwise, time for zendisc to do its thing
    138              self.run_zendisc(deviceName, devicePath, performanceMonitor)
    139
    140          finally:
    141              # Check discovery's success and clean up accordingly
    142              self.cleanup()
    143
    144          return self.deviceobj
    145
    146
    147 -class JobDeviceLoader(BaseDeviceLoader):
    148      implements(IDeviceLoader)
    149
    150 -    def run_zendisc(self, deviceName, devicePath, performanceMonitor):
    151          """
    152          In this subclass, just commit to database,
    153          so everybody can find the new device
    154          """
    155          transaction.commit()
    156
    157 -    def cleanup(self):
    158          """
    159          Delegate cleanup to the Job itself.
    160          """
    161          pass
    162
    163
    164 -class DeviceCreationJob(ShellCommandJob):
    165 -    def __init__(self, jobid, deviceName, devicePath="/Discovered", tag="",
    166                   serialNumber="", rackSlot=0, productionState=1000,
    167                   comments="", hwManufacturer="", hwProductName="",
    168                   osManufacturer="", osProductName="", locationPath="",
    169                   groupPaths=[], systemPaths=[], performanceMonitor="localhost",
    170                   discoverProto="snmp", priority=3, manageIp="",
    171                   zProperties=None, title=None, zendiscCmd=[]):
    172
    173          # Store device name for later finding
    174          self.deviceName = deviceName
    175          self.devicePath = devicePath
    176          self.performanceMonitor = performanceMonitor
    177          self.discoverProto = discoverProto
    178          self.manageIp = manageIp.replace(' ', '')
    179
    180          # Save the device stuff to set after adding
    181          self.zProperties = zProperties
    182          self.deviceProps = dict(tag=tag,
    183                            serialNumber=serialNumber,
    184                            rackSlot=rackSlot,
    185                            productionState=productionState,
    186                            comments=comments,
    187                            hwManufacturer=hwManufacturer,
    188                            hwProductName = hwProductName,
    189                            osManufacturer = osManufacturer,
    190                            osProductName = osProductName,
    191                            locationPath = locationPath,
    192                            groupPaths = groupPaths,
    193                            systemPaths = systemPaths,
    194                            priority = priority,
    195                            title= title)
    196
    197          zendiscCmd.extend(['--job', jobid])
    198          super(DeviceCreationJob, self).__init__(jobid, zendiscCmd)
    199
    200
    201 -    def run(self, r):
    202          # Store zProperties on the job
    203          self.getStatus().setZProperties(**self.zProperties)
    204
    205          self._v_loader = JobDeviceLoader(self)
    206          # Create the device object and generate the zendisc command
    207          try:
    208              self._v_loader.load_device(self.deviceName, self.devicePath,
    209                                      self.discoverProto,
    210                                      self.performanceMonitor, self.manageIp,
    211                                      self.zProperties, self.deviceProps)
    212              if self.discoverProto == 'none':
    213                  #need to commit otherwise the status object will lose
    214                  #started time attribute and everything will break
    215                  transaction.commit()
    216          except Exception, e:
    217              transaction.commit()
    218              log = self.getStatus().getLog()
    219              log.write(e.args[0])
    220              log.finish()
    221              self.finished(FAILURE)
    222          else:
    223              if self.discoverProto != 'none':
    224                  super(DeviceCreationJob, self).run(r)
    225              else:
    226                  log = self.getStatus().getLog()
    227                  log.write("device added without modeling")
    228                  log.finish()
    229                  self.finished(SUCCESS)
    230 -    def finished(self, r):
    231          if self._v_loader.deviceobj is not None and r!=FAILURE:
    232              result = SUCCESS
    233          else:
    234              result = FAILURE
    235          super(DeviceCreationJob, self).finished(result)
    236
    237 -class WeblogDeviceLoader(BaseDeviceLoader):
    238 -    def __init__(self, context, request):
    239          self.context = context
    240          self.request = request
    241
    242 -    def run_zendisc(self, deviceName, devicePath, performanceMonitor):
    243          # Commit to database so everybody can find the new device
    244          transaction.commit()
    245          collector = self.deviceobj.getPerformanceServer()
    246          collector._executeZenDiscCommand(deviceName, devicePath,
    247                                           performanceMonitor,
    248                                           REQUEST=self.request)
    249
    250
    251 -class ZDeviceLoader(ZenModelItem,SimpleItem):
    252      """Load devices into the DMD database"""
    253
    254      portal_type = meta_type = 'DeviceLoader'
    255
    256      manage_options = ((
    257              {'label':'ManualDeviceLoader', 'action':'manualDeviceLoader'},
    258              ) + SimpleItem.manage_options)
    259
    260
    261      security = ClassSecurityInfo()
    262
    263      factory_type_information = (
    264          {
    265              'immediate_view' : 'addDevice',
    266              'actions'        :
    267              (
    268                  { 'id'            : 'status'
    269                  , 'name'          : 'Status'
    270                  , 'action'        : 'addDevice'
    271                  , 'permissions'   : (
    272                    permissions.view, )
    273                  },
    274              )
    275          },
    276          )
    277
    278 -    def __init__(self, id):
    279          self.id = id
    280
    281
    282 -    def loadDevice(self, deviceName, devicePath="/Discovered",
    283              tag="", serialNumber="",
    284              zSnmpCommunity="", zSnmpPort=161, zSnmpVer=None,
    285              rackSlot=0, productionState=1000, comments="",
    286              hwManufacturer="", hwProductName="",
    287              osManufacturer="", osProductName="",
    288              locationPath="", groupPaths=[], systemPaths=[],
    289              performanceMonitor="localhost",
    290              discoverProto="snmp",priority=3,REQUEST=None):
    291          """
    292          Load a device into the database connecting its major relations
    293          and collecting its configuration.
    294          """
    295          device = None
    296          if not deviceName: return self.callZenScreen(REQUEST)
    297          xmlrpc = isXmlRpc(REQUEST)
    298          if REQUEST and not xmlrpc:
    299              handler = setupLoggingHeader(self, REQUEST)
    300
    301          loader = WeblogDeviceLoader(self, REQUEST)
    302
    303          try:
    304              device = loader.load_device(deviceName, devicePath, discoverProto,
    305                                          performanceMonitor,
    306                                          zProperties=dict(
    307                                              zSnmpCommunity=zSnmpCommunity,
    308                                              zSnmpPort=zSnmpPort,
    309                                              zSnmpVer=zSnmpVer
    310                                          ),
    311                                          deviceProperties=dict(
    312                                              tag=tag,
    313                                              serialNumber=serialNumber,
    314                                              rackSlot=rackSlot,
    315                                              productionState=productionState,
    316                                              comments=comments,
    317                                              hwManufacturer=hwManufacturer,
    318                                              hwProductName=hwProductName,
    319                                              osManufacturer=osManufacturer,
    320                                              osProductName=osProductName,
    321                                              locationPath=locationPath,
    322                                              groupPaths=groupPaths,
    323                                              systemPaths=systemPaths,
    324                                              priority=priority
    325                                          ))
    326          except (SystemExit, KeyboardInterrupt):
    327              raise
    328          except ZentinelException, e:
    329              log.info(e)
    330              if xmlrpc: return 1
    331          except DeviceExistsError, e:
    332              log.info(e)
    333              if xmlrpc: return 2
    334          except NoSnmp, e:
    335              log.info(e)
    336              if xmlrpc: return 3
    337          except Exception, e:
    338              log.exception(e)
    339              log.exception('load of device %s failed' % deviceName)
    340              transaction.abort()
    341          if device is None:
    342              log.error("Unable to add the device %s" % deviceName)
    343          else:
    344              log.info("Device %s loaded!" % deviceName)
    345
    346          if REQUEST and not xmlrpc:
    347              self.loaderFooter(device, REQUEST.RESPONSE)
    348              clearWebLoggingStream(handler)
    349          if xmlrpc: return 0
    350
    351 -    def addManufacturer(self, newHWManufacturerName=None,
    352                          newSWManufacturerName=None, REQUEST=None):
    353          """add a manufacturer to the database"""
    354          mname = newHWManufacturerName
    355          field = 'hwManufacturer'
    356          if not mname:
    357              mname = newSWManufacturerName
    358              field = 'osManufacturer'
    359          try:
    360              self.getDmdRoot("Manufacturers").createManufacturer(mname)
    361          except BadRequest, e:
    362              if REQUEST:
    363                  messaging.IMessageSender(self).sendToBrowser(
    364                      'Error',
    365                      str(e),
    366                      priority=messaging.WARNING
    367                  )
    368              else:
    369                  raise e
    370
    371          if REQUEST:
    372              REQUEST[field] = mname
    373              return self.callZenScreen(REQUEST)
    374
    375
    376      security.declareProtected('Change Device', 'setHWProduct')
    377 -    def setHWProduct(self, newHWProductName, hwManufacturer, REQUEST=None):
    378          """set the productName of this device"""
    379          if not hwManufacturer and REQUEST:
    380              messaging.IMessageSender(self).sendToBrowser(
    381                  'Error',
    382                  'Please select a HW Manufacturer',
    383                  priority=messaging.WARNING
    384              )
    385              return self.callZenScreen(REQUEST)
    386
    387          self.getDmdRoot("Manufacturers").createHardwareProduct(
    388                                          newHWProductName, hwManufacturer)
    389          if REQUEST:
    390              REQUEST['hwProductName'] = newHWProductName
    391              return self.callZenScreen(REQUEST)
    392
    393
    394      security.declareProtected('Change Device', 'setOSProduct')
    395 -    def setOSProduct(self, newOSProductName, osManufacturer, REQUEST=None):
    396          """set the productName of this device"""
    397          if not osManufacturer and REQUEST:
    398              messaging.IMessageSender(self).sendToBrowser(
    399                  'Error',
    400                  'Please select an OS Manufacturer.',
    401                  priority=messaging.WARNING
    402              )
    403              return self.callZenScreen(REQUEST)
    404
    405          self.getDmdRoot("Manufacturers").createSoftwareProduct(
    406                                          newOSProductName, osManufacturer, isOS=True)
    407          if REQUEST:
    408              REQUEST['osProductName'] = newOSProductName
    409              return self.callZenScreen(REQUEST)
    410
    411
    412      security.declareProtected('Change Device', 'addLocation')
    413 -    def addLocation(self, newLocationPath, REQUEST=None):
    414          """add a location to the database"""
    415          try:
    416              self.getDmdRoot("Locations").createOrganizer(newLocationPath)
    417          except BadRequest, e:
    418              if REQUEST:
    419                  messaging.IMessageSender(self).sendToBrowser(
    420                      'Error',
    421                      str(e),
    422                      priority=messaging.WARNING
    423                  )
    424              else:
    425                  raise e
    426
    427          if REQUEST:
    428              REQUEST['locationPath'] = newLocationPath
    429              return self.callZenScreen(REQUEST)
    430
    431
    432      security.declareProtected('Change Device', 'addSystem')
    433 -    def addSystem(self, newSystemPath, REQUEST=None):
    434          """add a system to the database"""
    435          try:
    436              self.getDmdRoot("Systems").createOrganizer(newSystemPath)
    437          except BadRequest, e:
    438              if REQUEST:
    439                  messaging.IMessageSender(self).sendToBrowser(
    440                      'Error',
    441                      str(e),
    442                      priority=messaging.WARNING
    443                  )
    444              else:
    445                  raise e
    446
    447          syss = REQUEST.get('systemPaths', [])
    448          syss.append(newSystemPath)
    449          if REQUEST:
    450              REQUEST['systemPaths'] = syss
    451              return self.callZenScreen(REQUEST)
    452
    453
    454      security.declareProtected('Change Device', 'addDeviceGroup')
    455 -    def addDeviceGroup(self, newDeviceGroupPath, REQUEST=None):
    456          """add a device group to the database"""
    457          try:
    458              self.getDmdRoot("Groups").createOrganizer(newDeviceGroupPath)
    459          except BadRequest, e:
    460              if REQUEST:
    461                  messaging.IMessageSender(self).sendToBrowser(
    462                      'Error',
    463                      str(e),
    464                      priority=messaging.WARNING
    465                  )
    466              else:
    467                  raise e
    468
    469          groups = REQUEST.get('groupPaths', [])
    470          groups.append(newDeviceGroupPath)
    471          if REQUEST:
    472              REQUEST['groupPaths'] = groups
    473              return self.callZenScreen(REQUEST)
    474
    475
    476      security.declareProtected('Change Device', 'setPerformanceMonitor')
    477 -    def setPerformanceMonitor(self, newPerformanceMonitor, REQUEST=None):
    478          """add new performance monitor to the database"""
    479          try:
    480              self.getDmdRoot("Monitors").getPerformanceMonitor(newPerformanceMonitor)
    481          except BadRequest, e:
    482              if REQUEST:
    483                  messaging.IMessageSender(self).sendToBrowser(
    484                      'Error',
    485                      str(e),
    486                      priority=messaging.WARNING
    487                  )
    488              else:
    489                  raise e
    490          if REQUEST:
    491              REQUEST['performanceMonitor'] = newPerformanceMonitor
    492              return self.callZenScreen(REQUEST)
    493
    494
    495 -    def setupLog(self, response):
    496          """setup logging package to send to browser"""
    497          root = getLogger()
    498          self._v_handler = StreamHandler(response)
    499          fmt = Formatter("""<tr class="tablevalues">
    500          <td>%(asctime)s</td><td>%(levelname)s</td>
    501          <td>%(name)s</td><td>%(message)s</td></tr>
    502          """, "%Y-%m-%d %H:%M:%S")
    503          self._v_handler.setFormatter(fmt)
    504          root.addHandler(self._v_handler)
    505          root.setLevel(10)
    506
    507
    508 -    def clearLog(self):
    509          alog = getLogger()
    510          if getattr(self, "_v_handler", False):
    511              alog.removeHandler(self._v_handler)
    512
    513
    514 -    def loaderFooter(self, devObj, response):
    515          """add navigation links to the end of the loader output"""
    516          if not devObj: return
    517          devurl = devObj.absolute_url()
    518          response.write("""<tr class="tableheader"><td colspan="4">
    519              Navigate to device <a href=%s>%s</a></td></tr>"""
    520              % (devurl, devObj.getId()))
    521          response.write("</table></body></html>")
    522