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