1
2
3
4
5
6
7
8
9
10
11
12
13
14 __doc__="""DeviceClass
15
16 $Id: DeviceClass.py,v 1.76 2004/04/22 19:09:53 edahl Exp $"""
17
18 __version__ = "$Revision: 1.76 $"[11:-2]
19
20 import os
21 import types
22 import time
23 import urllib
24 from glob import glob
25 import transaction
26 import simplejson
27 import logging
28 log = logging.getLogger('zen.DeviceClass')
29
30 import DateTime
31 from zExceptions import Redirect
32 from Globals import DTMLFile
33 from Globals import InitializeClass
34 from Globals import InitializeClass
35 from OFS.Folder import manage_addFolder
36 from Acquisition import aq_base, aq_parent, aq_chain
37 from AccessControl import ClassSecurityInfo
38 from AccessControl import Permissions as permissions
39
40 from Products.AdvancedQuery import MatchGlob, Or, Eq
41 from Products.PageTemplates.PageTemplateFile import PageTemplateFile
42
43 from Products.ZenRelations.RelSchema import *
44 from Products.ZenUtils.Search import makeCaseSensitiveFieldIndex
45 from Products.ZenUtils.Search import makeCaseInsensitiveFieldIndex
46 from Products.ZenUtils.Search import makeCaseInsensitiveKeywordIndex
47 from Products.ZenUtils.Search import makePathIndex
48 from Products.ZenUtils.Utils import zenPath
49 from Products.ZenUtils.Utils import importClass
50
51 from Products.ZenUtils.FakeRequest import FakeRequest
52
53 from RRDTemplate import RRDTemplate
54 from DeviceOrganizer import DeviceOrganizer
55 from ZenPackable import ZenPackable
56
57 _marker = "__MARKER___"
58
65
66
67 addDeviceClass = DTMLFile('dtml/addDeviceClass',globals())
68
69
71 """
72 DeviceClass is a device organizer that manages the primary classification
73 of device objects within the zenoss system. It manages properties
74 that are inherited through acquisition that modify the behavior of
75 many different sub systems within zenoss.
76 It also handles the creation of new devices in the system.
77 """
78
79
80 dmdRootName = "Devices"
81
82 manageDeviceSearch = DTMLFile('dtml/manageDeviceSearch',globals())
83 manageDeviceSearchResults = DTMLFile('dtml/manageDeviceSearchResults',
84 globals())
85
86 portal_type = meta_type = event_key = "DeviceClass"
87
88
89
90
91
92
93 default_catalog = 'deviceSearch'
94
95 _relations = DeviceOrganizer._relations + ZenPackable._relations + (
96 ("devices", ToManyCont(ToOne,"Products.ZenModel.Device","deviceClass")),
97 ("rrdTemplates", ToManyCont(ToOne,"Products.ZenModel.RRDTemplate","deviceClass")),
98 )
99
100
101 factory_type_information = (
102 {
103 'id' : 'DeviceClass',
104 'meta_type' : 'DeviceClass',
105 'description' : """Base class for all devices""",
106 'icon' : 'DeviceClass_icon.gif',
107 'product' : 'ZenModel',
108 'factory' : 'manage_addDeviceClass',
109 'immediate_view' : 'deviceOrganizerStatus',
110 'actions' :
111 (
112 { 'name' : 'Classes'
113 , 'action' : 'deviceOrganizerStatus'
114 , 'permissions' : ( permissions.view, )
115 },
116 { 'name' : 'Events'
117 , 'action' : 'viewEvents'
118 , 'permissions' : ( permissions.view, )
119 },
120 { 'name' : 'History'
121 , 'action' : 'viewHistoryEvents'
122 , 'permissions' : ( permissions.view, )
123 },
124 { 'name' : 'zProperties'
125 , 'action' : 'zPropertyEdit'
126 , 'permissions' : (permissions.view,)
127 },
128 { 'name' : 'Templates'
129 , 'action' : 'perfConfig'
130 , 'permissions' : ('Manage DMD',)
131 },
132 )
133 },
134 )
135
136 security = ClassSecurityInfo()
137
151 deviceMoveTargets = getPeerDeviceClassNames
152 childMoveTargets = getPeerDeviceClassNames
153
154
156 """
157 Create an instance based on its location in the device tree
158 walk up the primary aq path looking for a python instance class that
159 matches the name of the closest node in the device tree.
160 """
161 dev = self.findDevice(id)
162 if dev: return dev
163 pyClass = self.getPythonDeviceClass()
164 dev = pyClass(id)
165 self.devices._setObject(id, dev)
166 return self.devices._getOb(id)
167
168
170 """
171 Return the python class object to be used for device instances in this
172 device class. This is done by walking up the aq_chain of a deviceclass
173 to find a node that has the same name as a python class or has an
174 attribute named zPythonClass that matches a python class.
175 """
176 import sys
177 from Device import Device
178 cname = getattr(self, "zPythonClass", None)
179 if cname:
180 try:
181 return importClass(cname)
182 except ImportError:
183 log.exception("Unable to import class " + cname)
184 return Device
185
186
210
211
225
226
227 security.declareProtected('Change Device', 'setDeviceBatchProps')
228 - def setDeviceBatchProps(self, method='', extraarg=None,
229 selectstatus='none', goodevids=[],
230 badevids=[], offset=0, count=50, filter='',
231 orderby='id', orderdir='asc', REQUEST=None):
232 """docstring"""
233 if not method: return self()
234 d = {'lockDevicesFromUpdates':'sendEventWhenBlocked',
235 'lockDevicesFromDeletion':'sendEventWhenBlocked',
236 'unlockDevices':'',
237 'setGroups':'groupPaths',
238 'setSystems':'systemPaths',
239 'setLocation':'locationPath',
240 'setPerformanceMonitor':'performanceMonitor',
241 'setStatusMonitors':'statusMonitors',
242 'moveDevices':'moveTarget',
243 'removeDevices':'',
244 'setProdState':'state',
245 'setPriority':'priority'
246 }
247 request = FakeRequest()
248 argdict = dict(REQUEST=request)
249 if d[method]: argdict[d[method]] = extraarg
250 action = getattr(self, method)
251 argdict['deviceNames'] = self.getDeviceBatch(selectstatus,
252 goodevids, badevids, offset, count,
253 filter, orderby, orderdir)
254 return action(**argdict)
255
256
257 security.declareProtected('View', 'getEventDeviceInfo')
272
273
274 security.declareProtected('View', 'getDeviceWinInfo')
276 """Return list of (devname,user,passwd,url) for each device.
277 user and passwd are used to connect via wmi.
278 """
279 ffunc = None
280 starttime = time.time()
281 if lastPoll > 0:
282 lastPoll = DateTime.DateTime(lastPoll)
283 ffunc = lambda x: x.getSnmpLastCollection() > lastPoll
284 if eventlog:
285 ffunc = lambda x: x.zWinEventlog
286 devinfo = []
287 for dev in self.getSubDevices(devfilter=ffunc):
288 if not dev.monitorDevice(): continue
289 if getattr(dev, 'zWmiMonitorIgnore', False): continue
290 user = getattr(dev,'zWinUser','')
291 passwd = getattr(dev, 'zWinPassword', '')
292 sev = getattr(dev, 'zWinEventlogMinSeverity', '')
293 devinfo.append((dev.id, str(user), str(passwd), sev, dev.absolute_url()))
294 return starttime, devinfo
295
296
298 """Return a list of (devname, user, passwd, {'EvtSys':0,'Exchange':0})
299 """
300 svcinfo = []
301 allsvcs = {}
302 for s in self.getSubComponents("WinService"):
303 svcs=allsvcs.setdefault(s.hostname(),{})
304 name = s.name()
305 if type(name) == type(u''):
306 name = name.encode(s.zCollectorDecoding)
307 svcs[name] = (s.getStatus(), s.getAqProperty('zFailSeverity'))
308 for dev in self.getSubDevices():
309 if not dev.monitorDevice(): continue
310 if getattr(dev, 'zWmiMonitorIgnore', False): continue
311 svcs = allsvcs.get(dev.getId(), {})
312 if not svcs and not dev.zWinEventlog: continue
313 user = getattr(dev,'zWinUser','')
314 passwd = getattr(dev, 'zWinPassword', '')
315 svcinfo.append((dev.id, str(user), str(passwd), svcs))
316 return svcinfo
317
318
319 security.declareProtected('View', 'searchDeviceSummary')
321 """search device summary index and return device objects"""
322 if not query: return []
323 zcatalog = self._getCatalog()
324 if not zcatalog: return []
325 results = zcatalog({'summary':query})
326 return self._convertResultsToObj(results)
327
328
329 security.declareProtected('View', 'searchInterfaces')
331 """search interfaces index and return interface objects"""
332 if not query: return []
333 zcatalog = getattr(self, 'interfaceSearch', None)
334 if not zcatalog: return []
335 results = zcatalog(query)
336 return self._convertResultsToObj(results)
337
338
349
351 query = Or(MatchGlob('id', devicename), Eq('getDeviceIp', devicename))
352 return self._getCatalog().evalAdvancedQuery(query)
353
354
356 """look up a device and return its path"""
357 ret = self._findDevice(devicename)
358 if not ret: return ""
359 return ret[0].getPrimaryId
360
361
371
372
373 security.declareProtected('View', 'jsonGetDeviceNames')
375 ''' Return a list of all device names that match the filter.
376 '''
377 def cmpDevice(a, b):
378 return cmp(a.id, b.id)
379 if query:
380 devices = self.searchDevices(query)
381 else:
382 devices = self.getSubDevices()
383 devices.sort(cmpDevice)
384 return simplejson.dumps([d.id for d in devices])
385
386
387 security.declareProtected('View', 'jsonGetComponentPaths')
389 '''
390 Return a list of all components that match device in the form
391 (componentPath, componentName)
392 '''
393 from sets import Set
394 paths = Set()
395 if isinstance(deviceIds, basestring):
396 deviceIds = [deviceIds]
397 for devId in deviceIds:
398 d = self.findDevice(devId)
399 if d:
400 dPathLen = len(d.getPrimaryId()) + 1
401 for comp in d.getMonitoredComponents():
402 paths.add((comp.getPrimaryId()[dPathLen:], comp.name()))
403 paths = list(paths)
404 paths.sort(lambda x,y: cmp(x[0], y[0]))
405 return simplejson.dumps(paths)
406
407
408 security.declareProtected('View', 'jsonGetGraphIds')
410 ''' Get a list of the graph defs available for the given device
411 and component.
412 '''
413 from sets import Set
414 graphIds = Set()
415 if isinstance(deviceIds, basestring):
416 deviceIds = [deviceIds]
417 if isinstance(componentPaths, basestring):
418 componentPaths = [componentPaths]
419 if not componentPaths:
420 componentPaths = ('',)
421
422 for devId in deviceIds:
423 thing = self.findDevice(devId)
424 if thing:
425 for compPath in componentPaths:
426 compPath = compPath or ''
427 parts = compPath.split('/')
428 for part in parts:
429 if part:
430 if hasattr(thing, part):
431 thing = getattr(thing, part)
432 else:
433 break
434 else:
435 for t in thing.getRRDTemplates():
436 for g in t.getGraphDefs():
437 graphIds.add(g.id)
438 graphIds = list(graphIds)
439 graphIds.sort()
440 return simplejson.dumps(graphIds)
441
442
444 """look up device in catalog and return its pingStatus"""
445 dev = self.findDevice(devicename)
446 if dev: return dev.getPingStatusNumber()
447
448
450 """Return generator of components, by meta_type if specified.
451 """
452 zcat = getattr(self, "componentSearch")
453 res = zcat({'meta_type': meta_type, 'monitored': monitored})
454 for b in res:
455 try:
456 yield self.getObjByPath(b.getPrimaryId)
457 except KeyError:
458 log.warn("bad path '%s' in index 'componentSearch'",
459 b.getPrimaryId)
460
461
463 """Return monitored components for devices within this DeviceDeviceClass
464 """
465 return self.getSubComponents()
466
467
468 security.declareProtected('View', 'getImportFilesData')
470 """Get a list of XML filenames and basenames from the ZENHOME/import
471 directory.
472 """
473 path = zenPath('import')
474 filedata = []
475 for filename in glob(path+os.path.sep+'*.xml'):
476 basename = os.path.basename(filename)
477 filedata.append({
478 'filename': filename,
479 'display': basename})
480 filedata.sort()
481 return filedata
482
483
484 security.declareProtected('View', 'getRRDImportFilesData')
486 """Get a list of command-only import files' data.
487 """
488 return [ x for x in self.getImportFilesData() if 'RRD' in x['display'] ]
489
490
491 security.declareProtected('View', 'getRRDTemplates')
493 """Return the actual RRDTemplate instances.
494 """
495 templates = {}
496 if not context: context = self
497 mychain = aq_chain(context)
498 mychain.reverse()
499 for obj in mychain:
500 try:
501 templates.update(dict([(t.id, t) for t in obj.rrdTemplates()]))
502 except AttributeError:
503 pass
504 return templates.values()
505
506
508 "Returns all available templates"
509 def cmpTemplates(a, b):
510 return cmp(a.id.lower(), b.id.lower())
511 t = self.getRRDTemplates()
512 t.sort(cmpTemplates)
513 return t
514
515
517 "This will bind available templates to the zDeviceTemplates"
518 return self.setZenProperty('zDeviceTemplates', ids, REQUEST)
519
528
529
540
541
542 security.declareProtected('Add DMD Objects', 'manage_addRRDTemplate')
553
554
568
569
603
604
616
617
637
652
653 security.declareProtected('Add DMD Objects', 'manage_importRRDTemplates')
658
659
661 """make the catalog for device searching
662 """
663 from Products.ZCatalog.ZCatalog import manage_addZCatalog
664
665
666 manage_addZCatalog(self, self.default_catalog,
667 self.default_catalog)
668 zcat = self._getOb(self.default_catalog)
669 cat = zcat._catalog
670 for idxname in ['id',
671 'getDeviceIp','getDeviceClassPath','getProdState']:
672 cat.addIndex(idxname, makeCaseInsensitiveFieldIndex(idxname))
673 cat.addIndex('getPhysicalPath', makePathIndex('getPhysicalPath'))
674 zcat.addColumn('getPrimaryId')
675 zcat.addColumn('id')
676
677
678 manage_addZCatalog(self, "componentSearch", "componentSearch")
679 zcat = self._getOb("componentSearch")
680 cat = zcat._catalog
681 cat.addIndex('meta_type', makeCaseInsensitiveFieldIndex('meta_type'))
682 cat.addIndex('getParentDeviceName',
683 makeCaseInsensitiveFieldIndex('getParentDeviceName'))
684 cat.addIndex('getCollectors',
685 makeCaseInsensitiveKeywordIndex('getCollectors'))
686
687
688 zcat.addIndex('monitored', 'FieldIndex')
689 zcat.addColumn('getPrimaryId')
690 zcat.addColumn('meta_type')
691
692
703
704
706 devs = self.getDmdRoot("Devices")
707 if getattr(aq_base(devs), "zSnmpCommunities", False): return
708
709
710 devs._setProperty("zPythonClass", "")
711
712
713 devs._setProperty("zProdStateThreshold", 300, type="int")
714
715
716 devs._setProperty("zIfDescription", False, type="boolean")
717
718
719 devs._setProperty("zSnmpCommunities",["public", "private"],type="lines")
720 devs._setProperty("zSnmpCommunity", "public")
721 devs._setProperty("zSnmpPort", 161, type="int")
722 devs._setProperty("zSnmpVer", "v1")
723 devs._setProperty("zSnmpTries", 2, type="int")
724 devs._setProperty("zSnmpTimeout", 2.5, type="float")
725 devs._setProperty("zRouteMapCollectOnlyLocal", False, type="boolean")
726 devs._setProperty("zRouteMapCollectOnlyIndirect", False, type="boolean")
727 devs._setProperty("zInterfaceMapIgnoreTypes", "")
728 devs._setProperty("zInterfaceMapIgnoreNames", "")
729 devs._setProperty("zFileSystemMapIgnoreTypes", [], type="lines")
730 devs._setProperty("zFileSystemMapIgnoreNames", "")
731 devs._setProperty("zSysedgeDiskMapIgnoreNames", "")
732 devs._setProperty("zIpServiceMapMaxPort", 1024, type="int")
733 devs._setProperty("zDeviceTemplates", ["Device"], type="lines")
734 devs._setProperty("zLocalIpAddresses", "^127|^0\.0|^169\.254|^224")
735 devs._setProperty("zLocalInterfaceNames", "^lo|^vmnet")
736
737
738
739
740
741
742
743
744 devs._setProperty("zPingInterfaceName", "")
745 devs._setProperty("zPingInterfaceDescription", "")
746
747
748 devs._setProperty("zSnmpMonitorIgnore", False, type="boolean")
749 devs._setProperty("zPingMonitorIgnore", False, type="boolean")
750 devs._setProperty("zWmiMonitorIgnore", True, type="boolean")
751 devs._setProperty("zStatusConnectTimeout", 15.0, type="float")
752
753
754 devs._setProperty("zCollectorPlugins", [], type='lines')
755 devs._setProperty("zCollectorClientTimeout", 180, type="int")
756 devs._setProperty("zCollectorDecoding", 'latin-1')
757 devs._setProperty("zCommandUsername", "")
758 devs._setProperty("zCommandPassword", "")
759 devs._setProperty("zCommandProtocol", "ssh")
760 devs._setProperty("zCommandPort", 22, type="int")
761 devs._setProperty("zCommandLoginTries", 1, type="int")
762 devs._setProperty("zCommandLoginTimeout", 10.0, type="float")
763 devs._setProperty("zCommandCommandTimeout", 10.0, type="float")
764 devs._setProperty("zCommandSearchPath", [], type="lines")
765 devs._setProperty("zCommandExistanceTest", "test -f %s")
766 devs._setProperty("zCommandPath", "/opt/zenoss/libexec")
767 devs._setProperty("zTelnetLoginRegex", "ogin:.$")
768 devs._setProperty("zTelnetPasswordRegex", "assword:")
769 devs._setProperty("zTelnetSuccessRegexList",
770 ['\$.$', '\#.$'], type="lines")
771 devs._setProperty("zTelnetEnable", False, type="boolean")
772 devs._setProperty("zTelnetEnableRegex", "assword:")
773 devs._setProperty("zTelnetTermLength", True, type="boolean")
774 devs._setProperty("zTelnetPromptTimeout", 10.0, type="float")
775 devs._setProperty("zKeyPath", "~/.ssh/id_dsa")
776 devs._setProperty("zMaxOIDPerRequest", 40, type="int")
777
778
779 devs._setProperty("zLinks", "")
780
781
782
783
784
785
786 devs._setProperty("zWinUser", "")
787 devs._setProperty("zWinPassword", "")
788 devs._setProperty("zWinEventlogMinSeverity", 2, type="int")
789 devs._setProperty("zWinEventlog", False, type="boolean")
790
791
792 devs._setProperty("zIcon", "/zport/dmd/img/icons/noicon.png")
793
794
803
805 "This will result in a push of all the devices to live collectors"
806 self._p_changed = True
807 if REQUEST:
808 REQUEST['message'] = 'Changes to %s pushed to collectors' % self.id
809 return self.callZenScreen(REQUEST)
810
811
812 security.declareProtected('Change Device', 'setLastChange')
814 """Set the changed datetime for this device. value default is now.
815 """
816 if value is None:
817 value = time.time()
818 self._lastChange = float(value)
819
820
821
822 InitializeClass(DeviceClass)
823