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 create the zendisc command and return it. The
    153          job will do the actual running.
    154          """
    155          # Commit to database so everybody can find the new device
    156          transaction.commit()
    157
    158          jobid = self.context.getUid()
    159
    160          zm = binPath('zendisc')
    161          zendiscCmd = [zm]
    162          zendiscOptions = ['run', '--now','-d', deviceName,
    163                            '--monitor', performanceMonitor,
    164                            '--deviceclass', devicePath,
    165                            '--job', jobid]
    166          zendiscCmd.extend(zendiscOptions)
    167          self.zendiscCmd = zendiscCmd
    168
    169 -    def cleanup(self):
    170          """
    171          Delegate cleanup to the Job itself.
    172          """
    173          pass
    174
    175
    176 -class DeviceCreationJob(ShellCommandJob):
    177 -    def __init__(self, jobid, deviceName, devicePath="/Discovered", tag="",
    178                   serialNumber="", rackSlot=0, productionState=1000,
    179                   comments="", hwManufacturer="", hwProductName="",
    180                   osManufacturer="", osProductName="", locationPath="",
    181                   groupPaths=[], systemPaths=[], performanceMonitor="localhost",
    182                   discoverProto="snmp", priority=3, manageIp="",
    183                   zProperties=None):
    184
    185          # Store device name for later finding
    186          self.deviceName = deviceName
    187          self.devicePath = devicePath
    188          self.performanceMonitor = performanceMonitor
    189          self.discoverProto = discoverProto
    190          self.manageIp = manageIp.replace(' ', '')
    191
    192          # Save the device stuff to set after adding
    193          self.zProperties = zProperties
    194          self.deviceProps = dict(tag=tag,
    195                            serialNumber=serialNumber,
    196                            rackSlot=rackSlot,
    197                            productionState=productionState,
    198                            comments=comments,
    199                            hwManufacturer=hwManufacturer,
    200                            hwProductName = hwProductName,
    201                            osManufacturer = osManufacturer,
    202                            osProductName = osProductName,
    203                            locationPath = locationPath,
    204                            groupPaths = groupPaths,
    205                            systemPaths = systemPaths,
    206                            priority = priority)
    207
    208          # Set up the job, passing in a blank command (gets set later)
    209          super(DeviceCreationJob, self).__init__(jobid, '')
    210
    211
    212 -    def run(self, r):
    213          # Store zProperties on the job
    214          self.getStatus().setZProperties(**self.zProperties)
    215
    216          self._v_loader = JobDeviceLoader(self)
    217          # Create the device object and generate the zendisc command
    218          try:
    219              self._v_loader.load_device(self.deviceName, self.devicePath,
    220                                      self.discoverProto,
    221                                      self.performanceMonitor, self.manageIp,
    222                                      self.zProperties, self.deviceProps)
    223          except Exception, e:
    224              transaction.commit()
    225              log = self.getStatus().getLog()
    226              log.write(e.args[0])
    227              log.finish()
    228              self.finished(FAILURE)
    229          else:
    230              self.cmd = self._v_loader.zendiscCmd
    231              super(DeviceCreationJob, self).run(r)
    232
    233 -    def finished(self, r):
    234          self._v_loader.cleanup()
    235          if self._v_loader.deviceobj is not None and r!=FAILURE:
    236              result = SUCCESS
    237          else:
    238              result = FAILURE
    239          super(DeviceCreationJob, self).finished(result)
    240
    241 -class WeblogDeviceLoader(BaseDeviceLoader):
    242 -    def __init__(self, context, request):
    243          self.context = context
    244          self.request = request
    245
    246 -    def run_zendisc(self, deviceName, devicePath, performanceMonitor):
    247          # Commit to database so everybody can find the new device
    248          transaction.commit()
    249          collector = self.deviceobj.getPerformanceServer()
    250          collector._executeZenDiscCommand(deviceName, devicePath,
    251                                           performanceMonitor,
    252                                           REQUEST=self.request)
    253
    254
    255 -class ZDeviceLoader(ZenModelItem,SimpleItem):
    256      """Load devices into the DMD database"""
    257
    258      portal_type = meta_type = 'DeviceLoader'
    259
    260      manage_options = ((
    261              {'label':'ManualDeviceLoader', 'action':'manualDeviceLoader'},
    262              ) + SimpleItem.manage_options)
    263
    264
    265      security = ClassSecurityInfo()
    266
    267      factory_type_information = (
    268          {
    269              'immediate_view' : 'addDevice',
    270              'actions'        :
    271              (
    272                  { 'id'            : 'status'
    273                  , 'name'          : 'Status'
    274                  , 'action'        : 'addDevice'
    275                  , 'permissions'   : (
    276                    permissions.view, )
    277                  },
    278              )
    279          },
    280          )
    281
    282 -    def __init__(self, id):
    283          self.id = id
    284
    285
    286 -    def loadDevice(self, deviceName, devicePath="/Discovered",
    287              tag="", serialNumber="",
    288              zSnmpCommunity="", zSnmpPort=161, zSnmpVer=None,
    289              rackSlot=0, productionState=1000, comments="",
    290              hwManufacturer="", hwProductName="",
    291              osManufacturer="", osProductName="",
    292              locationPath="", groupPaths=[], systemPaths=[],
    293              performanceMonitor="localhost",
    294              discoverProto="snmp",priority=3,REQUEST=None):
    295          """
    296          Load a device into the database connecting its major relations
    297          and collecting its configuration.
    298          """
    299          device = None
    300          if not deviceName: return self.callZenScreen(REQUEST)
    301          xmlrpc = isXmlRpc(REQUEST)
    302          if REQUEST and not xmlrpc:
    303              handler = setupLoggingHeader(self, REQUEST)
    304
    305          loader = WeblogDeviceLoader(self, REQUEST)
    306
    307          try:
    308              device = loader.load_device(deviceName, devicePath, discoverProto,
    309                                          performanceMonitor,
    310                                          zProperties=dict(
    311                                              zSnmpCommunity=zSnmpCommunity,
    312                                              zSnmpPort=zSnmpPort,
    313                                              zSnmpVer=zSnmpVer
    314                                          ),
    315                                          deviceProperties=dict(
    316                                              tag=tag,
    317                                              serialNumber=serialNumber,
    318                                              rackSlot=rackSlot,
    319                                              productionState=productionState,
    320                                              comments=comments,
    321                                              hwManufacturer=hwManufacturer,
    322                                              hwProductName=hwProductName,
    323                                              osManufacturer=osManufacturer,
    324                                              osProductName=osProductName,
    325                                              locationPath=locationPath,
    326                                              groupPaths=groupPaths,
    327                                              systemPaths=systemPaths,
    328                                              priority=priority
    329                                          ))
    330          except (SystemExit, KeyboardInterrupt):
    331              raise
    332          except ZentinelException, e:
    333              log.info(e)
    334              if xmlrpc: return 1
    335          except DeviceExistsError, e:
    336              log.info(e)
    337              if xmlrpc: return 2
    338          except NoSnmp, e:
    339              log.info(e)
    340              if xmlrpc: return 3
    341          except Exception, e:
    342              log.exception(e)
    343              log.exception('load of device %s failed' % deviceName)
    344              transaction.abort()
    345          if device is None:
    346              log.error("Unable to add the device %s" % deviceName)
    347          else:
    348              log.info("Device %s loaded!" % deviceName)
    349
    350          if REQUEST and not xmlrpc:
    351              self.loaderFooter(device, REQUEST.RESPONSE)
    352              clearWebLoggingStream(handler)
    353          if xmlrpc: return 0
    354
    355 -    def addManufacturer(self, newHWManufacturerName=None,
    356                          newSWManufacturerName=None, REQUEST=None):
    357          """add a manufacturer to the database"""
    358          mname = newHWManufacturerName
    359          field = 'hwManufacturer'
    360          if not mname:
    361              mname = newSWManufacturerName
    362              field = 'osManufacturer'
    363          try:
    364              self.getDmdRoot("Manufacturers").createManufacturer(mname)
    365          except BadRequest, e:
    366              if REQUEST:
    367                  messaging.IMessageSender(self).sendToBrowser(
    368                      'Error',
    369                      str(e),
    370                      priority=messaging.WARNING
    371                  )
    372              else:
    373                  raise e
    374
    375          if REQUEST:
    376              REQUEST[field] = mname
    377              return self.callZenScreen(REQUEST)
    378
    379
    380      security.declareProtected('Change Device', 'setHWProduct')
    381 -    def setHWProduct(self, newHWProductName, hwManufacturer, REQUEST=None):
    382          """set the productName of this device"""
    383          if not hwManufacturer and REQUEST:
    384              messaging.IMessageSender(self).sendToBrowser(
    385                  'Error',
    386                  'Please select a HW Manufacturer',
    387                  priority=messaging.WARNING
    388              )
    389              return self.callZenScreen(REQUEST)
    390
    391          self.getDmdRoot("Manufacturers").createHardwareProduct(
    392                                          newHWProductName, hwManufacturer)
    393          if REQUEST:
    394              REQUEST['hwProductName'] = newHWProductName
    395              return self.callZenScreen(REQUEST)
    396
    397
    398      security.declareProtected('Change Device', 'setOSProduct')
    399 -    def setOSProduct(self, newOSProductName, osManufacturer, REQUEST=None):
    400          """set the productName of this device"""
    401          if not osManufacturer and REQUEST:
    402              messaging.IMessageSender(self).sendToBrowser(
    403                  'Error',
    404                  'Please select an OS Manufacturer.',
    405                  priority=messaging.WARNING
    406              )
    407              return self.callZenScreen(REQUEST)
    408
    409          self.getDmdRoot("Manufacturers").createSoftwareProduct(
    410                                          newOSProductName, osManufacturer, isOS=True)
    411          if REQUEST:
    412              REQUEST['osProductName'] = newOSProductName
    413              return self.callZenScreen(REQUEST)
    414
    415
    416      security.declareProtected('Change Device', 'addLocation')
    417 -    def addLocation(self, newLocationPath, REQUEST=None):
    418          """add a location to the database"""
    419          try:
    420              self.getDmdRoot("Locations").createOrganizer(newLocationPath)
    421          except BadRequest, e:
    422              if REQUEST:
    423                  messaging.IMessageSender(self).sendToBrowser(
    424                      'Error',
    425                      str(e),
    426                      priority=messaging.WARNING
    427                  )
    428              else:
    429                  raise e
    430
    431          if REQUEST:
    432              REQUEST['locationPath'] = newLocationPath
    433              return self.callZenScreen(REQUEST)
    434
    435
    436      security.declareProtected('Change Device', 'addSystem')
    437 -    def addSystem(self, newSystemPath, REQUEST=None):
    438          """add a system to the database"""
    439          try:
    440              self.getDmdRoot("Systems").createOrganizer(newSystemPath)
    441          except BadRequest, e:
    442              if REQUEST:
    443                  messaging.IMessageSender(self).sendToBrowser(
    444                      'Error',
    445                      str(e),
    446                      priority=messaging.WARNING
    447                  )
    448              else:
    449                  raise e
    450
    451          syss = REQUEST.get('systemPaths', [])
    452          syss.append(newSystemPath)
    453          if REQUEST:
    454              REQUEST['systemPaths'] = syss
    455              return self.callZenScreen(REQUEST)
    456
    457
    458      security.declareProtected('Change Device', 'addDeviceGroup')
    459 -    def addDeviceGroup(self, newDeviceGroupPath, REQUEST=None):
    460          """add a device group to the database"""
    461          try:
    462              self.getDmdRoot("Groups").createOrganizer(newDeviceGroupPath)
    463          except BadRequest, e:
    464              if REQUEST:
    465                  messaging.IMessageSender(self).sendToBrowser(
    466                      'Error',
    467                      str(e),
    468                      priority=messaging.WARNING
    469                  )
    470              else:
    471                  raise e
    472
    473          groups = REQUEST.get('groupPaths', [])
    474          groups.append(newDeviceGroupPath)
    475          if REQUEST:
    476              REQUEST['groupPaths'] = groups
    477              return self.callZenScreen(REQUEST)
    478
    479
    480      security.declareProtected('Change Device', 'setPerformanceMonitor')
    481 -    def setPerformanceMonitor(self, newPerformanceMonitor, REQUEST=None):
    482          """add new performance monitor to the database"""
    483          try:
    484              self.getDmdRoot("Monitors").getPerformanceMonitor(newPerformanceMonitor)
    485          except BadRequest, e:
    486              if REQUEST:
    487                  messaging.IMessageSender(self).sendToBrowser(
    488                      'Error',
    489                      str(e),
    490                      priority=messaging.WARNING
    491                  )
    492              else:
    493                  raise e
    494          if REQUEST:
    495              REQUEST['performanceMonitor'] = newPerformanceMonitor
    496              return self.callZenScreen(REQUEST)
    497
    498
    499 -    def setupLog(self, response):
    500          """setup logging package to send to browser"""
    501          root = getLogger()
    502          self._v_handler = StreamHandler(response)
    503          fmt = Formatter("""<tr class="tablevalues">
    504          <td>%(asctime)s</td><td>%(levelname)s</td>
    505          <td>%(name)s</td><td>%(message)s</td></tr>
    506          """, "%Y-%m-%d %H:%M:%S")
    507          self._v_handler.setFormatter(fmt)
    508          root.addHandler(self._v_handler)
    509          root.setLevel(10)
    510
    511
    512 -    def clearLog(self):
    513          alog = getLogger()
    514          if getattr(self, "_v_handler", False):
    515              alog.removeHandler(self._v_handler)
    516
    517
    518 -    def loaderFooter(self, devObj, response):
    519          """add navigation links to the end of the loader output"""
    520          if not devObj: return
    521          devurl = devObj.absolute_url()
    522          response.write("""<tr class="tableheader"><td colspan="4">
    523              Navigate to device <a href=%s>%s</a></td></tr>"""
    524              % (devurl, devObj.getId()))
    525          response.write("</table></body></html>")
    526