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

# Source Code for Module Products.ZenModel.ZDeviceLoader

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