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

Source Code for Module Products.ZenModel.DeviceOrganizer

  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__ = """DeviceOrganizer 
 12  Base class for device organizers 
 13  """ 
 14   
 15  from itertools import ifilter 
 16  from zope.event import notify 
 17  from zope.interface import implements 
 18  from ZODB.transact import transact 
 19  from AccessControl import ClassSecurityInfo 
 20  from Globals import InitializeClass 
 21   
 22  from Organizer import Organizer 
 23  from DeviceManagerBase import DeviceManagerBase 
 24  from Commandable import Commandable 
 25  from ZenMenuable import ZenMenuable 
 26  from MaintenanceWindowable import MaintenanceWindowable 
 27  from AdministrativeRoleable import AdministrativeRoleable 
 28  from Products.Zuul.catalog.events import IndexingEvent 
 29  from Products.CMFCore.utils import getToolByName 
 30   
 31  from Products.ZenRelations.RelSchema import * 
 32  from Products.ZenWidgets.interfaces import IMessageSender 
 33   
 34  from ZenossSecurity import * 
 35  from Products.ZenUtils.Utils import unused, getObjectsFromCatalog 
 36  from Products.ZenUtils.guid.interfaces import IGloballyIdentifiable 
 37  from Products.ZenWidgets import messaging 
 38  from Products.Jobber.zenmodel import DeviceSetLocalRolesJob 
 39   
 40  import logging 
 41  LOG = logging.getLogger('ZenModel.DeviceOrganizer') 
