1
2
3
4
5
6
7
8
9
10
11
12
13 import rrdtool
14 from AccessControl import Permissions
15
16 from Globals import InitializeClass
17 from ThresholdClass import ThresholdClass
18 from ThresholdInstance import ThresholdInstance, ThresholdContext
19 from Products.ZenModel.PerformanceConf import performancePath
20 from Products.ZenEvents import Event
21 from Products.ZenEvents.ZenEventClasses import Perf_Snmp, Clear
22 from Products.ZenUtils.ZenTales import talesEval
23
24 import logging
25 log = logging.getLogger('zen.MinMaxCheck')
26
27 from sets import Set
28
44
45
47
48 minval = ""
49 maxval = ""
50 eventClass = Perf_Snmp
51 severity = 3
52 escalateCount = 0
53
54 _properties = ThresholdClass._properties + (
55 {'id':'minval', 'type':'string', 'mode':'w'},
56 {'id':'maxval', 'type':'string', 'mode':'w'},
57 {'id':'eventClass', 'type':'string', 'mode':'w'},
58 {'id':'severity', 'type':'int', 'mode':'w'},
59 {'id':'escalateCount', 'type':'int', 'mode':'w'},
60 )
61
62 factory_type_information = (
63 {
64 'immediate_view' : 'editRRDThreshold',
65 'actions' :
66 (
67 { 'id' : 'edit'
68 , 'name' : 'Min/Max Threshold'
69 , 'action' : 'editRRDThreshold'
70 , 'permissions' : ( Permissions.view, )
71 },
72 )
73 },
74 )
75
77 """Return the config used by the collector to process simple min/max
78 thresholds. (id, minval, maxval, severity, escalateCount)
79 """
80 mmt = MinMaxThresholdInstance(self.id,
81 ThresholdContext(context),
82 self.dsnames,
83 minval=self.getMinval(context),
84 maxval=self.getMaxval(context),
85 eventClass=self.eventClass,
86 severity=self.severity,
87 escalateCount=self.escalateCount)
88 return mmt
89
97
98
106
107 InitializeClass(MinMaxThreshold)
108 MinMaxThresholdClass = MinMaxThreshold
109
111
112 - def __init__(self, id, context, dpNames,
113 minval, maxval, eventClass, severity, escalateCount):
123
125 "return the name of this threshold (from the ThresholdClass)"
126 return self.id
127
129 "Return an identifying context (device, or device and component)"
130 return self._context
131
133 "Returns the names of the datapoints used to compute the threshold"
134 return self.dataPointNames
135
137 if dp in self._rrdInfoCache:
138 return self._rrdInfoCache[dp]
139 data = rrdtool.info(self.context().path(dp))
140 value = data['step'], data['ds']['ds0']['type']
141 self._rrdInfoCache[dp] = value
142 return value
143
144 - def check(self, dataPoints):
145 """The given datapoints have been updated, so re-evaluate.
146 returns events or an empty sequence"""
147 result = []
148 for dp in self.dataPointNames:
149 cycleTime, rrdType = self.rrdInfoCache(dp)
150 startStop, names, values = \
151 rrdtool.fetch(self.context().path(dp), 'AVERAGE',
152 '-s', 'now-%d' % (cycleTime*2),
153 '-e', 'now')
154 value = values[0][0]
155 result.extend(self.checkRange(dp, value))
156 return result
157
158 - def checkRaw(self, dataPoint, timeOf, value):
159 """A new datapoint has been collected, use the given _raw_
160 value to re-evalue the threshold."""
161 result = []
162 if value is None: return result
163 try:
164 cycleTime, rrdType = self.rrdInfoCache(dataPoint)
165 except Exception:
166 log.error('Unable to read RRD file for %s' % dataPoint)
167 return result
168 if rrdType != 'GAUGE':
169 startStop, names, values = \
170 rrdtool.fetch(self.context().path(dataPoint), 'AVERAGE',
171 '-s', 'now-%d' % (cycleTime*2),
172 '-e', 'now')
173 value = values[0][0]
174 result.extend(self.checkRange(dataPoint, value))
175 return result
176
178 'Check the value for min/max thresholds'
179 log.debug("Checking %s %s against min %s and max %s",
180 dp, value, self.minimum, self.maximum)
181 if value is None:
182 return []
183 thresh = None
184 if self.maximum is not None and value > self.maximum:
185 thresh = self.maximum
186 how = 'exceeded'
187 if self.minimum is not None and value < self.minimum:
188 thresh = self.minimum
189 how = 'not met'
190 label = self.context().componentName or ''
191 if thresh is not None:
192 self.count = (self.count or 0) + 1
193 severity = self.severity
194 if self.escalateCount and self.count >= self.escalateCount:
195 severity = max(severity + 1, 5)
196 summary = '%s %s threshold of %s %s: current value %.2f' % (
197 self.context().deviceName, label, self.name(), how, float(value))
198 return [dict(device=self.context().deviceName,
199 summary=summary,
200 eventClass=self.eventClass,
201 component=self.context().componentName,
202 severity=severity)]
203 else:
204 if self.count != 0 and self.count is not None:
205 summary = '%s %s threshold restored current value: %.2f' % (
206 self.context().deviceName, label, value)
207 self.count = 0
208 return [dict(device=self.context().deviceName,
209 summary=summary,
210 eventClass=self.eventClass,
211 component=self.context().componentName,
212 severity=Event.Clear)]
213 return []
214
215
217 """Produce a visual indication on the graph of where the
218 threshold applies."""
219 if not color.startswith('#'):
220 color = '#%s' % color
221 ns = namespace
222 n = self.minimum
223 x = self.maximum
224 gp = relatedGps[self.dataPointNames[0]]
225 if getattr(gp, 'rpn', ''):
226 n = rpneval(n, gp.rpn)
227 x = rpneval(x, gp.rpn)
228 result = []
229 if n:
230 result += [
231 "HRULE:%s%s:%s\\j" % (n, color, self.getMinLabel(n)),
232 ]
233 if x:
234 result += [
235 "HRULE:%s%s:%s\\j" % (x, color, self.getMaxLabel(x))
236 ]
237 return gopts + result
238
239
243
244
248
250 names = list(Set([x.split('_', 1)[1] for x in self.dataPointNames]))
251 names.sort()
252 return ', '.join(names)
253
254
256 powers = ("k", "M", "G")
257 if number < 1000: return number
258 for power in powers:
259 number = number / 1000
260 if number < 1000:
261 return "%0.2f%s" % (number, power)
262 return "%.2f%s" % (number, powers[-1])
263
264 from twisted.spread import pb
265 pb.setUnjellyableForClass(MinMaxThresholdInstance, MinMaxThresholdInstance)
266