| Trees | Indices | Help |
|
|---|
|
|
1 #! /usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # ##########################################################################
4 #
5 # This program is part of Zenoss Core, an open source monitoring platform.
6 # Copyright (C) 2006-2009 Zenoss Inc.
7 #
8 # This program is free software; you can redistribute it and/or modify it
9 # under the terms of the GNU General Public License version 2 as published by
10 # the Free Software Foundation.
11 #
12 # For complete information please visit: http://www.zenoss.com/oss/
13 #
14 # ##########################################################################
15
16 __doc__ = """PerformanceConf
17 The configuration object for Performance servers
18 """
19
20 import os
21 import zlib
22 import socket
23 import logging
24 log = logging.getLogger('zen.PerformanceConf')
25
26 try:
27 from base64 import urlsafe_b64encode
28 raise ImportError
29 except ImportError:
30
31
33 """
34 Encode a string so that it's okay to be used in an URL
35
36 @param s: possibly unsafe string passed in by the user
37 @type s: string
38 @return: sanitized, url-safe version of the string
39 @rtype: string
40 """
41
42 import base64
43 s = base64.encodestring(s)
44 s = s.replace('+', '-')
45 s = s.replace('/', '_')
46 s = s.replace('\n', '')
47 return s
48
49
50 import xmlrpclib
51
52 from AccessControl import ClassSecurityInfo
53 from AccessControl import Permissions as permissions
54 from Globals import DTMLFile
55 from Globals import InitializeClass
56 from Monitor import Monitor
57 from Products.PythonScripts.standard import url_quote
58 from Products.ZenModel.ZenossSecurity import *
59 from Products.ZenRelations.RelSchema import *
60 from Products.ZenUtils.Utils import basicAuthUrl, zenPath, binPath
61 from Products.ZenUtils.Utils import unused
62 from Products.ZenUtils.Utils import isXmlRpc
63 from Products.ZenUtils.Utils import setupLoggingHeader
64 from Products.ZenUtils.Utils import executeCommand
65 from Products.ZenUtils.Utils import clearWebLoggingStream
66 from Products.ZenModel.Device import manage_createDevice
67 from Products.ZenWidgets import messaging
68 from StatusColor import StatusColor
69
70 PERF_ROOT = None
71
72
74 """
75 Return the base directory where RRD performance files are kept.
76
77 @param target: path to performance file
78 @type target: string
79 @return: sanitized path to performance file
80 @rtype: string
81 """
82 global PERF_ROOT
83 if PERF_ROOT is None:
84 PERF_ROOT = zenPath('perf')
85 if target.startswith('/'):
86 target = target[1:]
87 return os.path.join(PERF_ROOT, target)
88
89
91 """
92 Make a device class
93
94 @param context: Where you are in the Zope acquisition path
95 @type context: Zope context object
96 @param id: unique identifier
97 @type id: string
98 @param title: user readable label (unused)
99 @type title: string
100 @param REQUEST: Zope REQUEST object
101 @type REQUEST: Zope REQUEST object
102 @return:
103 @rtype:
104 """
105 unused(title)
106 dc = PerformanceConf(id)
107 context._setObject(id, dc)
108
109 if REQUEST is not None:
110 REQUEST['RESPONSE'].redirect(context.absolute_url()
111 + '/manage_main')
112
113
114 addPerformanceConf = DTMLFile('dtml/addPerformanceConf', globals())
115
116
118 """
119 Configuration for Performance servers
120 """
121 portal_type = meta_type = 'PerformanceConf'
122
123 monitorRootName = 'Performance'
124
125 security = ClassSecurityInfo()
126 security.setDefaultAccess('allow')
127
128 eventlogCycleInterval = 60
129 perfsnmpCycleInterval = 300
130 processCycleInterval = 180
131 statusCycleInterval = 60
132 winCycleInterval = 60
133 winmodelerCycleInterval = 60
134 wmibatchSize = 10
135 wmiqueryTimeout = 100
136 configCycleInterval = 6 * 60
137
138 zenProcessParallelJobs = 10
139
140 pingTimeOut = 1.5
141 pingTries = 2
142 pingChunk = 75
143 pingCycleInterval = 60
144 maxPingFailures = 1440
145
146 modelerCycleInterval = 720
147
148 renderurl = '/zport/RenderServer'
149 renderuser = ''
150 renderpass = ''
151
152 discoveryNetworks = ()
153
154 # make the default rrdfile size smaller
155 # we need the space to live within the disk cache
156 defaultRRDCreateCommand = (
157 'RRA:AVERAGE:0.5:1:600', # every 5 mins for 2 days
158 'RRA:AVERAGE:0.5:6:600', # every 30 mins for 12 days
159 'RRA:AVERAGE:0.5:24:600', # every 2 hours for 50 days
160 'RRA:AVERAGE:0.5:288:600', # every day for 600 days
161 'RRA:MAX:0.5:6:600',
162 'RRA:MAX:0.5:24:600',
163 'RRA:MAX:0.5:288:600',
164 )
165
166 _properties = (
167 {'id': 'eventlogCycleInterval', 'type': 'int', 'mode': 'w'},
168 {'id': 'perfsnmpCycleInterval', 'type': 'int', 'mode': 'w'},
169 {'id': 'processCycleInterval', 'type': 'int', 'mode': 'w'},
170 {'id': 'statusCycleInterval', 'type': 'int', 'mode': 'w'},
171 {'id': 'winCycleInterval', 'type': 'int', 'mode': 'w'},
172 {'id': 'winmodelerCycleInterval', 'type': 'int', 'mode': 'w'},
173 {'id': 'wmibatchSize', 'type': 'int', 'mode': 'w',
174 'description':"Number of data objects to retrieve in a single WMI query",},
175 {'id': 'wmiqueryTimeout', 'type': 'int', 'mode': 'w',
176 'description':"Number of milliseconds to wait for WMI query to respond",},
177 {'id': 'configCycleInterval', 'type': 'int', 'mode': 'w'},
178 {'id': 'renderurl', 'type': 'string', 'mode': 'w'},
179 {'id': 'renderuser', 'type': 'string', 'mode': 'w'},
180 {'id': 'renderpass', 'type': 'string', 'mode': 'w'},
181 {'id': 'defaultRRDCreateCommand', 'type': 'lines', 'mode': 'w'
182 },
183 {'id': 'zenProcessParallelJobs', 'type': 'int', 'mode': 'w'},
184 {'id': 'pingTimeOut', 'type': 'float', 'mode': 'w'},
185 {'id': 'pingTries', 'type': 'int', 'mode': 'w'},
186 {'id': 'pingChunk', 'type': 'int', 'mode': 'w'},
187 {'id': 'pingCycleInterval', 'type': 'int', 'mode': 'w'},
188 {'id': 'maxPingFailures', 'type': 'int', 'mode': 'w'},
189 {'id': 'modelerCycleInterval', 'type': 'int', 'mode': 'w'},
190 {'id': 'discoveryNetworks', 'type': 'lines', 'mode': 'w'},
191 )
192
193 _relations = Monitor._relations + (
194 ("devices", ToMany(ToOne,"Products.ZenModel.Device","perfServer")),
195 )
196
197 # Screen action bindings (and tab definitions)
198 factory_type_information = (
199 {
200 'immediate_view' : 'viewPerformanceConfOverview',
201 'actions' :
202 (
203 { 'id' : 'overview'
204 , 'name' : 'Overview'
205 , 'action' : 'viewPerformanceConfOverview'
206 , 'permissions' : (
207 permissions.view, )
208 },
209 { 'id' : 'edit'
210 , 'name' : 'Edit'
211 , 'action' : 'editPerformanceConf'
212 , 'permissions' : ("Manage DMD",)
213 },
214 { 'id' : 'performance'
215 , 'name' : 'Performance'
216 , 'action' : 'viewDaemonPerformance'
217 , 'permissions' : (permissions.view,)
218 },
219 { 'id' : 'viewHistory'
220 , 'name' : 'Modifications'
221 , 'action' : 'viewHistory'
222 , 'permissions' : (ZEN_VIEW_MODIFICATIONS,)
223 },
224 )
225 },
226 )
227
228
229 security.declareProtected('View', 'getDefaultRRDCreateCommand')
231 """
232 Get the default RRD Create Command, as a string.
233 For example:
234 '''RRA:AVERAGE:0.5:1:600
235 RRA:AVERAGE:0.5:6:600
236 RRA:AVERAGE:0.5:24:600
237 RRA:AVERAGE:0.5:288:600
238 RRA:MAX:0.5:288:600'''
239
240 @return: RRD create command
241 @rtype: string
242 """
243 return '\n'.join(self.defaultRRDCreateCommand)
244
245
247 """
248 Return the object given the name
249
250 @param deviceName: Name of a device
251 @type deviceName: string
252 @return: device corresponding to the name, or None
253 @rtype: device object
254 """
255 brains = self.dmd.Devices._findDevice(deviceName)
256 if brains:
257 return brains[0].getObject()
258
259
261 """
262 Get the root of the Network object in the DMD
263
264 @return: base DMD Network object
265 @rtype: Network object
266 """
267 return self.dmd.Networks
268
269
271 """
272 Return an URL for the given graph options and date range
273
274 @param gopts: graph options
275 @type gopts: string
276 @param drange: time range to use
277 @type drange: string
278 @return: URL to a graphic
279 @rtype: string
280 """
281 newOpts = []
282 width = 0
283 for o in gopts:
284 if o.startswith('--width'):
285 width = o.split('=')[1].strip()
286 continue
287 newOpts.append(o)
288 encodedOpts = urlsafe_b64encode(
289 zlib.compress('|'.join(newOpts), 9))
290 url = '%s/render?gopts=%s&drange=%d&width=%s' % (
291 self.renderurl, encodedOpts, drange, width)
292 if self.renderurl.startswith('proxy'):
293 url = url.replace('proxy', 'http')
294 return '/zport/RenderServer/render?remoteUrl=%s&gopts=%s&drange=%d&width=%s' % (
295 url_quote(url), encodedOpts, drange, width)
296 else:
297 return url
298
299
301 """
302 Set the full path of the target and send to view
303
304 @param context: Where you are in the Zope acquisition path
305 @type context: Zope context object
306 @param targetpath: device path of performance metric
307 @type targetpath: string
308 @param targettype: unused
309 @type targettype: string
310 @param view: view object
311 @type view: Zope object
312 @param drange: date range
313 @type drange: string
314 @return: URL to graph
315 @rtype: string
316 """
317 unused(targettype)
318 targetpath = performancePath(targetpath)
319 gopts = view.getGraphCmds(context, targetpath)
320 return self.buildGraphUrlFromCommands(gopts, drange)
321
322
324 """
325 Set the full paths for all targts in map and send to view
326
327 @param context: Where you are in the Zope acquisition path
328 @type context: Zope context object
329 @param targetsmap: list of (target, targettype) tuples
330 @type targetsmap: list
331 @param view: view object
332 @type view: Zope object
333 @param drange: date range
334 @type drange: string
335 @return: URL to graph
336 @rtype: string
337 """
338 ntm = []
339 for (target, targettype) in targetsmap:
340 if target.find('.rrd') == -1:
341 target += '.rrd'
342 fulltarget = performancePath(target)
343 ntm.append((fulltarget, targettype))
344 gopts = view.multiGraphOpts(context, ntm)
345 gopts = url_quote('|'.join(gopts))
346 url = '%s/render?gopts=%s&drange=%d' % (self.renderurl, gopts, drange)
347 if self.renderurl.startswith('http'):
348 return '/zport/RenderServer/render?remoteUrl=%s&gopts=%s&drange=%d' % (
349 url_quote(url), gopts, drange)
350 else:
351 return url
352
353
355 """
356 Return the URL for a list of custom gopts for a graph
357
358 @param gopts: graph options
359 @type gopts: string
360 @param drange: date range
361 @type drange: string
362 @return: URL to graph
363 @rtype: string
364 """
365 gopts = self._fullPerformancePath(gopts)
366 gopts = url_quote('|'.join(gopts))
367 url = '%s/render?gopts=%s&drange=%d' % (self.renderurl, gopts,
368 drange)
369 if self.renderurl.startswith('http'):
370 return '/zport/RenderServer/render?remoteUrl=%s&gopts=%s&drange=%d'\
371 % (url_quote(url), gopts, drange)
372 else:
373 return url
374
375
377 """
378 Fill out full path for custom gopts and call to server
379
380 @param gopts: graph options
381 @type gopts: string
382 @return: URL
383 @rtype: string
384 """
385 gopts = self._fullPerformancePath(gopts)
386 renderurl = str(self.renderurl)
387 if renderurl.startswith('proxy'):
388 renderurl = self.renderurl.replace('proxy', 'http')
389 if renderurl.startswith('http'):
390 url = basicAuthUrl(str(self.renderuser),
391 str(self.renderpass), renderurl)
392 server = xmlrpclib.Server(url)
393 else:
394 server = self.getObjByPath(renderurl)
395 return server.summary(gopts)
396
397
399 """
400 Return values
401
402 @param paths: paths to performance metrics
403 @type paths: list
404 @param cf: RRD CF
405 @type cf: string
406 @param resolution: resolution
407 @type resolution: string
408 @param start: start time
409 @type start: string
410 @param end: end time
411 @type end: string
412 @return: values
413 @rtype: list
414 """
415 url = self.renderurl
416 if url.startswith("http"):
417 url = basicAuthUrl(self.renderuser, self.renderpass, self.renderurl)
418 server = xmlrpclib.Server(url, allow_none=True)
419 else:
420 if not self.renderurl:
421 raise KeyError
422 server = self.getObjByPath(self.renderurl)
423 return server.fetchValues(map(performancePath, paths), cf,
424 resolution, start, end)
425
426
428 """
429 Fill out full path and call to server
430
431 @param paths: paths to performance metrics
432 @type paths: list
433 @return: values
434 @rtype: list
435 """
436 url = self.renderurl
437 if url.startswith('proxy'):
438 url = self.renderurl.replace('proxy', 'http')
439 if url.startswith('http'):
440 url = basicAuthUrl(self.renderuser, self.renderpass,
441 self.renderurl)
442 server = xmlrpclib.Server(url)
443 else:
444 if not self.renderurl:
445 raise KeyError
446 server = self.getObjByPath(self.renderurl)
447 return server.currentValues(map(performancePath, paths))
448
449
451 """
452 Add full path to a list of custom graph options
453
454 @param gopts: graph options
455 @type gopts: string
456 @return: full path + graph options
457 @rtype: string
458 """
459 for i in range(len(gopts)):
460 opt = gopts[i]
461 if opt.find('DEF') == 0:
462 opt = opt.split(':')
463 (var, file) = opt[1].split('=')
464 file = performancePath(file)
465 opt[1] = '%s=%s' % (var, file)
466 opt = ':'.join(opt)
467 gopts[i] = opt
468 return gopts
469
470
471 security.declareProtected('View', 'performanceDeviceList')
473 """
474 Return a list of URLs that point to our managed devices
475
476 @param force: unused
477 @type force: boolean
478 @return: list of device objects
479 @rtype: list
480 """
481 unused(force)
482 devlist = []
483 for dev in self.devices():
484 dev = dev.primaryAq()
485 if not dev.pastSnmpMaxFailures() and dev.monitorDevice():
486 devlist.append(dev.getPrimaryUrlPath(full=True))
487 return devlist
488
489
490 security.declareProtected('View', 'performanceDataSources')
492 """
493 Return a string that has all the definitions for the performance DS's.
494
495 @return: list of Data Sources
496 @rtype: string
497 """
498 dses = []
499 oidtmpl = 'OID %s %s'
500 dstmpl = """datasource %s
501 rrd-ds-type = %s
502 ds-source = snmp://%%snmp%%/%s%s
503 """
504 rrdconfig = self.getDmdRoot('Devices').rrdconfig
505 for ds in rrdconfig.objectValues(spec='RRDDataSource'):
506 if ds.isrow:
507 inst = '.%inst%'
508 else:
509 inst = ''
510 dses.append(oidtmpl % (ds.getName(), ds.oid))
511 dses.append(dstmpl % (ds.getName(), ds.rrdtype,
512 ds.getName(), inst))
513 return '\n'.join(dses)
514
516 """
517 Remove RRD performance data files
518
519 @param device: Name of a device or entry in DMD
520 @type device: string
521 @param datasource: datasource name
522 @type datasource: string
523 @param datapoint: datapoint name
524 @type datapoint: string
525 """
526 remoteUrl = None
527 if self.renderurl.startswith('http'):
528 if datapoint:
529 remoteUrl = '%s/deleteRRDFiles?device=%s&datapoint=%s' % (
530 self.renderurl, device, datapoint)
531 elif datasource:
532 remoteUrl = '%s/deleteRRDFiles?device=%s&datasource=%s' % (
533 self.renderurl, device, datasource)
534 else:
535 remoteUrl = '%s/deleteRRDFiles?device=%s' % (
536 self.renderurl, device)
537 rs = self.getDmd().getParentNode().RenderServer
538 rs.deleteRRDFiles(device, datasource, datapoint, remoteUrl)
539
540
542 """
543 Provide a method to set performance monitor from any organizer
544
545 @param performanceMonitor: DMD object that collects from a device
546 @type performanceMonitor: DMD object
547 @param deviceNames: list of device names
548 @type deviceNames: list
549 @param REQUEST: Zope REQUEST object
550 @type REQUEST: Zope REQUEST object
551 """
552 if not performanceMonitor:
553 if REQUEST:
554 messaging.IMessageSender(self).sendToBrowser('Error',
555 'No monitor was selected.',
556 priority=messaging.WARNING)
557 return self.callZenScreen(REQUEST)
558 if deviceNames is None:
559 if REQUEST:
560 messaging.IMessageSender(self).sendToBrowser('Error',
561 'No devices were selected.',
562 priority=messaging.WARNING)
563 return self.callZenScreen(REQUEST)
564 for devName in deviceNames:
565 dev = self.devices._getOb(devName)
566 dev = dev.primaryAq()
567 dev.setPerformanceMonitor(performanceMonitor)
568 if REQUEST:
569 messaging.IMessageSender(self).sendToBrowser('Monitor Set',
570 'Performance monitor was set to %s.'
571 % performanceMonitor)
572 if REQUEST.has_key('oneKeyValueSoInstanceIsntEmptyAndEvalToFalse'):
573 return REQUEST['message']
574 else:
575 return self.callZenScreen(REQUEST)
576
577
578 security.declareProtected('View', 'getPingDevices')
580 """
581 Return devices associated with this monitor configuration.
582
583 @return: list of devices for this monitor
584 @rtype: list
585 """
586 devices = []
587 for dev in self.devices.objectValuesAll():
588 dev = dev.primaryAq()
589 if dev.monitorDevice() and not dev.zPingMonitorIgnore:
590 devices.append(dev)
591 return devices
592
593 - def _executeZenDiscCommand(self, deviceName, devicePath= "/Discovered",
594 performanceMonitor="localhost", discoverProto="snmp",
595 zSnmpPort=161,zSnmpCommunity="", REQUEST=None):
596 """
597 Execute zendisc on the new device and return result
598
599 @param deviceName: Name of a device
600 @type deviceName: string
601 @param devicePath: DMD path to create the new device in
602 @type devicePath: string
603 @param performanceMonitor: DMD object that collects from a device
604 @type performanceMonitor: DMD object
605 @param discoverProto: auto or none
606 @type discoverProto: string
607 @param zSnmpPort: zSnmpPort
608 @type zSnmpPort: string
609 @param zSnmpCommunity: SNMP community string
610 @type zSnmpCommunity: string
611 @param REQUEST: Zope REQUEST object
612 @type REQUEST: Zope REQUEST object
613 @return:
614 @rtype:
615 """
616 zm = binPath('zendisc')
617 zendiscCmd = [zm]
618 zendiscOptions = ['run', '--now','-d', deviceName,
619 '--monitor', performanceMonitor,
620 '--deviceclass', devicePath]
621 if REQUEST:
622 zendiscOptions.append("--weblog")
623 zendiscCmd.extend(zendiscOptions)
624 result = executeCommand(zendiscCmd, REQUEST)
625 return result
626
628 """
629 Executes the collector based daemon command.
630
631 @param command: the collector daemon to run, should not include path
632 @type command: string
633 @param args: list of arguments for the command
634 @type args: list of strings
635 @param REQUEST: Zope REQUEST object
636 @type REQUEST: Zope REQUEST object
637 @return: result of the command
638 @rtype: string
639 """
640 cmd = binPath(command)
641 daemonCmd = [cmd]
642 daemonCmd.extend(args)
643 result = executeCommand(daemonCmd, REQUEST)
644 return result
645
646
649 """
650 Collect the configuration of this device AKA Model Device
651
652 @permission: ZEN_MANAGE_DEVICE
653 @param device: Name of a device or entry in DMD
654 @type device: string
655 @param setlog: If true, set up the output log of this process
656 @type setlog: boolean
657 @param REQUEST: Zope REQUEST object
658 @type REQUEST: Zope REQUEST object
659 @param generateEvents: unused
660 @type generateEvents: string
661 """
662 xmlrpc = isXmlRpc(REQUEST)
663 if setlog and REQUEST and not xmlrpc:
664 handler = setupLoggingHeader(device, REQUEST)
665
666 zenmodelerOpts = ['run', '--now', '--monitor', self.id, '-F', '-d', device.id]
667 if REQUEST:
668 zenmodelerOpts.append('--weblog')
669 result = self._executeZenModelerCommand(zenmodelerOpts, REQUEST)
670 if result and xmlrpc:
671 return result
672 log.info('configuration collected')
673
674 if setlog and REQUEST and not xmlrpc:
675 clearWebLoggingStream(handler)
676
677 if xmlrpc:
678 return 0
679
681 """
682 Execute zenmodeler and return result
683
684 @param zenmodelerOpts: zenmodeler command-line options
685 @type zenmodelerOpts: string
686 @param REQUEST: Zope REQUEST object
687 @type REQUEST: Zope REQUEST object
688 @return: results of command
689 @rtype: string
690 """
691 zm = binPath('zenmodeler')
692 zenmodelerCmd = [zm]
693 zenmodelerCmd.extend(zenmodelerOpts)
694 result = executeCommand(zenmodelerCmd, REQUEST)
695 return result
696
697
698 InitializeClass(PerformanceConf)
699
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0beta1 on Mon Oct 19 14:44:19 2009 | http://epydoc.sourceforge.net |