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