1
2
3
4
5
6
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
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
70
71
72
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")
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
200
201
208
209
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
234
235
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
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
289
290
291 security.declareProtected(ZEN_CHANGE_DEVICE_PRODSTATE, 'setProdState')
292 - def setProdState(self, state, deviceNames=None,
293 isOrganizer=False, REQUEST=None):
303
304
305 - def setPriority(self, priority, deviceNames=None,
306 isOrganizer=False, REQUEST=None):
316
317
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):
365
366 - def unlockDevices(self, deviceNames=None, isOrganizer=False, REQUEST=None):
373
374 - def lockDevicesFromDeletion(self, deviceNames=None,
375 sendEventWhenBlocked=None, isOrganizer=False, REQUEST=None):
382
383 - def lockDevicesFromUpdates(self, deviceNames=None,
384 sendEventWhenBlocked=None, isOrganizer=False, REQUEST=None):
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
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
470
471
487
488
507
508
515
522
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
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
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