1
2
3
4
5
6
7
8
9
10
11 __doc__ = """RRDImpl
12
13 Implementation of basic RRD services for zenhub
14 """
15
16 import os.path
17 import logging
18 import time
19
20 from Products.ZenRRD.RRDUtil import RRDUtil
21 from Products.ZenEvents.ZenEventClasses import Critical, Status_Perf
22
23
24 log = logging.getLogger("zenhub")
25
26
27
29 """
30 RRDUtil wrapper class for zenhub
31 """
32
33
34 LONG_RRD_TYPES = ['COUNTER', 'DERIVE']
35
37 """
38 Initializer
39
40 @param dmd: Device Management Database (DMD) reference
41 @type dmd: dmd object
42 """
43
44 self.rrd = {}
45
46
47 self.counts = {}
48
49 self.dmd = dmd
50 self.zem = dmd.ZenEventManager
51
52
53 - def writeRRD(self, devId, compType, compId, dpName, value):
54 """
55 Write the given data to its RRD file.
56 Also check any thresholds and send events if value is out of bounds.
57 Note that if the write does not succeed, a None value is returned.
58
59 @param devId: device name (as known by DMD)
60 @type devId: string
61 @param compType: component type (found in objects meta_type field)
62 @type compType: string
63 @param compId: name of the component
64 @type compId: string
65 @param dpName: name of the data point
66 @type dpName: string
67 @param value: performance metric to store
68 @type value: number
69 @return: valid value (ie long or float) or None
70 @rtype: number or None
71 """
72 log.debug('Writing %s %s' % (dpName, value))
73 dev = self.getDeviceOrComponent(devId, compType, compId)
74 dp = dev.getRRDDataPoint(dpName)
75 if not dp:
76 log.warn('Did not find datapoint %s on device %s', dpName, devId)
77 return None
78 rrdKey = (dev.getPrimaryPath(), dp.getPrimaryPath())
79 rrdCreateCmd = None
80 if rrdKey in self.rrd:
81 rrd = self.rrd[rrdKey]
82 else:
83 rrdCreateCmd = dp.createCmd or self.getDefaultRRDCreateCommand(dev)
84 rrd = RRDUtil(rrdCreateCmd, dp.datasource.cycletime)
85 self.rrd[rrdKey] = rrd
86
87
88 if dp.rrdtype in RRDImpl.LONG_RRD_TYPES:
89 try:
90 value = long(value)
91 except ValueError:
92 log.warn("Value '%s' received for data point '%s' that " \
93 "could not be converted to a long" % \
94 (value, dp.rrdtype))
95
96
97
98 dp_has_threshold = self.hasThreshold(dp)
99 if dp_has_threshold:
100 rrd_write_fn = rrd.save
101 else:
102 rrd_write_fn = rrd.put
103
104 path = os.path.join(dev.rrdPath(), dp.name())
105 try:
106 value = rrd_write_fn( path,
107 value,
108 dp.rrdtype,
109 rrdCreateCmd,
110 dp.datasource.cycletime,
111 dp.rrdmin,
112 dp.rrdmax)
113
114 except Exception, ex:
115 summary= "Unable to save data in zenhub for RRD %s" % \
116 path
117 log.critical( summary )
118
119 message= "Data was value= %s, type=%s, min=%s, max=%s" % \
120 ( value, dp.rrdtype, dp.rrdmin, dp.rrdmax, )
121 log.critical( message )
122 log.exception( ex )
123
124 import traceback
125 trace_info= traceback.format_exc()
126
127 evid= self.zem.sendEvent(dict(
128 dedupid="%s|%s" % (devId, 'RRD write failure'),
129 severity=Critical,
130 device=devId,
131 eventClass=Status_Perf,
132 component="RRD",
133 compType=compType,
134 compId=compId,
135 datapoint=dpName,
136 message=message,
137 traceback=trace_info,
138 summary=summary))
139
140
141 return
142
143 if dp_has_threshold:
144 self.checkThresholds(dev, dp, value)
145 return value
146
147
149 """
150 Get the overridable create command for new RRD files.
151
152 @param device: device object from in DMD
153 @type device: device object
154 @return: RRD create command
155 @rtype: string
156 """
157 return device.perfServer().getDefaultRRDCreateCommand()
158
159
161 """
162 If a compId is given then try to return that component. If unable
163 to find it or if compId is not specified then try to return the
164 given device. If unable to find then return None.
165
166 @param devId: device name (as known by DMD)
167 @type devId: string
168 @param compId: name of the component
169 @type compId: string
170 @param compType: component type (found in objects meta_type field)
171 @type compType: string
172 @return: device or component object
173 @rtype: object
174 """
175 retobj = None
176 device = self.dmd.Devices.findDevice(devId)
177 if device:
178 if compId:
179 retobj = next((comp for comp in device.getDeviceComponents()
180 if comp.meta_type == compType and comp.id == compId),
181 None)
182
183 else:
184 retobj = device
185 return retobj
186
188 dp_name = dp.name()
189 return any(thresh.enabled and dp_name in thresh.dsnames
190 for thresh in dp.datasource.rrdTemplate.thresholds())
191
193 """
194 Check the given value against any thresholds. Count the number of
195 times a dp has exceeded a given threshold in self.counts. Send events
196 as appropriate.
197
198 @param dev: device or component object
199 @type dev: object
200 @param dp: datapoint
201 @type dp: RRD datapoint object
202 @param value: performance metric to compare
203 @type value: number
204 """
205 if value is None:
206 return
207
208
209
210 dp_name = dp.name()
211 for t in [t for t in dp.datasource.rrdTemplate.thresholds()
212 if t.enabled and dp_name in t.dsnames]:
213 log.debug('Checking %s value of %s against threshold %s: %s:%s' %
214 (dp_name, value, t.id, t.getMinval(dev), t.getMaxval(dev)))
215 inst = t.createThresholdInstance(dev)
216
217
218 countKey = inst.countKey('dp_ds')
219 inst.count[countKey] = self.counts.get(countKey, None)
220 for evt in inst.checkRaw(dp.name(), time.time(), value):
221 self.zem.sendEvent(evt)
222 self.counts[countKey] = inst.countKey('dp_ds')
223