42 43 -class DeviceOrganizer(Organizer, DeviceManagerBase, Commandable, ZenMenuable, 44 MaintenanceWindowable, AdministrativeRoleable):
45 """ 46 DeviceOrganizer is the base class for device organizers. 47 It has lots of methods for rolling up device statistics and information. 48 """ 49 implements(IGloballyIdentifiable) 50 51 security = ClassSecurityInfo() 52 53 # Screen action bindings (and tab definitions) 54 factory_type_information = ( 55 { 56 'immediate_view' : 'deviceOrganizerStatus', 57 'actions' : 58 ( 59 { 'id' : 'status' 60 , 'name' : 'Status' 61 , 'action' : 'deviceOrganizerStatus' 62 , 'permissions' : (ZEN_VIEW, ) 63 }, 64 { 'id' : 'events' 65 , 'name' : 'Events' 66 , 'action' : 'viewEvents' 67 , 'permissions' : (ZEN_VIEW, ) 68 }, 69 # { 'id' : 'historyEvents' 70 # , 'name' : 'History' 71 # , 'action' : 'viewHistoryEvents' 72 # , 'permissions' : (ZEN_VIEW, ) 73 # }, 74 { 'id' : 'manage' 75 , 'name' : 'Administration' 76 , 'action' : 'deviceOrganizerManage' 77 , 'permissions' : (ZEN_MANAGE_DMD,) 78 }, 79 ) 80 }, 81 ) 82 83 _relations = Organizer._relations + ( 84 ("maintenanceWindows", ToManyCont( 85 ToOne, "Products.ZenModel.MaintenanceWindow", "productionState")), 86 ("adminRoles", ToManyCont( 87 ToOne,"Products.ZenModel.AdministrativeRole","managedObject")), 88 ('userCommands', ToManyCont( 89 ToOne, 'Products.ZenModel.UserCommand', 'commandable')), 90 ('zenMenus', ToManyCont( 91 ToOne, 'Products.ZenModel.ZenMenu', 'menuable')), 92 ) 93 94 security.declareProtected(ZEN_COMMON, "getSubDevices")
95 - def getSubDevices(self, devfilter=None):
96 """ 97 Get all the devices under an instance of a DeviceOrganizer 98 99 @param devfilter: Filter function applied to returned list 100 @type devfilter: function 101 @return: Devices 102 @rtype: list 103 104 """ 105 catalog = getToolByName(self.dmd.Devices, self.dmd.Devices.default_catalog) 106 107 if not 'path' in catalog.indexes(): 108 LOG.warn('Please run zenmigrate to create device path indexes.') 109 return self.getSubDevices_recursive(devfilter) 110 111 devices = getObjectsFromCatalog(catalog, { 112 'path': "/".join(self.getPhysicalPath())}, LOG) 113 devices = ifilter(lambda dev:self.checkRemotePerm(ZEN_VIEW, dev), 114 devices) 115 devices = ifilter(devfilter, devices) 116 return list(devices)
117 118 security.declareProtected(ZEN_VIEW, "getSubDevicesGen")
119 - def getSubDevicesGen(self):
120 """get all the devices under and instance of a DeviceGroup""" 121 catalog = getToolByName(self.dmd.Devices, self.dmd.Devices.default_catalog) 122 123 if not 'path' in catalog.indexes(): 124 LOG.warn('Please run zenmigrate to create device path indexes.') 125 yield self.getSubDevicesGen_recursive(devfilter) 126 127 devices = getObjectsFromCatalog(catalog, { 128 'path': "/".join(self.getPhysicalPath())}, LOG) 129 devices = ifilter(lambda dev:self.checkRemotePerm(ZEN_VIEW, dev), 130 devices) 131 for device in devices: 132 yield device
133 134 security.declareProtected(ZEN_COMMON, "getSubDevices_recursive")
135 - def getSubDevices_recursive(self, devfilter=None, devrel="devices"):
136 devrelobj = getattr(self, devrel, None) 137 if not devrelobj: 138 raise AttributeError( "%s not found on %s" % (devrel, self.id) ) 139 devices = filter(devfilter, devrelobj()) 140 devices = [ dev for dev in devices 141 if self.checkRemotePerm(ZEN_VIEW, dev)] 142 for subgroup in self.children(checkPerm=False): 143 devices.extend(subgroup.getSubDevices_recursive(devfilter, devrel)) 144 return devices
145 146 security.declareProtected(ZEN_VIEW, "getSubDevicesGen")
147 - def getSubDevicesGen_recursive(self, devrel="devices"):
148 """get all the devices under and instance of a DeviceGroup""" 149 devrelobj = getattr(self, devrel, None) 150 if not devrelobj: 151 raise AttributeError( "%s not found on %s" % (devrel, self.id) ) 152 for dev in devrelobj.objectValuesGen(): 153 yield dev 154 for subgroup in self.children(): 155 for dev in subgroup.getSubDevicesGen_recursive(devrel): 156 yield dev
157
158 - def getSubDevicesGenTest(self, devrel="devices"):
159 """get all the devices under and instance of a DeviceGroup""" 160 devices = getattr(self, devrel, None) 161 if not devices: 162 raise AttributeError( "%s not found on %s" % (devrel, self.id) )
163 164
165 - def getMonitoredComponents(self):
166 """Return monitored components for devices within this DeviceOrganizer. 167 """ 168 cmps = [] 169 for dev in self.getSubDevicesGen(): 170 cmps.extend(dev.getMonitoredComponents()) 171 return cmps
172 173
174 - def getAllCounts(self, devrel="devices"):
175 """Count all devices within a device group and get the 176 ping and snmp counts as well""" 177 devices = getattr(self, devrel) 178 pingStatus = 0 179 snmpStatus = 0 180 devCount = devices.countObjects() 181 for dev in devices(): 182 if dev.getPingStatusNumber() > 0: 183 pingStatus += 1 184 if dev.getSnmpStatusNumber() > 0: 185 snmpStatus += 1 186 counts = [devCount, pingStatus, snmpStatus] 187 for group in self.children(): 188 sc = group.getAllCounts() 189 for i in range(3): counts[i] += sc[i] 190 return counts
191 192
193 - def countDevices(self, devrel="devices"):
194 """count all devices with in a device group""" 195 unused(devrel) 196 count = self.devices.countObjects() 197 for group in self.children(): 198 count += group.countDevices() 199 return count
200 201
202 - def pingStatus(self, devrel="devices"):
203 """aggrigate ping status for all devices in this group and below""" 204 status = self._status("Ping", devrel) 205 for group in self.children(): 206 status += group.pingStatus() 207 return status
208 209
210 - def snmpStatus(self, devrel="devices"):
211 """aggrigate snmp status for all devices in this group and below""" 212 status = self._status("Snmp", devrel) 213 for group in self.children(): 214 status += group.snmpStatus() 215 return status
216 217
218 - def _buildDeviceList(self, deviceNames):
219 """Build a device list for set methods""" 220 if isinstance(deviceNames, basestring): 221 deviceNames = [deviceNames] 222 if deviceNames is not None: 223 deviceNames = set(deviceNames) 224 return [d.primaryAq() for d in self.getSubDevices() 225 if deviceNames is None or d.id in deviceNames 226 or d.getPrimaryId() in deviceNames]
227 228
229 - def deviceClassMoveTargets(self):
230 """Return list of all organizers excluding our self.""" 231 targets = filter(lambda x: x != self.getOrganizerName(), 232 self.dmd.Devices.getOrganizerNames()) 233 return sorted(targets, key=lambda x: x.lower())
234 235
236 - def moveDevicesToClass(self, moveTarget, deviceNames=None, REQUEST=None):
237 """Move Devices from one DeviceClass to Another""" 238 if deviceNames is None: 239 if REQUEST: 240 messaging.IMessageSender(self).sendToBrowser( 241 'Error', 242 'No devices were selected', 243 priority=messaging.WARNING 244 ) 245 return self.callZenScreen(REQUEST) 246 deviceNames = [ x.split('/')[-1] for x in deviceNames ] 247 return self.dmd.Devices.moveDevices(moveTarget, deviceNames, REQUEST)
248 249
250 - def _handleOrganizerCall(self, arg=None, deviceNames=None, \ 251 isOrganizer=False, REQUEST=None, \ 252 deviceMethod=None):
253 """ Handle the many many methods that simply call one 254 method on device differently""" 255 #check to see if we have the essentials to work with 256 if not deviceMethod: return 257 if deviceNames is None and not isOrganizer: 258 if REQUEST: 259 messaging.IMessageSender(self).sendToBrowser( 260 'Error', 261 'No devices were selected', 262 priority=messaging.WARNING 263 ) 264 return self.callZenScreen(REQUEST) 265 for dev in self._buildDeviceList(deviceNames): 266 devMethod = getattr(dev, deviceMethod, None) 267 if devMethod and arg: 268 devMethod(arg) 269 elif devMethod: 270 devMethod()
271 272
273 - def _buildReturnMessage(self, title, message, paths=None, \ 274 checkPaths=False):
275 """build the standard return message for the various set 276 methods""" 277 if checkPaths: 278 if paths: 279 if not isinstance(paths, basestring): 280 paths = ", ".join(paths) 281 message += paths 282 else: 283 message = "%s unset" % message.split(" ")[0] 284 if self.REQUEST.has_key('oneKeyValueSoInstanceIsntEmptyAndEvalToFalse'): 285 return message 286 else: 287 IMessageSender(self).sendToBrowser(title, message) 288 return self.callZenScreen(self.REQUEST)
289 290 291 security.declareProtected(ZEN_CHANGE_DEVICE_PRODSTATE, 'setProdState')
292 - def setProdState(self, state, deviceNames=None, 293 isOrganizer=False, REQUEST=None):
294 """Set production state of all devices in this Organizer. 295 """ 296 self._handleOrganizerCall(state, deviceNames, isOrganizer, \ 297 REQUEST, "setProdState") 298 if REQUEST: 299 statename = self.convertProdState(state) 300 msg = "Production state set to %s for %s." % (statename, 301 " ".join(deviceNames)) 302 return self._buildReturnMessage("Production State Changed", msg)
303 304
305 - def setPriority(self, priority, deviceNames=None, 306 isOrganizer=False, REQUEST=None):
307 """Set prioirty of all devices in this Organizer. 308 """ 309 self._handleOrganizerCall(priority, deviceNames, isOrganizer, \ 310 REQUEST, "setPriority") 311 if REQUEST: 312 priname = self.convertPriority(priority) 313 msg = "Priority set to %s for %s." % (priname, 314 " ".join(deviceNames)) 315 return self._buildReturnMessage('Priority Changed', msg)
316 317
318 - def setPerformanceMonitor(self, performanceMonitor=None, deviceNames=None, 319 isOrganizer=False, REQUEST=None):
320 """ Provide a method to set performance monitor from any organizer """ 321 if not performanceMonitor: 322 if REQUEST: 323 messaging.IMessageSender(self).sendToBrowser( 324 'Error', 325 'No monitor was selected', 326 priority=messaging.WARNING 327 ) 328 return self.callZenScreen(REQUEST) 329 self._handleOrganizerCall(performanceMonitor, deviceNames, isOrganizer, \ 330 REQUEST, "setPerformanceMonitor") 331 if REQUEST: 332 msg = "Collector set to %s" % (performanceMonitor) 333 return self._buildReturnMessage('Collector Set', msg)
334 335
336 - def setGroups(self, groupPaths=None, deviceNames=None, 337 isOrganizer=False, REQUEST=None):
338 """ Provide a method to set device groups from any organizer """ 339 if not groupPaths: groupPaths = [] 340 self._handleOrganizerCall(groupPaths, deviceNames, isOrganizer, \ 341 REQUEST, "setGroups") 342 if REQUEST: 343 msg = "Groups set to" 344 return self._buildReturnMessage('Groups Set', msg, groupPaths, True)
345 346
347 - def setSystems(self, systemPaths=None, deviceNames=None, 348 isOrganizer=False, REQUEST=None):
349 """ Provide a method to set device systems from any organizer """ 350 if not systemPaths: systemPaths = [] 351 self._handleOrganizerCall(systemPaths, deviceNames, isOrganizer, \ 352 REQUEST, "setSystems") 353 if REQUEST: 354 msg = "Systems set to" 355 return self._buildReturnMessage('Systems Set', msg, systemPaths, True)
356
357 - def setLocation(self, locationPath="", deviceNames=None, 358 isOrganizer=False, REQUEST=None):
359 """ Provide a method to set device location from any organizer """ 360 self._handleOrganizerCall(locationPath, deviceNames, isOrganizer, \ 361 REQUEST, "setLocation") 362 if REQUEST: 363 msg = "Location set to %s" % locationPath 364 return self._buildReturnMessage('Location Set', msg)
365
366 - def unlockDevices(self, deviceNames=None, isOrganizer=False, REQUEST=None):
367 """Unlock devices""" 368 self._handleOrganizerCall(None, deviceNames, isOrganizer, \ 369 REQUEST, "unlock") 370 if REQUEST: 371 msg = "Devices unlocked" 372 return self._buildReturnMessage('Devices Unlocked', msg)
373
374 - def lockDevicesFromDeletion(self, deviceNames=None, 375 sendEventWhenBlocked=None, isOrganizer=False, REQUEST=None):
376 """Lock devices from being deleted""" 377 self._handleOrganizerCall(sendEventWhenBlocked, deviceNames, isOrganizer, \ 378 REQUEST, "lockFromDeletion") 379 if REQUEST: 380 msg = "Devices locked from deletion" 381 return self._buildReturnMessage('Devices Locked', msg)
382
383 - def lockDevicesFromUpdates(self, deviceNames=None, 384 sendEventWhenBlocked=None, isOrganizer=False, REQUEST=None):
385 """Lock devices from being deleted or updated""" 386 self._handleOrganizerCall(sendEventWhenBlocked, deviceNames, isOrganizer, \ 387 REQUEST, "lockFromUpdates") 388 if REQUEST: 389 msg = "Devices locked from updates and deletion" 390 return self._buildReturnMessage('Devices Locked', msg)
391 392
393 - def index_object(self, idxs=None):
394 """No action. 395 Index of subdevices will happen in manage_addAdministrativeRole 396 """ 397 pass
398
399 - def unindex_object(self):
400 """No action. 401 Unindex of subdevices will happen in manage_deleteAdministrativeRole 402 """ 403 pass
404
405 - def _setDeviceLocalRoles(self):
406 def deviceChunk(devices, chunksize=10): 407 i = 0 408 maxi = len(devices) 409 while i < maxi: 410 nexti = i+chunksize 411 yield devices[i:nexti] 412 i = nexti
413 414 @transact 415 def setLocalRoles(devices): 416 for device in devices: 417 device = device.primaryAq() 418 device.setAdminLocalRoles()
419 420 devices = self.getSubDevices() 421 total = len(devices) 422 count = 0 423 for chunk in deviceChunk(devices): 424 count += len(chunk) 425 LOG.info("Setting admin roles on %d of total %d", count, total) 426 setLocalRoles(chunk) 427
428 - def _maybeCreateLocalRolesJob(self):
429 """ 430 Look at our total number of devices if it is above the threshold 431 then submit a job for updating the admin roles. 432 """ 433 path = "/".join(self.getPhysicalPath()) 434 threshold = getattr(self.dmd.UserInterfaceSettings, "deviceMoveJobThreshold", 5) 435 436 # find out how many devices we have by just looking at the brains 437 catalog = getToolByName(self.dmd.Devices, self.dmd.Devices.default_catalog) 438 brains = catalog({ 'path' : path}) 439 440 if len(brains) > threshold: 441 job = self.dmd.JobManager.addJob( 442 DeviceSetLocalRolesJob, description="Update Local Roles on %s" % path, 443 kwargs=dict(organizerUid=path)) 444 href = "/zport/dmd/joblist#jobs:%s" % (job.getId()) 445 messaging.IMessageSender(self).sendToBrowser( 446 'Job Added', 447 'Job Added for setting the roles on the organizer %s, view the <a href="%s"> job log</a>' % (path, href) 448 ) 449 return job 450 return self._setDeviceLocalRoles()
451
452 - def manage_addAdministrativeRole(self, newId, REQUEST=None):
453 """ 454 Overrides AdministrativeRoleable.manage_addAdministrativeRole 455 Adds an administrator to this DeviceOrganizer 456 457 @param userid: User to make an administrator of this Organizer 458 @type userid: string 459 """ 460 461 AdministrativeRoleable.manage_addAdministrativeRole(self, newId) 462 notify(IndexingEvent(self, ('allowedRolesAndUsers',), False)) 463 self._maybeCreateLocalRolesJob() 464 if REQUEST: 465 messaging.IMessageSender(self).sendToBrowser( 466 'Role Added', 467 'Administrative role %s was added.' % newId 468 ) 469 return self.callZenScreen(REQUEST)
470 471
472 - def manage_editAdministrativeRoles(self, ids=(), role=(), REQUEST=None):
473 """ 474 Overrides AdministrativeRoleable.manage_editAdministrativeRoles 475 Edit the administrators to this DeviceOrganizer 476 """ 477 AdministrativeRoleable.manage_editAdministrativeRoles( 478 self,ids,role) 479 notify(IndexingEvent(self, ('allowedRolesAndUsers',), False)) 480 self._maybeCreateLocalRolesJob() 481 if REQUEST: 482 messaging.IMessageSender(self).sendToBrowser( 483 'Role Added', 484 'Administrative roles were updated: %s' % ', '.join(ids) 485 ) 486 return self.callZenScreen(REQUEST)
487 488
489 - def manage_deleteAdministrativeRole(self, delids=(), REQUEST=None):
490 """ 491 Overrides AdministrativeRoleable.manage_deleteAdministrativeRole 492 Deletes administrators to this DeviceOrganizer 493 494 @param delids: Users to delete from this Organizer 495 @type delids: tuple of strings 496 """ 497 AdministrativeRoleable.manage_deleteAdministrativeRole(self, delids) 498 notify(IndexingEvent(self, ('allowedRolesAndUsers',), False)) 499 self._maybeCreateLocalRolesJob() 500 if REQUEST: 501 if delids: 502 messaging.IMessageSender(self).sendToBrowser( 503 'Roles Deleted', 504 'Administrative roles were deleted: %s' % ', '.join(delids) 505 ) 506 return self.callZenScreen(REQUEST)
507 508
509 - def manage_snmpCommunity(self, REQUEST=None):
510 """reset Community on all devices in this Organizer. 511 """ 512 [ d.manage_snmpCommunity() for d in self.getSubDevices() ] 513 if REQUEST: 514 return self.callZenScreen(REQUEST)
515
516 - def setManageIp(self, REQUEST=None):
517 """reset ip on all devices in this Organizer. 518 """ 519 [ d.setManageIp() for d in self.getSubDevices() ] 520 if REQUEST: 521 return self.callZenScreen(REQUEST)
522
523 - def collectDevice(self, REQUEST=None):
524 """model all devices in this Organizer. 525 """ 526 [ d.collectDevice() for d in self.getSubDevices() ] 527 if REQUEST: 528 return self.callZenScreen(REQUEST)
529
530 - def _status(self, type, devrel="devices"):
531 """build status info for device in this device group""" 532 status = 0 533 statatt = "get%sStatusNumber" % type 534 devices = getattr(self, devrel, None) 535 if not devices: 536 raise AttributeError( "%s not found on %s" % (devrel, self.id) ) 537 for device in devices(): 538 if getattr(device, statatt, -1)() > 0: 539 status += 1 540 return status
541
542 - def statusColor(self, status):
543 """colors for status fields for device groups""" 544 retval = '#00ff00' 545 if status == -1: 546 retval = "#d02090" 547 elif status == 1: 548 retval = '#ffff00' 549 elif status == 2: 550 retval = '#ff9900' 551 elif status > 2: 552 retval = '#ff0000' 553 return retval
554
555 - def getUserCommandTargets(self):
556 ''' Called by Commandable.doCommand() to ascertain objects on which 557 a UserCommand should be executed. 558 ''' 559 return self.getSubDevices()
560
561 - def getUrlForUserCommands(self):
562 return self.getPrimaryUrlPath() + '/deviceOrganizerManage'
563 576 577 security.declareProtected(ZEN_VIEW, 'getIconPath')
578 - def getIconPath(self):
579 """ Override the zProperty icon path and return a folder 580 """ 581 return "/zport/dmd/img/icons/folder.png"
582 583 security.declareProtected(ZEN_VIEW, 'getPrettyLink') 599 600 InitializeClass(DeviceOrganizer) 601