1
2
3
4
5
6
7
8
9
10
11 __doc__ = """zenbatchdump
12
13 zenbatchdump dumps a list of devices to a file.
14 """
15
16 import sys
17 import re
18 from datetime import datetime
19 import platform
20 from collections import defaultdict
21
22 import Globals
23
24 from Products.ZenUtils.ZCmdBase import ZCmdBase
25 from Products.ZenModel.DeviceClass import DeviceClass
26 from Products.ZenModel.Device import Device
27 from Products.ZenModel.DeviceOrganizer import DeviceOrganizer
28
29
31 """
32 Base class
33 """
34
35 sample_configs = """#
36 # zenbatchdump run on host zenoss41 on date 2011-10-16 16:34:23.569920
37 # with --root=Devices/Server/Linux
38 # To load this Device dump file, use:
39 # zenbatchload <file>
40
41
42 '/Locations'
43 '/Locations/TestZenBatchDumper'
44 '/Locations/TestZenBatchDumper/City1'
45 '/Locations/TestZenBatchDumper/City1/Building1'
46 '/Locations/TestZenBatchDumper/City2'
47
48
49 '/Systems'
50 '/Systems/TestZenBatchDumper'
51 '/Systems/TestZenBatchDumper/System1'
52 '/Systems/TestZenBatchDumper/Scary/System2'
53 '/Systems/TestZenBatchDumper/Scary/System3'
54
55
56 '/Groups'
57 '/Groups/TestZenBatchDumper'
58 '/Groups/TestZenBatchDumper/Production'
59 '/Groups/TestZenBatchDumper/Production/Critical'
60 '/Groups/TestZenBatchDumper/Production/Secondary'
61 '/Groups/TestZenBatchDumper/TEST'
62 '/Groups/TestZenBatchDumper/DEV'
63
64 '/Devices/TestZenBatchDumper' zCollectorPlugins=['zenoss.snmp.NewDeviceMap', 'zenoss.snmp.DeviceMap', 'HPDeviceMap', 'DellDeviceMap', 'zenoss.snmp.InterfaceMap', 'zenoss.snmp.RouteMap', 'zenoss.snmp.IpServiceMap', 'zenoss.snmp.HRFileSystemMap', 'zenoss.snmp.HRSWInstalledMap', 'zenoss.snmp.HRSWRunMap', 'zenoss.snmp.CpuMap', 'HPCPUMap', 'DellCPUMap', 'DellPCIMap'], zIcon='/zport/dmd/img/icons/server.png'
65
66 '/Devices/TestZenBatchDumper/Server' zCollectorPlugins=['zenoss.snmp.NewDeviceMap', 'zenoss.snmp.DeviceMap', 'HPDeviceMap', 'DellDeviceMap', 'zenoss.snmp.InterfaceMap', 'zenoss.snmp.RouteMap', 'zenoss.snmp.IpServiceMap', 'zenoss.snmp.HRFileSystemMap', 'zenoss.snmp.HRSWInstalledMap', 'zenoss.snmp.HRSWRunMap', 'zenoss.snmp.CpuMap', 'HPCPUMap', 'DellCPUMap', 'DellPCIMap'], zIcon='/zport/dmd/img/icons/server.png'
67
68 '/Devices/TestZenBatchDumper/Server/Linux' zCollectorPlugins=['zenoss.snmp.NewDeviceMap', 'zenoss.snmp.DeviceMap', 'HPDeviceMap', 'DellDeviceMap', 'zenoss.snmp.InterfaceMap', 'zenoss.snmp.RouteMap', 'zenoss.snmp.IpServiceMap', 'zenoss.snmp.HRFileSystemMap', 'zenoss.snmp.HRSWRunMap', 'zenoss.snmp.CpuMap', 'HPCPUMap', 'DellCPUMap', 'DellPCIMap'], zHardDiskMapMatch='^[hs]d[a-z]\\d+$|c\\d+t\\d+d\\d+s\\d+$|^cciss\\/c\\dd\\dp\\d$|^dm\\-\\d$', zIcon='/zport/dmd/img/icons/server-linux.png', zIpServiceMapMaxPort=8090
69
70 'localhost' setHWProductKey=('.1.3.6.1.4.1.8072.3.2.10', 'net snmp'), setHWSerialNumber='', setHWTag='', setLastChange=DateTime('2011/10/16 09:07:53.208444 GMT-7'), setManageIp='127.0.0.1', setOSProductKey='Linux 2.6.18-164.el5', setPriority=3, setProdState=1000, setPerformanceMonitor='localhost'
71
72 'thor' setLocation='/Locations/TestZenBatchDumper/City1', setSystems=['/Systems/TestZenBatchDumper/Scary/System2', '/Systems/TestZenBatchDumper/System1'], setGroups=['/Groups/TestZenBatchDumper/TEST', '/Groups/TestZenBatchDumper/DEV'], setHWProductKey=('.1.3.6.1.4.1.8072.3.2.10', 'net snmp'), setHWSerialNumber='', setHWTag='', setLastChange=DateTime('2011/10/16 09:22:59.450108 GMT-7'), setManageIp='192.168.55.225', setOSProductKey='Linux 2.6.32-25-server', setPriority=4, setProdState=1000, setPerformanceMonitor='localhost'
73
74 'loki' setLocation='/Locations/TestZenBatchDumper/City2', setSystems=['/Systems/TestZenBatchDumper/System1'], setGroups=['/Groups/TestZenBatchDumper/Production/Critical'], setHWProductKey=('.1.3.6.1.4.1.8072.3.2.10', 'net snmp'), setHWSerialNumber='', setHWTag='', setLastChange=DateTime('2011/10/16 09:19:59.450108 GMT-7'), setManageIp='192.168.55.223', setOSProductKey='Linux 2.6.32-25-server', setPriority=4, setProdState=1000, setPerformanceMonitor='localhost'
75
76 '/Devices/TestZenBatchDumper/Server/Windows' zCollectorPlugins=['zenoss.snmp.NewDeviceMap', 'zenoss.snmp.DeviceMap', 'HPDeviceMap', 'DellDeviceMap', 'zenoss.snmp.InterfaceMap', 'zenoss.snmp.RouteMap', 'zenoss.snmp.IpServiceMap', 'zenoss.snmp.HRFileSystemMap', 'zenoss.snmp.HRSWInstalledMap', 'zenoss.snmp.HRSWRunMap', 'zenoss.snmp.CpuMap', 'HPCPUMap', 'DellCPUMap', 'DellPCIMap', 'zenoss.snmp.InformantHardDiskMap', 'zenoss.wmi.WinServiceMap'], zHardDiskMapMatch='.*', zIcon='/zport/dmd/img/icons/server-windows.png', zWinEventlog=True, zWmiMonitorIgnore=False
77
78 '/Devices/TestZenBatchDumper/Server/Windows/WMI' zCollectorPlugins=['zenoss.wmi.WindowsDeviceMap', 'zenoss.wmi.WinServiceMap', 'zenoss.wmi.CpuMap', 'zenoss.wmi.FileSystemMap', 'zenoss.wmi.IpInterfaceMap', 'zenoss.wmi.IpRouteMap', 'zenoss.wmi.MemoryMap', 'zenoss.wmi.ProcessMap', 'zenoss.wmi.SoftwareMap'], zDeviceTemplates=['Device_WMI'], zWinPerfCycleSeconds=300, zWinPerfCyclesPerConnection=10
79
80 '192.168.5.219' zWinPassword='easyPassword', zWinUser='admin', setLocation='/Locations/TestZenBatchDumper/City1/Building1', setGroups=['/Groups/TestZenBatchDumper/Production/Secondary'], setHWProductKey=('Unknown', 'Chassis Manufacture'), setHWSerialNumber='Chassis Serial Number', setHWTag='Asset-1234567890', setLastChange=DateTime('2011/10/16 09:19:56.920976 GMT-7'), setManageIp='192.168.55.229', setOSProductKey=('Windows 7 Home Premium ', 'Microsoft'), setPriority=3, setProdState=1000, setPerformanceMonitor='localhost'
81
82
83 # Dumped:
84 # Locations: 5
85 # Groups: 7
86 # Systems: 5
87 # DeviceClasses: 5
88 # Devices: 4
89 """
90
92 ZCmdBase.__init__(self, *args, **kwargs)
93 self.defaults = {}
94 self.emittedDeviceClasses = set()
95
97 """
98 initializes and verify the device root and prune options properly
99
100 @return: was initialization successful
101 @rtype: bool
102 """
103
104 if self.options.root == "":
105 self.root = self.dmd.Devices
106 self.options.prune = False
107 else:
108 try:
109 self.root = self.dmd.unrestrictedTraverse(self.options.root)
110 except KeyError:
111 self.log.error("%s is not a valid DeviceOrganizer path under %s\n" % (self.options.root, self.dmd.getPrimaryUrlPath()))
112 return False
113
114 self.rootPath = self.root.getPrimaryUrlPath()
115 return True
116
118 """
119 Returns string of object local zProperties, cProperties and "setter" properties suitable for ZenBatchLoader
120
121 @parameter obj: a Device or DeviceClass (or perhaps Location later)
122 @type obj: ZenModelRM
123 @return: string containing local zProperties as documented in above sample
124 @rtype str
125 """
126 props = []
127
128 desc = getattr(obj,"description","")
129 if desc:
130 props.append("%s=%s" % ('description',repr(desc)))
131 for prop in ((x['id'], repr(x['value'])) for x in obj.exportZProperties() if x['islocal']):
132 key = prop[0]
133 if obj.zenPropIsPassword(key):
134 val = repr(getattr(obj, key, ''))
135 prop = (key, val)
136 props.append("%s=%s" % prop)
137
138 for cProp in obj.custPropertyMap():
139 if cProp['id'] == 'cDateTest': continue
140 value = getattr(obj,cProp['id'],'')
141 if value and value != '':
142 props.append("%s=%s" % (cProp['id'], repr(value)))
143
144
145 ignoreSetters = ('setLastPollSnmpUpTime', 'setSnmpLastCollection', 'setSiteManager', 'setLocation', 'setGroups', 'setSystems')
146 for setMethod in [setter for setter in dir(obj) if setter.startswith('set')]:
147 if setMethod in ignoreSetters:
148 continue
149 getMethod = setMethod.replace('set', 'get', 1)
150 getter = getattr(obj, getMethod, None)
151 if getter and callable(getter):
152
153 if setMethod == 'setProdState':
154 states = obj.getProdStateConversions()
155 for state in states:
156 if getter() in state:
157 value = state[1]
158 else:
159 value = getter()
160 if value and value != '':
161 props.append("%s=%s" % (setMethod, repr(value)))
162 else:
163
164 value = getattr(obj, setMethod[3:].lower(), None)
165 if value and value != '':
166 props.append("%s=%s" % (setMethod, repr(value)))
167
168
169 if ('getPerformanceServerName' in dir(obj)):
170 props.append("setPerformanceMonitor=" + repr(obj.getPerformanceServerName()))
171 return props
172
174 """
175 Returns a device and its zProperties in strings appropriate for ZenBatchLoader
176
177 @parameter dev: Device object to emit
178 @type dev: Device
179 @return: strings containing device name and list of Device-local zProperties and cProperties
180 @rtype: tuple of strings
181 """
182
183 result = self._emitProps(dev)
184 location = dev.location()
185 if location:
186 result.append("setLocation=" + repr("/".join(location.getPrimaryPath()[4:])))
187
188 systems = dev.systems()
189 if systems:
190 result.append("setSystems=" + repr(["/"+"/".join(system.getPrimaryPath()[4:]) for system in systems]))
191
192 groups = dev.groups()
193 if groups:
194 result.append("setGroups=" + repr(["/"+"/".join(grp.getPrimaryPath()[4:]) for grp in groups]))
195
196 return (repr(dev.getId()),result)
197
199 """
200 Returns a device organizer with its type and local properties
201
202 @parameter org: DeviceOrganizer to emit
203 @type org: DeviceOrganizer
204 @return: strings containing the device organizer name, type and properties
205 @rtype: tuple of strings
206 """
207
208 path = org.getPrimaryPath()
209 name = "'/%s' " % "/".join(path[3:])
210
211 props = [] if isinstance(org, DeviceClass) and 'ZenPacks' in org.zPythonClass else self._emitProps(org)
212
213 if '/Locations/' in path:
214 props.append('setAddress="%s"' % org.address)
215
216 return (name, props)
217
219 """
220 Recurse upward from a device emitting parent DeviceClasses if not already emitted
221
222 @parameter outFile: file object to which output is written
223 @type outFile: file or other object with .write() method that is simillar
224 @parameter dev: Device/DeviceClass for whom we emit parent Organizer paths
225 @type dev: Device or DeviceClass
226 @return: number of DeviceClasses emitted
227 @rtype: int
228 """
229
230 result = 0
231 if isinstance(obj, Device):
232
233 obj = obj.getPrimaryParent().getPrimaryParent()
234 if not obj in self.emittedDeviceClasses:
235 parent = obj.getPrimaryParent()
236
237 if parent.getPrimaryPath()[2:] != self.dmd.getPrimaryPath()[2:]:
238 result = self._backtraceOrg(outFile, parent)
239 (name, props) = self._emitOrg(obj);
240 outFile.write("\n%s %s\n" % (name, ", ".join(props)))
241 self.emittedDeviceClasses.add(obj)
242 result += 1
243 return result
244
246 """
247 Recurse through the Locations, Systems and Groups trees printing out Organizers with properties
248 return number of Devices emitted
249
250 @parameter outFile: output object to which we write output
251 @type outFile: file or other object with .write() method that is simillar
252 @parameter branch: object reference to current tree branch (only used for recursion, should be called with None)
253 @type branch: DeviceOrganizer
254 @return: number of Locations, Systems or Groups dumped
255 @rtype: int
256 """
257 if getattr(self.options,'rootPath',None) is None:
258
259
260 if not self._prepRoot():
261 return -1;
262
263 result = 0
264
265 if not isinstance(branch, DeviceOrganizer):
266 raise TypeError("listLSGOTree must start in a DeviceOrganizer not (%s)") % branch
267
268
269
270 if getattr(self.options, 'pruneLSGO', None) and not isinstance(self.root, DeviceClass) and \
271 not (branch.getPrimaryUrlPath().startswith(self.rootPath) or \
272 self.root.getPrimaryUrlPath().startswith(branch.getPrimaryUrlPath())):
273 return result
274
275 outFile.write("\n")
276 (name, props) = self._emitOrg(branch)
277 result += 1
278 outFile.write("\n%s %s\n" % (name, ", ".join(props)))
279
280 for org in branch.children():
281 result += self.listLSGOTree(outFile, org)
282 return result
283
287
289 for dev in root.getDevices():
290
291
292 dev = self.dmd.unrestrictedTraverse(dev.getPrimaryPath())
293 if not dev in self.root.getSubDevices():
294 continue
295 if 'ZenPack' in dev.zPythonClass:
296 continue
297 if matcher:
298 if matcher(dev):
299 yield dev
300 else:
301 yield dev
302
304 """
305 Recurse through the Devices tree printing out Organizers and Devices with properties
306 return number of Devices emitted
307
308 @parameter outFile: output object to which we write output
309 @type outFile: file or other object with .write() method that is simillar
310 @parameter branch: object reference to current tree branch (only used for recursion, should be called with None)
311 @type branch: DeviceClass (or perhaps DeviceOrganizer at worst)
312 @return: number of leaf Devices and DeviceClasses dumped
313 @rtype: dict
314 """
315 if getattr(self.options,'rootPath',None) is None:
316
317
318 if not self._prepRoot():
319 return { 'fail' : True }
320
321 if branch is None:
322 branch = self.dmd.Devices
323
324 if not isinstance(branch, DeviceClass):
325 raise TypeError("listDeviceTree must start in a DeviceClass not " + repr(branch))
326
327 result = defaultdict(int)
328
329
330 if not self.options.prune or branch.getPrimaryUrlPath() in self.rootPath:
331 outFile.write("\n")
332 (name, props) = self._emitOrg(branch)
333 result['DeviceClasses'] += 1
334 outFile.write("\n%s %s\n" % (name, ", ".join(props)))
335 self.emittedDeviceClasses.add(branch)
336
337
338 for dev in self.chooseDevice(branch,self.makeRegexMatcher()):
339 (name,props) = self._emitDev(dev)
340
341 result['DeviceClasses'] += self._backtraceOrg(outFile, dev)
342 outFile.write("\n%s %s\n" % (name, ", ".join(props)))
343 result['Devices'] += 1
344
345
346 for org in branch.children():
347 found = self.listDeviceTree(outFile, org)
348 result['Devices'] += found['Devices']
349 result['DeviceClasses'] += found['DeviceClasses']
350 return result
351
353 """
354 Add our command-line options to the basics
355 """
356 ZCmdBase.buildOptions(self)
357
358 self.parser.add_option('--root',
359 dest = "root", default = "",
360 help = "Set the root Device Path to dump (eg: /Devices/Servers or /Devices/Network/Cisco/Nexus; default: /Devices)")
361
362 self.parser.add_option('--outFile',
363 dest = 'outFile', default = sys.__stdout__,
364 help = "Specify file to which zenbatchdump will write output")
365
366 self.parser.add_option('--regex',
367 dest = 'regex', default = '.*',
368 help = "Specify include filter for device objects")
369
370 self.parser.add_option('--prune',
371 dest = 'prune', default = False,
372 action = 'store_true',
373 help = "Should DeviceClasses only be dumped if part of root path")
374
376 """
377 Run the batch device dump
378 """
379
380 if isinstance(self.options.outFile, str):
381 try:
382 outFile = open(self.options.outFile, "w")
383 except IOError as e:
384 self.log.error("Cannot open file %s for writing: %s" % (self.options.outFile,e))
385 sys.exit(1)
386 else:
387 outFile = self.options.outFile
388 self.options.outFile = outFile.name
389
390
391 if self.options.root:
392 if self.options.root[0] == '/':
393 self.options.root = self.options.root[1:]
394 if not self._prepRoot():
395 outFile.close()
396 sys.exit(2)
397
398 self.printHeader(outFile)
399 foundLSGO = {}
400 foundLSGO['Locations'] = self.listLSGOTree(outFile, self.dmd.Locations)
401 foundLSGO['Systems'] = self.listLSGOTree(outFile, self.dmd.Systems)
402 foundLSGO['Groups'] = self.listLSGOTree(outFile, self.dmd.Groups)
403 foundDevices = self.listDeviceTree(outFile)
404 self.printTrailer(outFile, foundLSGO, foundDevices)
405 outFile.close()
406
408 curDate = datetime.now()
409 hostname = platform.node()
410 outFile.write("# zenbatchdump run on host %s on date %s\n" % (hostname,str(curDate)))
411 outFile.write("# with --root=%s\n" % self.options.root)
412 outFile.write("# To load this Device dump file, use:\n")
413 outFile.write("# zenbatchload <file>\n")
414
416 outFile.write("\n# Dumped:\n")
417 for type in foundLSGO:
418 outFile.write("# %13s: %d\n" % (type, foundLSGO[type]))
419 for type in foundDevices:
420 outFile.write("# %13s: %d\n" % (type, foundDevices[type]))
421
422
423 if __name__=='__main__':
424 batchDumper = BatchDeviceDumper()
425 batchDumper.run()
426