1
2
3
4
5
6
7
8
9
10
11
12
13
14 __doc__ = """Device
15 Base device (remote computer) class
16 """
17
18 import os
19 import shutil
20 import time
21 import types
22 import socket
23 import logging
24 log = logging.getLogger("zen.Device")
25
26 from _mysql_exceptions import OperationalError
27
28 from urllib import quote as urlquote
29
30 from Products.ZenUtils.Utils import isXmlRpc
31 from Products.ZenUtils.Utils import unused
32 from Products.ZenUtils import Time
33 import RRDView
34 from Products.ZenUtils.IpUtil import checkip, IpAddressError, maskToBits
35 from Products.ZenModel.interfaces import IIndexed
36
37
38 from ManagedEntity import ManagedEntity
39
40 from AccessControl import ClassSecurityInfo
41 from Globals import DTMLFile
42 from Globals import InitializeClass
43 from DateTime import DateTime
44
45 from ZODB.POSException import POSError
46
47
48
49 from Products.DataCollector.ApplyDataMap import ApplyDataMap
50
51 from Products.ZenRelations.RelSchema import *
52 from Commandable import Commandable
53 from Lockable import Lockable
54 from MaintenanceWindowable import MaintenanceWindowable
55 from AdministrativeRoleable import AdministrativeRoleable
56 from ZenMenuable import ZenMenuable
57
58 from OperatingSystem import OperatingSystem
59 from DeviceHW import DeviceHW
60
61 from ZenStatus import ZenStatus
62 from Products.ZenModel.Exceptions import *
63 from ZenossSecurity import *
64 from Products.ZenUtils.FakeRequest import FakeRequest
65 from Products.ZenUtils.Utils import edgesToXML
66 from Products.ZenUtils import NetworkTree
67
68 from zope.interface import implements
69 from EventView import IEventView
70 from Products.ZenWidgets.interfaces import IMessageSender
71 from Products.ZenWidgets import messaging
72 from Products.Jobber.status import SUCCESS, FAILURE
73 from Products.ZenUtils.Utils import binPath
74 from Products.ZenEvents.browser.EventPillsAndSummaries import getEventPillME
75 from OFS.CopySupport import CopyError
76
77
79 """
80 Return the default network root.
81 """
82 return context.getDmdRoot('Networks')
83
84
105
106
107 -def manage_createDevice(context, deviceName, devicePath="/Discovered",
108 tag="", serialNumber="",
109 zSnmpCommunity="", zSnmpPort=161, zSnmpVer="",
110 rackSlot="", productionState=1000, comments="",
111 hwManufacturer="", hwProductName="",
112 osManufacturer="", osProductName="",
113 locationPath="", groupPaths=[], systemPaths=[],
114 performanceMonitor="localhost",
115 discoverProto="snmp", priority=3, manageIp="",
116 zProperties=None, title=None):
117 """
118 Device factory creates a device and sets up its relations and collects its
119 configuration. SNMP Community discovery also happens here. If an IP is
120 passed for deviceName it will be used for collection and the device name
121 will be set to the SNMP SysName (or ptr if SNMP Fails and ptr is valid)
122
123 @rtype: Device
124 """
125 manageIp = manageIp.replace(' ', '')
126 checkDeviceExists(context, deviceName, manageIp, performanceMonitor)
127 deviceName = context.prepId(deviceName)
128 log.info("device name '%s' for ip '%s'", deviceName, manageIp)
129 deviceClass = context.getDmdRoot("Devices").createOrganizer(devicePath)
130 deviceName = context.prepId(deviceName)
131 device = deviceClass.createInstance(deviceName)
132 device.setManageIp(manageIp)
133 device.manage_editDevice(
134 tag, serialNumber,
135 zSnmpCommunity, zSnmpPort, zSnmpVer,
136 rackSlot, productionState, comments,
137 hwManufacturer, hwProductName,
138 osManufacturer, osProductName,
139 locationPath, groupPaths, systemPaths,
140 performanceMonitor, priority, zProperties,
141 title)
142 return device
143
144
147 """
148 Find the SNMP community and version for an ip address using zSnmpCommunities.
149
150 @rtype: tuple of (community, port, version, device name)
151 """
152 from pynetsnmp.SnmpSession import SnmpSession
153
154 devroot = context.getDmdRoot('Devices').createOrganizer(devicePath)
155 communities = []
156 if community: communities.append(community)
157 communities.extend(getattr(devroot, "zSnmpCommunities", []))
158 if not port: port = getattr(devroot, "zSnmpPort", 161)
159 versions = ('v2c', 'v1')
160 if not version: version = getattr(devroot, 'zSnmpVer', None)
161 if version: versions = (version,)
162 timeout = getattr(devroot, "zSnmpTimeout", 2)
163 retries = getattr(devroot, "zSnmpTries", 2)
164 session = SnmpSession(ip, timeout=timeout, port=port, retries=retries)
165 oid = '.1.3.6.1.2.1.1.5.0'
166 goodcommunity = ""
167 goodversion = ""
168 devname = ""
169 for version in versions:
170 session.setVersion(version)
171 for community in communities:
172 session.community = community
173 try:
174 devname = session.get(oid).values()[0]
175 goodcommunity = session.community
176 goodversion = version
177 break
178 except (SystemExit, KeyboardInterrupt, POSError): raise
179 except: pass
180 if goodcommunity:
181 break
182 else:
183 raise NoSnmp("No SNMP found for IP = %s" % ip)
184 return (goodcommunity, port, goodversion, devname)
185
198
199 addDevice = DTMLFile('dtml/addDevice',globals())
200
201
202 -class Device(ManagedEntity, Commandable, Lockable, MaintenanceWindowable,
203 AdministrativeRoleable, ZenMenuable):
204 """
205 Device is a base class that represents the idea of a single computer system
206 that is made up of software running on hardware. It currently must be IP
207 enabled but maybe this will change.
208 """
209
210 implements(IEventView, IIndexed)
211
212 event_key = portal_type = meta_type = 'Device'
213
214 default_catalog = "deviceSearch"
215
216 relationshipManagerPathRestriction = '/Devices'
217
218 manageIp = ""
219 productionState = 1000
220 preMWProductionState = productionState
221 snmpAgent = ""
222 snmpDescr = ""
223 snmpOid = ""
224 snmpContact = ""
225 snmpSysName = ""
226 snmpLocation = ""
227 rackSlot = ""
228 comments = ""
229 sysedgeLicenseMode = ""
230 priority = 3
231
232
233 _temp_device = False
234
235 _properties = ManagedEntity._properties + (
236 {'id':'manageIp', 'type':'string', 'mode':'w'},
237 {'id':'productionState', 'type':'keyedselection', 'mode':'w',
238 'select_variable':'getProdStateConversions','setter':'setProdState'},
239 {'id':'preMWProductionState', 'type':'keyedselection', 'mode':'w',
240 'select_variable':'getProdStateConversions','setter':'setProdState'},
241 {'id':'snmpAgent', 'type':'string', 'mode':'w'},
242 {'id':'snmpDescr', 'type':'string', 'mode':''},
243 {'id':'snmpOid', 'type':'string', 'mode':''},
244 {'id':'snmpContact', 'type':'string', 'mode':''},
245 {'id':'snmpSysName', 'type':'string', 'mode':''},
246 {'id':'snmpLocation', 'type':'string', 'mode':''},
247 {'id':'snmpLastCollection', 'type':'date', 'mode':''},
248 {'id':'snmpAgent', 'type':'string', 'mode':''},
249 {'id':'rackSlot', 'type':'string', 'mode':'w'},
250 {'id':'comments', 'type':'text', 'mode':'w'},
251 {'id':'sysedgeLicenseMode', 'type':'string', 'mode':''},
252 {'id':'priority', 'type':'int', 'mode':'w'},
253 )
254
255 _relations = ManagedEntity._relations + (
256 ("deviceClass", ToOne(ToManyCont, "Products.ZenModel.DeviceClass",
257 "devices")),
258 ("perfServer", ToOne(ToMany, "Products.ZenModel.PerformanceConf",
259 "devices")),
260 ("location", ToOne(ToMany, "Products.ZenModel.Location", "devices")),
261 ("systems", ToMany(ToMany, "Products.ZenModel.System", "devices")),
262 ("groups", ToMany(ToMany, "Products.ZenModel.DeviceGroup", "devices")),
263 ("maintenanceWindows",ToManyCont(ToOne,
264 "Products.ZenModel.MaintenanceWindow", "productionState")),
265 ("adminRoles", ToManyCont(ToOne,"Products.ZenModel.AdministrativeRole",
266 "managedObject")),
267 ('userCommands', ToManyCont(ToOne, 'Products.ZenModel.UserCommand',
268 'commandable')),
269
270 ('monitors', ToMany(ToMany, 'Products.ZenModel.StatusMonitorConf',
271 'devices')),
272 )
273
274
275 factory_type_information = (
276 {
277 'id' : 'Device',
278 'meta_type' : 'Device',
279 'description' : """Base class for all devices""",
280 'icon' : 'Device_icon.gif',
281 'product' : 'ZenModel',
282 'factory' : 'manage_addDevice',
283 'immediate_view' : 'deviceStatus',
284 'actions' :
285 (
286 { 'id' : 'status'
287 , 'name' : 'Status'
288 , 'action' : 'deviceStatus'
289 , 'permissions' : (ZEN_VIEW, )
290 },
291 { 'id' : 'osdetail'
292 , 'name' : 'OS'
293 , 'action' : 'deviceOsDetail'
294 , 'permissions' : (ZEN_VIEW, )
295 },
296 { 'id' : 'hwdetail'
297 , 'name' : 'Hardware'
298 , 'action' : 'deviceHardwareDetail'
299 , 'permissions' : (ZEN_VIEW, )
300 },
301 { 'id' : 'swdetail'
302 , 'name' : 'Software'
303 , 'action' : 'deviceSoftwareDetail'
304 , 'permissions' : (ZEN_VIEW, )
305 },
306 { 'id' : 'events'
307 , 'name' : 'Events'
308 , 'action' : 'viewEvents'
309 , 'permissions' : (ZEN_VIEW, )
310 },
311
312
313
314
315
316 { 'id' : 'perfServer'
317 , 'name' : 'Perf'
318 , 'action' : 'viewDevicePerformance'
319 , 'permissions' : (ZEN_VIEW, )
320 },
321
322
323
324
325
326 { 'id' : 'edit'
327 , 'name' : 'Edit'
328 , 'action' : 'editDevice'
329 , 'permissions' : ("Change Device",)
330 },
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356 )
357 },
358 )
359
360 security = ClassSecurityInfo()
361
362 - def __init__(self, id, buildRelations=True):
372
374 flag = getattr(self, '_temp_device', None)
375 if flag is None:
376 flag = self._temp_device = False
377 return flag
378
379
380 security.declareProtected(ZEN_MANAGE_DMD, 'changeDeviceClass')
382 """
383 Wrapper for DeviceClass.moveDevices. The primary reason to use this
384 method instead of that one is that this one redirects the user to the
385 device in the web interface instead of the new device class.
386
387 @param deviceClassPath: device class in DMD path
388 @type deviceClassPath: string
389 @param REQUEST: Zope REQUEST object
390 @type REQUEST: Zope REQUEST object
391 """
392 self.deviceClass().moveDevices(deviceClassPath, (self.id,))
393 if REQUEST:
394 messaging.IMessageSender(self).sendToBrowser(
395 title='Device Moved',
396 body="%s was moved to %s." % (self.id, deviceClassPath))
397 REQUEST['message'] = "%s moved to %s" % (self.id, deviceClassPath)
398 if isinstance(REQUEST, FakeRequest) and \
399 REQUEST.has_key('oneKeyValueSoInstanceIsntEmptyAndEvalToFalse'):
400 return REQUEST['message']
401 device = self.getDmdRoot('Devices').findDevice(self.id)
402 REQUEST['RESPONSE'].redirect(device.absolute_url())
403 return
404
405
407 """
408 DEPRECATED
409 """
410 import warnings
411 warnings.warn('Device.getRRDTemplate is deprecated',
412 DeprecationWarning)
413 return ManagedEntity.getRRDTemplate(self)
414
416 """
417 Returns all the templates bound to this Device
418
419 @rtype: list
420
421 >>> from Products.ZenModel.Device import manage_addDevice
422 >>> manage_addDevice(devices, 'test')
423 >>> devices.test.getRRDTemplates()
424 [<RRDTemplate at /zport/dmd/Devices/rrdTemplates/Device>]
425 """
426 if not hasattr(self, 'zDeviceTemplates'):
427 return ManagedEntity.getRRDTemplates(self)
428 result = []
429 for name in self.zDeviceTemplates:
430 template = self.getRRDTemplateByName(name)
431 if template:
432 result.append(template)
433 return result
434
435
438
439
441 """
442 Returns the available DataSource options. DataSource options
443 are used to populate the dropdown when adding a new DataSource
444 and is a string. See L{RRDTemplate.RRDTemplate.getDataSourceOptions}
445 for more information.
446
447 @rtype: list
448 @return: [(displayName, dsOption),]
449 """
450
451
452
453
454
455 templates = self.getRRDTemplates()
456 if templates:
457 return templates[0].getDataSourceOptions()
458 return []
459
460
461
462
463
464
465
466
467
469 """
470 Returns the cached sysUpTime for this device
471
472 @rtype: int
473 """
474 try:
475 return self.cacheRRDValue('sysUpTime', -1)
476 except Exception:
477 log.exception("failed getting sysUpTime")
478 return -1
479
480
482 """
483 Returns the uptime of this device
484
485 @rtype: string
486 @todo: Performance enhancement: Should move import outside of method
487 """
488 from Products.ZenEvents import Availability
489 results = Availability.query(self.dmd, device=self.id, *args, **kw)
490 if results:
491 return results[0]
492 else:
493 return None
494
495
496
498 """
499 Override from object to handle lastPollSnmpUpTime and
500 snmpLastCollection
501
502 @todo: Not sure this is needed, see getLastPollSnmpUpTime and
503 getSnmpLastCollection
504 """
505 if name == 'lastPollSnmpUpTime':
506 return self._lastPollSnmpUpTime.getStatus()
507 elif name == 'snmpLastCollection':
508 return DateTime(self._snmpLastCollection)
509 else:
510 raise AttributeError( name )
511
512
514 """
515 Override from PropertyManager to handle checks and ip creation
516
517 @todo: Not sure this is needed, see setSnmpLastCollection
518 """
519 self._wrapperCheck(value)
520 if id == 'snmpLastCollection':
521 self._snmpLastCollection = float(value)
522 else:
523 ManagedEntity._setPropValue(self, id, value)
524
525
526 - def applyDataMap(self, datamap, relname="", compname="", modname=""):
533
534
536 """
537 Return a sequence of path tuples suitable for indexing by
538 a MultiPathIndex.
539 """
540 orgs = (
541 self.systems() +
542 self.groups() +
543 [self.location()] +
544 [self.deviceClass()]
545 )
546 orgs = filter(None, orgs)
547 paths = []
548 myPrimaryId = self.getPrimaryId()
549 myId = self.getId()
550 for org in orgs:
551 rel = org.primaryAq().devices
552 try:
553 orgself = rel._getOb(myPrimaryId)
554 except AttributeError:
555
556 try:
557 orgself = rel._getOb(myId)
558 except AttributeError:
559 log.warn("Unable to find %s (%s) in organizer %s",
560 myId, myPrimaryId,
561 '/'.join(org.getPrimaryPath()[3:]))
562 continue
563 paths.append(orgself.getPhysicalPath())
564
565 return paths
566
567
569 """
570 Trace the route to target using our routing table.
571 Wrapper method of OperatingSystem.traceRoute
572
573 @param target: Device name
574 @type target: string
575 @param ippath: IP addesses
576 @type ippath: list
577 @return: IP Addresses
578 @rtype: list
579 """
580 if ippath is None: ippath=[]
581 if type(target) in types.StringTypes:
582 target = self.findDevice(target)
583 if not target: raise ValueError("Target %s not found in DMD" % target)
584 return self.os.traceRoute(target, ippath)
585
586
588 """
589 Return list of monitored DeviceComponents on this device.
590 Wrapper method for getDeviceComponents
591 """
592 return self.getDeviceComponents(monitored=True,
593 collector=collector, type=type)
594
595 security.declareProtected(ZEN_VIEW, 'getDeviceComponents')
597 """
598 Return list of all DeviceComponents on this device.
599
600 @type monitored: boolean
601 @type collector: string
602 @type type: string
603 @permission: ZEN_VIEW
604 @rtype: list
605 """
606
607
608
609
610 if not self.componentSearch._catalog.indexes.has_key('getParentDeviceName'):
611 return self.getDeviceComponentsNoIndexGen()
612
613 query = {
614 'getParentDeviceName':self.id,
615 }
616 if collector is not None:
617 query['getCollectors'] = collector
618 if monitored is not None:
619 query['monitored'] = monitored
620 if type is not None:
621 query['meta_type'] = type
622 brains = self.componentSearch(query)
623 return [c.getObject() for c in brains]
624
625
627 """
628 Return a list of all device components by walking relations. This is
629 much slower then the normal getDeviceComponents method which uses the
630 component index. It is used when rebuilding the device indexes.
631 """
632 from DeviceComponent import DeviceComponent
633 for baseObject in (self, self.os, self.hw):
634 for rel in baseObject.getRelationships():
635 if rel.meta_type != "ToManyContRelationship": continue
636 for obj in rel():
637 if not isinstance(obj, DeviceComponent): break
638 yield obj
639
640
649
650
652 """
653 DEPRECATED - Return the hardware manufacturer name of this device.
654
655 @rtype: string
656 @todo: Remove this method and remove the call from testDevice.py
657 """
658 return self.hw.getManufacturerName()
659
660
662 """
663 Return the hardware product name of this device.
664
665 @rtype: string
666 """
667 return self.hw.getProductName()
668
669
671 """
672 DEPRECATED - Return the productKey of the device hardware.
673
674 @rtype: string
675 @todo: Remove this method and remove the call from testDevice.py
676 """
677 return self.hw.getProductKey()
678
679
681 """
682 DEPRECATED - Return the OS manufacturer name of this device.
683
684 @rtype: string
685 @todo: Remove this method and remove the call from testDevice.py
686 """
687 return self.os.getManufacturerName()
688
689
691 """
692 DEPRECATED - Return the OS product name of this device.
693
694 @rtype: string
695 @todo: Remove this method and remove the call from testDevice.py
696 """
697 return self.os.getProductName()
698
699
701 """
702 DEPRECATED - Return the productKey of the device OS.
703
704 @rtype: string
705 @todo: Remove this method and remove the call from testDevice.py
706 """
707 return self.os.getProductKey()
708
709
711 """
712 Set the productKey of the device OS.
713 """
714 self.os.setProductKey(prodKey, manufacturer)
715
716
718 """
719 DEPRECATED - Return the tag of the device HW.
720
721 @rtype: string
722 @todo: remove this method and remove the call from testDevice.py
723 """
724 return self.hw.tag
725
726
728 """
729 Set the asset tag of the device hardware.
730 """
731 self.hw.tag = assettag
732
733
735 """
736 Set the productKey of the device hardware.
737 """
738 self.hw.setProductKey(prodKey, manufacturer)
739
740
742 """
743 Set the hardware serial number.
744 """
745 self.hw.serialNumber = number
746
747
749 """
750 DEPRECATED - Return the hardware serial number.
751
752 @rtype: string
753 @todo: Remove this method and remove the call from testDevice.py
754 """
755 return self.hw.serialNumber
756
757
759 """
760 Return the ips that our indirect routs point to which aren't currently
761 connected to devices.
762
763 @todo: Can be moved to zendisc.py
764 """
765 ips = []
766 for r in self.os.routes():
767 ipobj = r.nexthop()
768
769 if ipobj: ips.append(ipobj.id)
770 return ips
771
772
773 security.declareProtected(ZEN_VIEW, 'getLocationName')
775 """
776 Return the full location name ie /Location/SubLocation/Rack
777
778 @rtype: string
779 @permission: ZEN_VIEW
780 """
781 loc = self.location()
782 if loc: return loc.getOrganizerName()
783 return ""
784
785 security.declareProtected(ZEN_VIEW, 'getLocationLink')
801
802
803 security.declareProtected(ZEN_VIEW, 'getSystemNames')
805 """
806 Return the system names for this device
807
808 @rtype: list
809 @permission: ZEN_VIEW
810 """
811 return map(lambda x: x.getOrganizerName(), self.systems())
812
813
814 security.declareProtected(ZEN_VIEW, 'getSystemNamesString')
816 """
817 Return the system names for this device as a string
818
819 @rtype: string
820 @permission: ZEN_VIEW
821 """
822 return sep.join(self.getSystemNames())
823
824
825 security.declareProtected(ZEN_VIEW, 'getDeviceGroupNames')
827 """
828 Return the device group names for this device
829
830 @rtype: list
831 @permission: ZEN_VIEW
832 """
833 return map(lambda x: x.getOrganizerName(), self.groups())
834
835
836 security.declareProtected(ZEN_VIEW, 'getPerformanceServer')
845
846
847 security.declareProtected(ZEN_VIEW, 'getPerformanceServerName')
858
859
861 """Return the network root object
862 """
863 return self.getDmdRoot('Networks')
864
865 security.declareProtected(ZEN_VIEW, 'getLastChange')
867 """
868 Return DateTime of last change detected on this device.
869
870 @rtype: DateTime
871 @permission: ZEN_VIEW
872 """
873 return DateTime(float(self._lastChange))
874
875
876 security.declareProtected(ZEN_VIEW, 'getLastChangeString')
878 """
879 Return date string of last change detected on this device.
880
881 @rtype: string
882 @permission: ZEN_VIEW
883 """
884 return Time.LocalDateTimeSecsResolution(float(self._lastChange))
885
886
887 security.declareProtected(ZEN_VIEW, 'getSnmpLastCollection')
889 """
890 Return DateTime of last SNMP collection on this device.
891
892 @rtype: DateTime
893 @permission: ZEN_VIEW
894 """
895 return DateTime(float(self._snmpLastCollection))
896
897
898 security.declareProtected(ZEN_VIEW, 'getSnmpLastCollectionString')
900 """
901 Return date string of last SNMP collection on this device.
902
903 @rtype: string
904 @permission: ZEN_VIEW
905 """
906 return Time.LocalDateTimeSecsResolution(float(self._snmpLastCollection))
907
908
909 security.declareProtected(ZEN_ADMIN_DEVICE, 'setManageIp')
911 """
912 Set the manage IP, if IP is not passed perform DNS lookup.
913
914 @rtype: string
915 @permission: ZEN_ADMIN_DEVICE
916 """
917 ip = ip.replace(' ', '')
918 origip = ip
919 try:
920 if ip.find("/") > -1:
921 ipWithoutNetmask, netmask = ip.split("/",1)
922 checkip(ipWithoutNetmask)
923
924 if maskToBits(netmask) is None: ip = ""
925 else:
926 checkip(ip)
927 except IpAddressError: ip = ""
928 except ValueError: ip = ""
929 if not ip:
930 try: ip = socket.gethostbyname(self.id)
931 except socket.error: ip = ""
932 self.manageIp = ip
933 self.index_object()
934 if REQUEST:
935 msgr = IMessageSender(self)
936 if ip:
937 msgr.sendToBrowser('Manage IP Set',
938 "%s's IP address has been set to %s." % (self.id, ip))
939 else:
940 msgr.sendToBrowser('Invalid IP',
941 ("%s is an invalid IP address, and no appropriate IP could"
942 " be found via DNS") % origip)
943 return self.callZenScreen(REQUEST)
944 else:
945 return self.manageIp
946
947
948 security.declareProtected(ZEN_VIEW, 'getManageIp')
950 """
951 Return the management ip for this device.
952
953 @rtype: string
954 @permission: ZEN_VIEW
955 """
956 return self.manageIp
957
958
960 """
961 DEPRECATED - Return the management ipobject for this device.
962
963 @rtype: IpAddress
964 @todo: This method may not be called anywhere, remove it.
965 """
966 if self.manageIp:
967 return self.Networks.findIp(self.manageIp)
968
969
970 security.declareProtected(ZEN_VIEW, 'getManageInterface')
972 """
973 Return the management interface of a device based on its manageIp.
974
975 @rtype: IpInterface
976 @permission: ZEN_VIEW
977 """
978 ipobj = self.Networks.findIp(self.manageIp)
979 if ipobj: return ipobj.interface()
980
981
982 security.declareProtected(ZEN_VIEW, 'uptimeStr')
984 """
985 Return the SNMP uptime
986
987 @rtype: string
988 @permission: ZEN_VIEW
989 """
990 ut = self.sysUpTime()
991 if ut < 0:
992 return "Unknown"
993 elif ut == 0:
994 return "0d:0h:0m:0s"
995 ut = float(ut)/100.
996 days = ut/86400
997 hour = (ut%86400)/3600
998 mins = (ut%3600)/60
999 secs = ut%60
1000 return "%02dd:%02dh:%02dm:%02ds" % (
1001 days, hour, mins, secs)
1002
1003
1005 """
1006 Build a list of all device paths that have the python class pyclass
1007
1008 @rtype: list
1009 """
1010 dclass = self.getDmdRoot("Devices")
1011 return dclass.getPeerDeviceClassNames(self.__class__)
1012
1013
1014
1015
1016
1017
1018 security.declareProtected(ZEN_CHANGE_DEVICE, 'manage_snmpCommunity')
1020 """
1021 Reset the snmp community using the zSnmpCommunities variable.
1022
1023 @permission: ZEN_CHANGE_DEVICE
1024 """
1025 try:
1026 zSnmpCommunity, zSnmpPort, zSnmpVer, snmpname = \
1027 findCommunity(self, self.manageIp, self.getDeviceClassPath(),
1028 port=self.zSnmpPort, version=self.zSnmpVer)
1029 except NoSnmp:
1030 pass
1031 else:
1032 if self.zSnmpCommunity != zSnmpCommunity:
1033 self.setZenProperty("zSnmpCommunity", zSnmpCommunity)
1034 if self.zSnmpPort != zSnmpPort:
1035 self.setZenProperty("zSnmpPort", zSnmpPort)
1036 if self.zSnmpVer != zSnmpVer:
1037 self.setZenProperty("zSnmpVer", zSnmpVer)
1038
1039
1040 security.declareProtected(ZEN_CHANGE_DEVICE, 'manage_editDevice')
1041 - def manage_editDevice(self,
1042 tag="", serialNumber="",
1043 zSnmpCommunity="", zSnmpPort=161, zSnmpVer="",
1044 rackSlot="", productionState=1000, comments="",
1045 hwManufacturer="", hwProductName="",
1046 osManufacturer="", osProductName="",
1047 locationPath="", groupPaths=[], systemPaths=[],
1048 performanceMonitor="localhost", priority=3,
1049 zProperties=None, title=None, REQUEST=None):
1050 """
1051 Edit the device relation and attributes.
1052
1053 @param locationPath: path to a Location
1054 @type locationPath: string
1055 @param groupPaths: paths to DeviceGroups
1056 @type groupPaths: list
1057 @param systemPaths: paths to Systems
1058 @type systemPaths: list
1059 @param performanceMonitor: name of PerformanceMonitor
1060 @type performanceMonitor: string
1061 @permission: ZEN_CHANGE_DEVICE
1062 """
1063 if title is not None:
1064 self.title = title
1065 self.hw.tag = tag
1066 self.hw.serialNumber = serialNumber
1067
1068
1069 if zProperties is None: zProperties = {}
1070 zProperties.update({'zSnmpCommunity':zSnmpCommunity,
1071 'zSnmpPort':zSnmpPort,
1072 'zSnmpVer':zSnmpVer})
1073 for prop, value in zProperties.items():
1074 if value and getattr(self, prop) != value:
1075 self.setZenProperty(prop, value)
1076
1077 self.rackSlot = rackSlot
1078 self.setProdState(productionState)
1079 self.setPriority(priority)
1080 self.comments = comments
1081
1082 if hwManufacturer and hwProductName:
1083 log.info("setting hardware manufacturer to %s productName to %s"
1084 % (hwManufacturer, hwProductName))
1085 self.hw.setProduct(hwProductName, hwManufacturer)
1086 else:
1087 self.hw.productClass.removeRelation()
1088
1089 if osManufacturer and osProductName:
1090 log.info("setting os manufacturer to %s productName to %s"
1091 % (osManufacturer, osProductName))
1092 self.os.setProduct(osProductName, osManufacturer)
1093 self.os.productClass().isOS = True
1094 else:
1095 self.os.productClass.removeRelation()
1096
1097 if locationPath:
1098 log.info("setting location to %s" % locationPath)
1099 self.setLocation(locationPath)
1100
1101 if groupPaths:
1102 log.info("setting group %s" % groupPaths)
1103 self.setGroups(groupPaths)
1104
1105 if systemPaths:
1106 log.info("setting system %s" % systemPaths)
1107 self.setSystems(systemPaths)
1108
1109 if performanceMonitor != self.getPerformanceServerName():
1110 log.info("setting performance monitor to %s" % performanceMonitor)
1111 self.setPerformanceMonitor(performanceMonitor)
1112
1113 self.setLastChange()
1114 self.index_object()
1115 if REQUEST:
1116 from Products.ZenUtils.Time import SaveMessage
1117 IMessageSender(self).sendToBrowser('Saved', SaveMessage())
1118 return self.callZenScreen(REQUEST)
1119
1121 """
1122 Changes the title to newTitle and reindexes the object
1123 """
1124 self.title = newTitle
1125 self.index_object()
1126
1128 """
1129 Returns true if the device production state >= zProdStateThreshold.
1130
1131 @rtype: boolean
1132 """
1133 return self.productionState >= self.zProdStateThreshold
1134
1135
1137 """
1138 Returns true if the device is subject to SNMP monitoring
1139
1140 @rtype: boolean
1141 """
1142 return (self.monitorDevice()
1143 and self.getManageIp()
1144 and not self.zSnmpMonitorIgnore)
1145
1146
1154
1155
1157 """
1158 Return the numeric device priority.
1159
1160 @rtype: int
1161 """
1162 return self.priority
1163
1164
1166 """
1167 Return the device priority as a string.
1168
1169 @rtype: string
1170 """
1171 return self.convertPriority(self.priority)
1172
1174 """
1175 Return the pingStatus as a string
1176
1177 @rtype: string
1178 """
1179 return self.convertStatus(self.getPingStatus())
1180
1182 """
1183 Return the snmpStatus as a string
1184
1185 @rtype: string
1186 """
1187 return self.convertStatus(self.getSnmpStatus())
1188
1189 security.declareProtected(ZEN_CHANGE_DEVICE_PRODSTATE, 'setProdState')
1190 - def setProdState(self, state, maintWindowChange=False, REQUEST=None):
1235
1236 security.declareProtected(ZEN_CHANGE_DEVICE, 'setPriority')
1270
1271 security.declareProtected(ZEN_CHANGE_DEVICE, 'setLastChange')
1273 """
1274 Set the changed datetime for this device.
1275
1276 @param value: secs since the epoch, default is now
1277 @type value: float
1278 @permission: ZEN_CHANGE_DEVICE
1279 """
1280 if value is None:
1281 value = time.time()
1282 self._lastChange = float(value)
1283
1284 security.declareProtected(ZEN_CHANGE_DEVICE, 'setSnmpLastCollection')
1286 """
1287 Set the last time snmp collection occurred.
1288
1289 @param value: secs since the epoch, default is now
1290 @type value: float
1291 @permission: ZEN_CHANGE_DEVICE
1292 """
1293 if value is None:
1294 value = time.time()
1295 self._snmpLastCollection = float(value)
1296
1297
1298 security.declareProtected(ZEN_CHANGE_DEVICE, 'addManufacturer')
1299 - def addManufacturer(self, newHWManufacturerName=None,
1300 newSWManufacturerName=None, REQUEST=None):
1301 """
1302 DEPRECATED -
1303 Add either a hardware or software manufacturer to the database.
1304
1305 @permission: ZEN_CHANGE_DEVICE
1306 @todo: Doesn't really do work on a device object.
1307 Already exists on ZDeviceLoader
1308 """
1309 mname = newHWManufacturerName
1310 field = 'hwManufacturer'
1311 if not mname:
1312 mname = newSWManufacturerName
1313 field = 'osManufacturer'
1314 self.getDmdRoot("Manufacturers").createManufacturer(mname)
1315 if REQUEST:
1316 REQUEST[field] = mname
1317 messaging.IMessageSender(self).sendToBrowser(
1318 'Manufacturer Added',
1319 'The %s manufacturer has been created.' % mname
1320 )
1321 return self.callZenScreen(REQUEST)
1322
1323
1324 security.declareProtected(ZEN_CHANGE_DEVICE, 'setHWProduct')
1325 - def setHWProduct(self, newHWProductName=None, hwManufacturer=None,
1326 REQUEST=None):
1354
1355
1356 security.declareProtected(ZEN_CHANGE_DEVICE, 'setOSProduct')
1357 - def setOSProduct(self, newOSProductName=None, osManufacturer=None, REQUEST=None):
1383
1384
1385 security.declareProtected(ZEN_CHANGE_DEVICE, 'setLocation')
1399
1400
1401 - def addLocation(self, newLocationPath, REQUEST=None):
1402 """
1403 DEPRECATED
1404 Add a new location and relate it to this device
1405
1406 @todo: Doesn't really do work on a device object.
1407 Already exists on ZDeviceLoader
1408 """
1409 self.getDmdRoot("Locations").createOrganizer(newLocationPath)
1410 if REQUEST:
1411 REQUEST['locationPath'] = newLocationPath
1412 messaging.IMessageSender(self).sendToBrowser(
1413 'Location Added',
1414 'Location %s has been created.' % newLocationPath
1415 )
1416 return self.callZenScreen(REQUEST)
1417
1418
1419 security.declareProtected(ZEN_CHANGE_DEVICE, 'setPerformanceMonitor')
1444
1445
1446 security.declareProtected(ZEN_CHANGE_DEVICE, 'setGroups')
1448 """
1449 Set the list of groups for this device based on a list of paths
1450
1451 @permission: ZEN_CHANGE_DEVICE
1452 """
1453 objGetter = self.getDmdRoot("Groups").createOrganizer
1454 self._setRelations("groups", objGetter, groupPaths)
1455 self.index_object()
1456
1457
1458 security.declareProtected(ZEN_CHANGE_DEVICE, 'addDeviceGroup')
1475
1476
1477 security.declareProtected(ZEN_CHANGE_DEVICE, 'setSystems')
1479 """
1480 Set a list of systems to this device using their system paths
1481
1482 @permission: ZEN_CHANGE_DEVICE
1483 """
1484 objGetter = self.getDmdRoot("Systems").createOrganizer
1485 self._setRelations("systems", objGetter, systemPaths)
1486 self.index_object()
1487
1488
1489 security.declareProtected(ZEN_CHANGE_DEVICE, 'addSystem')
1490 - def addSystem(self, newSystemPath, REQUEST=None):
1506
1507
1508 security.declareProtected(ZEN_CHANGE_DEVICE, 'setTerminalServer')
1510 """
1511 Set the terminal server of this device
1512
1513 @param termservername: device name of terminal server
1514 @permission: ZEN_CHANGE_DEVICE
1515 """
1516 termserver = self.findDevice(termservername)
1517 if termserver:
1518 self.addRelation('termserver', termserver)
1519
1520
1522 """
1523 Set related objects to this device
1524
1525 @param relName: name of the relation to set
1526 @param objGetter: method to get the relation
1527 @param relPaths: list of relationship paths
1528 """
1529 if type(relPaths) != type([]) and type(relPaths) != type(()):
1530 relPaths = [relPaths,]
1531 relPaths = filter(lambda x: x.strip(), relPaths)
1532 rel = getattr(self, relName, None)
1533 if not rel:
1534 raise AttributeError( "Relation %s not found" % relName)
1535 curRelIds = {}
1536 for value in rel.objectValuesAll():
1537 curRelIds[value.getOrganizerName()] = value
1538 for path in relPaths:
1539 if not curRelIds.has_key(path):
1540 robj = objGetter(path)
1541 self.addRelation(relName, robj)
1542 else:
1543 del curRelIds[path]
1544 for obj in curRelIds.values():
1545 self.removeRelation(relName, obj)
1546 self.setAdminLocalRoles()
1547
1548
1550 """
1551 Return the expanded zComment property
1552
1553 @rtype: HTML output
1554 """
1555 from Products.ZenUtils.ZenTales import talesEval
1556 try:
1557 return talesEval('string:' + self.zLinks, self)
1558 except Exception, ex:
1559 import cgi
1560 return "<i class='errortitle'>%s</i>" % cgi.escape(str(ex))
1561
1562
1563
1564
1565
1566 security.declareProtected(ZEN_VIEW, 'device')
1568 """
1569 Support DeviceResultInt mixin class. Returns itself
1570
1571 @permission: ZEN_VIEW
1572 """
1573 return self
1574
1575
1576
1577
1578
1579
1580
1582 """
1583 Returns true if the device has more SNMP failures
1584 than maxFailures on its status mon.
1585
1586 @rtype: boolean
1587 """
1588 statusmon = self.monitors()
1589 if len(statusmon) > 0:
1590 statusmon = statusmon[0]
1591 return statusmon.maxFailures < self.getSnmpStatusNumber()
1592 return False
1593
1594
1595
1596 security.declareProtected(ZEN_MANAGE_DEVICE_STATUS,
1597 'getLastPollSnmpUpTime')
1599 """
1600 Get the value of the snmpUpTime status object
1601
1602 @permission: ZEN_MANAGE_DEVICE_STATUS
1603 """
1604 return self._lastPollSnmpUpTime.getStatus()
1605
1606
1607
1608 security.declareProtected(ZEN_MANAGE_DEVICE_STATUS,
1609 'setLastPollSnmpUpTime')
1611 """
1612 Set the value of the snmpUpTime status object
1613
1614 @permission: ZEN_MANAGE_DEVICE_STATUS
1615 """
1616 self._lastPollSnmpUpTime.setStatus(value)
1617
1618
1619 - def snmpAgeCheck(self, hours):
1620 """
1621 Returns True if SNMP data was collected more than 24 hours ago
1622 """
1623 lastcoll = self.getSnmpLastCollection()
1624 hours = hours/24.0
1625 if DateTime() > lastcoll + hours: return 1
1626
1627
1629 """
1630 Apply zProperties inherited from Product Contexts.
1631 """
1632 self._applyProdContext(self.hw.getProductContext())
1633 self._applyProdContext(self.os.getProductContext())
1634 for soft in self.os.software():
1635 self._applyProdContext(soft.getProductContext())
1636
1637
1638 - def _applyProdContext(self, context):
1639 """
1640 Apply zProperties taken for the product context passed in.
1641
1642 @param context: list of tuples returned from
1643 getProductContext on a MEProduct.
1644 """
1645 for name, value in context:
1646 if name == "zDeviceClass" and value:
1647 log.info("move device to %s", value)
1648 self.moveDevices(value, self.id)
1649 elif name == "zDeviceGroup" and value:
1650 log.info("add device to group %s", value)
1651 self.addDeviceGroup(value)
1652 elif name == "zSystem" and value:
1653 log.info("add device to system %s", value)
1654 self.addSystem(value)
1655
1656
1657
1658
1659
1660
1661
1662 security.declareProtected(ZEN_MANAGE_DEVICE, 'collectDevice')
1663 - def collectDevice(self, setlog=True, REQUEST=None, generateEvents=False):
1664 """
1665 Collect the configuration of this device AKA Model Device
1666
1667 @param setlog: If true, set up the output log of this process
1668 @permission: ZEN_MANAGE_DEVICE
1669 @todo: generateEvents param is not being used.
1670 """
1671 unused(generateEvents)
1672 xmlrpc = isXmlRpc(REQUEST)
1673 perfConf = self.getPerformanceServer()
1674 perfConf.collectDevice(self, setlog, REQUEST)
1675
1676 if xmlrpc: return 0
1677
1678
1679 security.declareProtected(ZEN_DELETE_DEVICE, 'deleteDevice')
1680 - def deleteDevice(self, deleteStatus=False, deleteHistory=False,
1681 deletePerf=False, REQUEST=None):
1708
1709
1710 security.declareProtected(ZEN_MANAGE_DEVICE, 'manage_deleteHeartbeat')
1724
1725
1726 security.declareProtected(ZEN_ADMIN_DEVICE, 'renameDevice')
1728 """
1729 Rename device from the DMD
1730
1731 @permission: ZEN_ADMIN_DEVICE
1732 @param newId: new name
1733 @type newId: string
1734 @param REQUEST: Zope REQUEST object
1735 @type REQUEST: Zope REQUEST object
1736 """
1737 parent = self.getPrimaryParent()
1738 oldId = self.getId()
1739 if newId is None:
1740 if REQUEST:
1741 REQUEST['RESPONSE'].redirect("%s/%s" % (parent.absolute_url(), oldId))
1742 return
1743
1744 if not isinstance(newId, unicode):
1745 newId = self.prepId(newId)
1746
1747 newId = newId.strip()
1748
1749 if newId == '' or newId == oldId:
1750 if REQUEST:
1751 REQUEST['RESPONSE'].redirect("%s/%s" % (parent.absolute_url(), oldId))
1752 return
1753
1754
1755 try:
1756
1757
1758 if self.title:
1759 self.title = newId
1760 parent.manage_renameObject(oldId, newId)
1761 self.renameDeviceInEvents(oldId, newId)
1762 self.renameDeviceInPerformance(oldId, newId)
1763 self.setLastChange()
1764
1765 if REQUEST:
1766 messaging.IMessageSender(self).sendToBrowser(
1767 'Device Renamed',
1768 "Device %s was renamed to %s." % (oldId, newId)
1769 )
1770 REQUEST['RESPONSE'].redirect("%s/%s" % (parent.absolute_url(), newId))
1771
1772 except CopyError, e:
1773 if REQUEST:
1774 messaging.IMessageSender(self).sendToBrowser(
1775 'Device Rename Failed', str(e), messaging.CRITICAL)
1776 return self.callZenScreen(REQUEST)
1777
1779 """update the device column in the status and history tables for rows
1780 associated with this device"""
1781 zem=self.dmd.ZenEventManager
1782 query="update %%s set device='%s' where device='%s';"%(new, old)
1783 sqlscript=''.join([query%t for t in ('status', 'history')])
1784 args=['mysql',
1785 '-h%s'%zem.host,
1786 '-P%s'%zem.port,
1787 '-u%s'%zem.username,
1788 '-p%s'%zem.password,
1789 '-e%s'%sqlscript,
1790 zem.database,
1791 ]
1792 if not os.fork(): os.execvp('mysql', args)
1793
1814
1815
1824
1825
1832
1833
1835 """
1836 IpAddresses aren't contained underneath Device, so manage_beforeDelete
1837 won't propagate. Thus we must remove those links explicitly.
1838 """
1839 cat = self.dmd.ZenLinkManager._getCatalog(layer=3)
1840 brains = cat(deviceId=self.id)
1841 for brain in brains:
1842 brain.getObject().unindex_links()
1843
1844
1864
1865
1867 """
1868 Called by Commandable.doCommand() to ascertain objects on which
1869 a UserCommand should be executed.
1870 """
1871 return [self]
1872
1881
1883 """
1884 Returns a URL to redirect to after a command has executed
1885 used by Commandable
1886 """
1887 return self.getPrimaryUrlPath() + '/deviceManagement'
1888
1890 """
1891 Returns HTML Event Summary of a device
1892 """
1893 html = []
1894 html.append("<table width='100%' cellspacing='1' cellpadding='3'>")
1895 html.append("<tr>")
1896 def evsummarycell(ev):
1897 if ev[1]-ev[2]>=0: klass = '%s empty thin' % ev[0]
1898 else: klass = '%s thin' % ev[0]
1899 h = '<th align="center" width="16%%" class="%s">%s/%s</th>' % (
1900 klass, ev[1], ev[2])
1901 return h
1902 info = self.getEventSummary(severity)
1903 html += map(evsummarycell, info)
1904 html.append('</tr></table>')
1905 return '\n'.join(html)
1906
1908 """
1909 Returns data ready for serialization
1910 """
1911 url, classurl = map(urlquote,
1912 (self.getDeviceUrl(), self.getDeviceClassPath()))
1913 id = '<a class="tablevalues" href="%s">%s</a>' % (
1914 url, self.titleOrId())
1915 ip = self.getDeviceIp()
1916 if self.checkRemotePerm(ZEN_VIEW, self.deviceClass()):
1917 path = '<a href="/zport/dmd/Devices%s">%s</a>' % (classurl,classurl)
1918 else:
1919 path = classurl
1920 prod = self.getProdState()
1921 zem = self.dmd.ZenEventManager
1922 evsum = getEventPillME(zem, self, 1, minSeverity)[0]
1923 return [id, ip, path, prod, evsum, self.id]
1924
1926 """
1927 Add export of our child objects.
1928 """
1929 map(lambda o: o.exportXml(ofile, ignorerels), (self.hw, self.os))
1930
1932 """
1933 Returns a list of possible options for a given zProperty
1934 """
1935 if propname == 'zCollectorPlugins':
1936 from Products.DataCollector.Plugins import loadPlugins
1937 names = [ldr.pluginName for ldr in loadPlugins(self.dmd)]
1938 names.sort()
1939 return names
1940 if propname == 'zCommandProtocol':
1941 return ['ssh', 'telnet']
1942 if propname == 'zSnmpVer':
1943 return ['v1', 'v2c', 'v3']
1944 if propname == 'zSnmpAuthType':
1945 return ['', 'MD5', 'SHA']
1946 if propname == 'zSnmpPrivType':
1947 return ['', 'DES', 'AES']
1948 return ManagedEntity.zenPropertyOptions(self, propname)
1949
1950 security.declareProtected(ZEN_MANAGE_DEVICE, 'pushConfig')
1952 """
1953 This will result in a push of all the devices to live collectors
1954
1955 @permission: ZEN_MANAGE_DEVICE
1956 """
1957 self._p_changed = True
1958 if REQUEST:
1959 messaging.IMessageSender(self).sendToBrowser(
1960 'Changes Pushed',
1961 'Changes to %s pushed to collectors.' % self.id
1962 )
1963 return self.callZenScreen(REQUEST)
1964
1965 security.declareProtected(ZEN_EDIT_LOCAL_TEMPLATES, 'bindTemplates')
1967 """
1968 This will bind available templates to the zDeviceTemplates
1969
1970 @permission: ZEN_EDIT_LOCAL_TEMPLATES
1971 """
1972 return self.setZenProperty('zDeviceTemplates', ids, REQUEST)
1973
1974 security.declareProtected(ZEN_EDIT_LOCAL_TEMPLATES, 'removeZDeviceTemplates')
1976 """
1977 Deletes the local zProperty, zDeviceTemplates
1978
1979 @permission: ZEN_EDIT_LOCAL_TEMPLATES
1980 """
1981 for id in self.zDeviceTemplates:
1982 self.removeLocalRRDTemplate(id)
1983 return self.deleteZenProperty('zDeviceTemplates', REQUEST)
1984
1985 security.declareProtected(ZEN_EDIT_LOCAL_TEMPLATES, 'addLocalTemplate')
2002
2004 """
2005 Returns all available templates for this device
2006 """
2007
2008 templates = self.objectValues('RRDTemplate')
2009
2010
2011 templates += [t for t in self.deviceClass().getRRDTemplates()
2012 if t.id not in [r.id for r in templates]]
2013 def cmpTemplates(a, b):
2014 return cmp(a.id.lower(), b.id.lower())
2015 templates.sort(cmpTemplates)
2016 return [ t for t in templates
2017 if isinstance(self, t.getTargetPythonClass()) ]
2018
2019
2020 security.declareProtected(ZEN_VIEW, 'getLinks')
2035
2036 security.declareProtected(ZEN_VIEW, 'getXMLEdges')
2037 - def getXMLEdges(self, depth=3, filter="/", start=()):
2045
2046 security.declareProtected(ZEN_VIEW, 'getPrettyLink')
2048 """
2049 Gets a link to this device, plus an icon
2050
2051 @rtype: HTML text
2052 @permission: ZEN_VIEW
2053 """
2054 template = ("<div class='device-icon-container'>"
2055 "<img class='device-icon' src='%s'/> "
2056 "</div>%s")
2057 icon = self.getIconPath()
2058 href = self.getPrimaryUrlPath().replace('%','%%')
2059 name = self.titleOrId()
2060 linktemplate = "<a href='"+href+"' class='prettylink'>%s</a>"
2061 rendered = template % (icon, name)
2062 if not self.checkRemotePerm(ZEN_VIEW, self):
2063 return rendered
2064 else:
2065 return linktemplate % rendered
2066
2067
2130
2131 InitializeClass(Device)
2132