| Trees | Indices | Help |
|
|---|
|
|
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")
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")
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")
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")
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
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
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
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
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
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
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
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
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
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
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')
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
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
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
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
394 """No action.
395 Index of subdevices will happen in manage_addAdministrativeRole
396 """
397 pass
398
400 """No action.
401 Unindex of subdevices will happen in manage_deleteAdministrativeRole
402 """
403 pass
404
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
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
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
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
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
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
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
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
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
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
556 ''' Called by Commandable.doCommand() to ascertain objects on which
557 a UserCommand should be executed.
558 '''
559 return self.getSubDevices()
560
562 return self.getPrimaryUrlPath() + '/deviceOrganizerManage'
563
565 """ Return all Links on all interfaces on all
566 Devices in this Organizer
567 """
568 alllinks = []
569 if recursive:
570 devices = self.getSubDevicesGen()
571 else:
572 devices = self.devices.objectValuesGen()
573 for device in devices:
574 alllinks.extend(list(device.getLinks()))
575 return alllinks
576
577 security.declareProtected(ZEN_VIEW, 'getIconPath')
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')
585 """ Gets a link to this object, plus an icon """
586 href = self.getPrimaryUrlPath().replace('%','%%')
587 linktemplate = "<a href='"+href+"' class='prettylink'>%s</a>"
588 icon = ("<div class='device-icon-container'> "
589 "<img class='device-icon' src='%s'/> "
590 "</div>") % self.getIconPath()
591 name = self.getPrimaryDmdId()
592 if noicon: icon=''
593 if shortDesc: name = self.id
594 rendered = icon + name
595 if not self.checkRemotePerm("View", self):
596 return rendered
597 else:
598 return linktemplate % rendered
599
600 InitializeClass(DeviceOrganizer)
601
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1.1812 on Mon Jul 30 17:11:45 2012 | http://epydoc.sourceforge.net |