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