1
2
3
4
5
6
7
8
9
10
11 __doc__="""GraphDefinition
12
13 GraphDefinition defines the global options for a graph.
14 """
15
16 import sys
17 import string
18
19 from Products.ZenRelations.RelSchema import *
20 from Products.ZenModel.ZenossSecurity import ZEN_MANAGE_DMD
21 from Globals import InitializeClass
22 from AccessControl import ClassSecurityInfo, Permissions
23 from ZenModelRM import ZenModelRM
24 from Products.ZenWidgets import messaging
25 from ZenPackable import ZenPackable
26 import logging
27 log = logging.getLogger("zen.Device")
28 from Acquisition import aq_base
29 from Products.ZenUtils.Utils import resequence
30 from Products.ZenUtils.deprecated import deprecated
31 from Products.ZenMessaging.audit import audit
45
47 isFake = True
48 - def __init__(self, name):
50 - def __getattr__(self, name):
52 - def __call__(self, *unused, **ignored):
54 - def __getitem__(self, key):
62 - def __nonzero__(self):
68
70 """
71 GraphDefinition defines the global options for a graph.
72 """
73
74 meta_type = 'GraphDefinition'
75
76 height = 100
77 width = 500
78 units = ""
79 log = False
80 base = False
81
82 miny = -1
83 maxy = -1
84 custom = ""
85 hasSummary = True
86 sequence = 0
87
88 _properties = (
89 {'id':'height', 'type':'int', 'mode':'w'},
90 {'id':'width', 'type':'int', 'mode':'w'},
91 {'id':'units', 'type':'string', 'mode':'w'},
92 {'id':'log', 'type':'boolean', 'mode':'w'},
93 {'id':'base', 'type':'boolean', 'mode':'w'},
94
95 {'id':'miny', 'type':'int', 'mode':'w'},
96 {'id':'maxy', 'type':'int', 'mode':'w'},
97 {'id':'custom', 'type':'text', 'mode':'w'},
98 {'id':'hasSummary', 'type':'boolean', 'mode':'w'},
99 {'id':'sequence', 'type':'long', 'mode':'w'},
100 )
101
102 _relations = (
103 ("rrdTemplate",
104 ToOne(ToManyCont,"Products.ZenModel.RRDTemplate", "graphDefs")),
105 ('report',
106 ToOne(ToManyCont, 'Products.ZenModel.MultiGraphReport', 'graphDefs')),
107 ('graphPoints',
108 ToManyCont(ToOne, 'Products.ZenModel.GraphPoint', 'graphDef')),
109
110 ('reportClass',
111 ToOne(ToManyCont, 'Products.ZenModel.MultiGraphReportClass', 'graphDefs')),
112 )
113
114
115
116 factory_type_information = (
117 {
118 'immediate_view' : 'editGraphDefinition',
119 'actions' :
120 (
121 { 'id' : 'edit'
122 , 'name' : 'Graph Definition'
123 , 'action' : 'editGraphDefinition'
124 , 'permissions' : ( Permissions.view, )
125 },
126 { 'id' : 'editCustom'
127 , 'name' : 'Graph Custom Definition'
128 , 'action' : 'editCustGraphDefinition'
129 , 'permissions' : ( Permissions.view, )
130 },
131 { 'id' : 'viewCommands'
132 , 'name' : 'Graph Commands'
133 , 'action' : 'viewGraphCommands'
134 , 'permissions' : ( Permissions.view, )
135 },
136 )
137 },
138 )
139
140 security = ClassSecurityInfo()
141
142
143
145 """ Return ordered list of graph points
146 """
147 gps = (gp for gp in self.graphPoints()
148 if includeThresholds or not gp.isThreshold)
149 def graphPointKey(a):
150 try:
151 return int(a.sequence)
152 except ValueError:
153 return sys.maxint
154 return sorted(gps, key=graphPointKey)
155
156
158 """ Get ordered list of threshold graph points
159 """
160 gps = [gp for gp in self.getGraphPoints() if gp.isThreshold]
161 return gps
162
163
169
170
178
179
180
181
191
192
194 """Checks a valid id
195 """
196
197
198
199
200 if len(id) > 200:
201 return 'GraphPoint names can not be longer than 200 characters.'
202 allowed = set(string.ascii_letters + string.digits + '_')
203 attempted = set(id)
204 if not attempted.issubset(allowed):
205 return 'Only letters, digits and underscores are allowed' + \
206 ' in GraphPoint names.'
207 return ZenModelRM.checkValidId(self, id, prep_id)
208
209
212
213
215 """ Return list of graph point ids
216 """
217 return [gp.id for gp in self.getGraphPoints()]
218
219
221 """
222 Return a string that lists the names of the graphpoints used in this
223 graph definition. If this graph definition has a perf template then
224 note in the string which graphpoints are broken (in that they refer
225 to nonexistent datapoints.)
226 """
227 names = []
228 for gp in self.getGraphPoints():
229 if hasattr(aq_base(gp), 'isBroken') and gp.isBroken():
230 names.append('%s(<span style="color: red">missing</span>)' %
231 gp.id)
232 else:
233 names.append(gp.id)
234 return ', '.join(names)
235
236
238 """ Used by dialog_addGraphPoint to construct the list of
239 available graphpoint types.
240 """
241 return (('DefGraphPoint', 'DEF'),
242 ('VdefGraphPoint', 'VDEF'),
243 ('CdefGraphPoint', 'CDEF'),
244 ('PrintGraphPoint', 'PRINT'),
245 ('GprintGraphPoint', 'GPRINT'),
246 ('CommentGraphPoint', 'COMMENT'),
247 ('VruleGraphPoint', 'VRULE'),
248 ('HruleGraphPoint', 'HRULE'),
249 ('LineGraphPoint', 'LINE'),
250 ('AreaGraphPoint', 'AREA'),
251 ('TickGraphPoint', 'TICK'),
252 ('ShiftGraphPoint', 'SHIFT'))
253
254
256 """ Create the graphpoint with the given id or something similar
257 and add to self.graphPoints
258 """
259 def getUniqueId(container, base):
260 ids = set(container.objectIds())
261 new = base
262 i = 2
263 while new in ids:
264 new = '%s%s' % (base, i)
265 i += 1
266 return new
267 newId = getUniqueId(self.graphPoints, newId)
268 gp = cls(newId)
269
270 if gp.isThreshold:
271 gp.sequence = -1
272 else:
273 gp.sequence = len(self.graphPoints())
274
275 if self.report() and hasattr(gp, 'legend'):
276
277
278
279 gp.legend = gp.DEFAULT_MULTIGRAPH_LEGEND
280 self.graphPoints._setObject(gp.id, gp)
281 gp = self.graphPoints._getOb(gp.id)
282 if gp.sequence == -1:
283 self.manage_resequenceGraphPoints()
284 return gp
285
286
287 security.declareProtected(ZEN_MANAGE_DMD, 'manage_addCustomGraphPoint')
300
301
302 security.declareProtected(ZEN_MANAGE_DMD, 'manage_addDataPointGraphPoints')
306 """ Create new graph points
307 The migrate script graphDefinitions and friends depends on the first
308 element in newGps being the DataPointGraphPoint when only one
309 name is passed in dpNames.
310 """
311 if not dpNames:
312 if REQUEST:
313 messaging.IMessageSender(self).sendToBrowser(
314 'Error',
315 'No graph points were selected.',
316 priority=messaging.WARNING
317 )
318 return self.callZenScreen(REQUEST)
319 else:
320 from DataPointGraphPoint import DataPointGraphPoint
321 newGps = []
322 for dpName in dpNames:
323 dpId = dpName.split('_', 1)[-1]
324 gp = self.createGraphPoint(DataPointGraphPoint, dpId)
325 gp.dpName = dpName
326 newGps.append(gp)
327 if includeThresholds:
328 for dpName in dpNames:
329 newGps += self.addThresholdsForDataPoint(dpName)
330 if REQUEST:
331 for dpName in dpNames:
332 audit('UI.GraphDefinition.AddGraphPoint', self.id, graphPointType='DataPoint',
333 graphPoint=dpName, includeThresholds=str(includeThresholds))
334 messaging.IMessageSender(self).sendToBrowser(
335 'Graph Points Added',
336 '%s graph point%s were added.' % (len(newGps),
337 len(newGps) > 1 and 's' or '')
338 )
339 return self.callZenScreen(REQUEST)
340 return newGps
341
342
358
359
360 security.declareProtected(ZEN_MANAGE_DMD, 'manage_addThresholdGraphPoints')
382
383
384 security.declareProtected(ZEN_MANAGE_DMD, 'manage_deleteGraphPoints')
403
404
405 security.declareProtected(ZEN_MANAGE_DMD, 'manage_resequenceGraphPoints')
407 """Reorder the sequence of the GraphPoints.
408 """
409 retval = resequence(self, self.graphPoints(), seqmap, origseq, REQUEST)
410 if REQUEST:
411 audit('UI.GraphDefinition.ResequenceGraphPoints', self.id, sequence=seqmap, oldData_={'sequence':origseq})
412 return retval
413
414
416 """ Return a list of (value, name) tuples for the list of datapoints
417 which the user selects from to create new graphpoints.
418 """
419 return [(dp.name(), dp.name())
420 for dp in self.rrdTemplate.getRRDDataPoints()]
421
422
424 """ Return a list of (value, name) tuples for the list of thresholds
425 which the user selects from to create new graphpoints.
426 """
427 return [(t.id, t.id) for t in self.rrdTemplate.thresholds()]
428
429
430
431
432
433 - def getGraphCmds(self, context, rrdDir, multiid=-1, upToPoint=None,
434 includeSetup=True, includeThresholds=True,
435 prefix='', cmds=None, idxOffset=0):
436 """build the graph opts for a single rrdfile"""
437 from Products.ZenUtils.ZenTales import talesEval
438 if not cmds:
439 cmds = []
440 if includeSetup:
441 cmds += self.graphsetup()
442
443
444
445 if includeThresholds:
446 threshGps = [gp for gp in self.getThresholdGraphPoints()
447 if upToPoint is None or gp.sequence < upToPoint]
448 if threshGps:
449 for index, gp in enumerate(threshGps):
450 try:
451 cmds = gp.getGraphCmds(cmds, context, rrdDir,
452 self.hasSummary, index+idxOffset,
453 multiid, prefix)
454 except (KeyError, NameError), e:
455 cmds.append('COMMENT: UNKNOWN VALUE IN '
456 'GRAPHPOINT %s\: %s' % (gp.id, str(e)))
457 gpList = [gp for gp in self.getGraphPoints(includeThresholds=False)
458 if upToPoint is None or gp.sequence < upToPoint]
459 for index, gp in enumerate(gpList):
460 try:
461 cmds = gp.getGraphCmds(cmds, context, rrdDir,
462 self.hasSummary, index+idxOffset,
463 multiid, prefix)
464 except (KeyError, NameError), e:
465 cmds.append('COMMENT: UNKNOWN VALUE IN GRAPHPOINT '
466 '%s\: %s' % (gp.id, str(e)))
467 if self.custom and includeSetup and not upToPoint:
468 try:
469 res = talesEval("string:"+str(self.custom), context)
470 except (KeyError, NameError), e:
471 res = 'COMMENT:UNKNOWN VALUE IN CUSTOM COMMANDS\: %s' % str(e)
472 cmds.extend(l for l in res.split('\n') if l.strip())
473
474
475
476 return cmds
477
478
480 """ Return list of rrd variable names that are defined by DEF, CDEF
481 or VDEF statements in the rrd commands. If upToPoint is not None then
482 only consider statements generated by graphoints where
483 sequence < upToPoint
484 """
485 cmds = self.getFakeGraphCmds(upToPoint=upToPoint)
486 names = [line[line.find(':')+1:line.find('=')]
487 for line in cmds.split('\n')
488 if line[:line.find(':')] in ('DEF', 'CDEF', 'VDEF')]
489 return names
490
491
500
501
503 """Setup global graph parameters.
504 """
505 gopts = ['-F', '-E', '--disable-rrdtool-tag']
506 if self.height:
507 gopts.append('--height=%d' % int(self.height))
508 if self.width:
509 gopts.append('--width=%d' % int(self.width))
510 if self.log:
511 gopts.append('--logarithmic')
512 if self.maxy > -1:
513 gopts.append('--upper-limit=%d' % int(self.maxy))
514 gopts.append('--rigid')
515 if self.miny > -1:
516 gopts.append('--lower-limit=%d' % int(self.miny))
517 gopts.append('--rigid')
518
519
520 gopts.append('--vertical-label=%s' % (self.units or ' '))
521 if self.units == 'percentage':
522 if not self.maxy > -1:
523 gopts.append('--upper-limit=100')
524 if not self.miny > -1:
525 gopts.append('--lower-limit=0')
526 if self.base:
527 gopts.append('--base=1024')
528 gopts = [str(o) for o in gopts]
529 return gopts
530
531
539
540
542 """
543 Get a list of all unique datapoint names
544 """
545 dpNames = set()
546 limitReached = False
547 for t in self.dmd.Devices.getAllRRDTemplates():
548 for ds in t.datasources():
549
550
551 if hasattr(ds, 'datapoints'):
552 for dp in ds.datapoints():
553 dpNames.add(dp.name())
554 if limit and len(dpNames) >= limit:
555 limitReached = True
556 break
557 if limitReached:
558 break
559 if limitReached:
560 break
561 return sorted(dpNames)
562
563
565 """
566 Get a list of all unique threshold names
567 """
568 names = set()
569 limitReached = False
570 for t in self.dmd.Devices.getAllRRDTemplates():
571 for thresh in t.thresholds():
572 names.add(thresh.id)
573 if len(names) >= limit:
574 limitReached = True
575 break
576 if limitReached:
577 break
578 return sorted(names)
579
580
581 InitializeClass(GraphDefinition)
582