1
2
3
4
5
6
7
8
9
10
11
12
13
14 __doc__="""RenderServer
15
16 Frontend that passes rrd graph options to rrdtool to render.
17
18 $Id: RenderServer.py,v 1.14 2003/06/04 18:25:58 edahl Exp $"""
19
20 __version__ = "$Revision: 1.14 $"[11:-2]
21
22 import os
23 import time
24 import logging
25 import urllib
26 import zlib
27 import mimetypes
28
29 from AccessControl import ClassSecurityInfo
30 from Globals import InitializeClass
31 from Globals import DTMLFile
32 from OFS.Image import manage_addFile
33
34 try:
35 import rrdtool
36 except ImportError:
37 pass
38
39 try:
40 from base64 import urlsafe_b64decode
41 raise ImportError
42 except ImportError:
44 import base64
45 return base64.decodestring(s.replace('-','+').replace('_','/'))
46
47 from Products.ZenUtils.PObjectCache import PObjectCache
48 from Products.ZenUtils.PObjectCache import CacheObj
49 from Products.ZenUtils.Utils import zenPath
50
51 from RRDToolItem import RRDToolItem
52
53 from Products.ZenModel.PerformanceConf import performancePath
54 import glob
55 import tarfile
56
57 import utils
58
59 log = logging.getLogger("RenderServer")
60
61
68
69
70 addRenderServer = DTMLFile('dtml/addRenderServer',globals())
71
72
74
75 meta_type = "RenderServer"
76
77 cacheName = 'RRDRenderCache'
78
79 security = ClassSecurityInfo()
80
81 - def __init__(self, id, tmpdir = '/tmp/renderserver', cachetimeout=300):
82 self.id = id
83 self.tmpdir = tmpdir
84 self.cachetimeout = cachetimeout
85
86 security.declareProtected('View', 'render')
87 - def render(self, gopts=None, start=None, end=None, drange=None,
88 remoteUrl=None, width=None, ftype='PNG', getImage=True,
89 graphid='', comment=None, REQUEST=None):
90 """render a graph and return it"""
91 gopts = zlib.decompress(urlsafe_b64decode(gopts))
92 gopts = gopts.split('|')
93 gopts.append('--width=%s' % width)
94 if start:
95 gopts.append('--start=%s' % start)
96 if end:
97 gopts.append('--end=%s' % end)
98 drange = int(drange)
99 id = self.graphId(gopts, drange, ftype)
100 graph = self.getGraph(id, ftype, REQUEST)
101 if not graph:
102 if not os.path.exists(self.tmpdir):
103 os.makedirs(self.tmpdir, 0750)
104 filename = "%s/graph-%s" % (self.tmpdir,id)
105 if remoteUrl:
106 f = open(filename, "w")
107 f.write(urllib.urlopen(remoteUrl).read())
108 f.close()
109 else:
110 if ftype.lower()=='html':
111 imgtype = 'PNG'
112 else:
113 imgtype = ftype
114 gopts.insert(0, "--imgformat=%s" % imgtype)
115
116 end = int(time.time())-300
117 start = end - drange
118 gopts.insert(0, 'COMMENT:%s\\c' % comment)
119 gopts.insert(0, '--end=%d' % end)
120 gopts.insert(0, '--start=%d' % start)
121 gopts.insert(0, filename)
122 try:
123 rrdtool.graph(*gopts)
124 except Exception, ex:
125 if ex.args[0].find('No such file or directory') > -1:
126 return None
127 log.exception("failed generating graph")
128 log.warn(" ".join(gopts))
129 raise
130 self.addGraph(id, filename)
131 graph = self.getGraph(id, ftype, REQUEST)
132 if getImage:
133 return graph
134 else:
135 return """
136 <script>
137 parent.location.hash = '%s:%s;';
138 </script>
139 """ % (graphid, str(bool(graph)))
140
141
161
163 """Tar a package of RRDFiles"""
164 srcdir = performancePath('/Devices/%s' % device)
165 tarfilename = '%s/%s.tgz' % (self.tmpdir, device)
166 tar = tarfile.open(tarfilename, "w:gz")
167 for file in os.listdir(srcdir):
168 tar.add('%s/%s' % (srcdir, file), '/%s' % os.path.basename(file))
169 tar.close()
170
172 """Untar a package of RRDFiles"""
173 destdir = performancePath('/Devices/%s' % device)
174 tarfilename = '%s/%s.tgz' % (self.tmpdir, device)
175 tar = tarfile.open(tarfilename, "r:gz")
176 for file in tar.getmembers():
177 tar.extract(file, destdir)
178 tar.close()
179
181 """receive a device's RRD Files from another server"""
182 tarfile = REQUEST.get('tarfile')
183 tarfilename = REQUEST.get('tarfilename')
184 f=open('%s/%s' % (self.tmpdir, tarfilename), 'wb')
185 f.write(urllib.unquote(tarfile))
186 f.close()
187
189 """Move a package of RRDFiles"""
190 tarfilename = '%s.tgz' % device
191 f=open('%s/%s' % (self.tmpdir, tarfilename), 'rb')
192 tarfilebody=f.read()
193 f.close()
194
195 params = urllib.urlencode({'tarfilename': tarfilename,
196 'tarfile':tarfilebody})
197
198 perfMon = self.dmd.getDmdRoot("Monitors").getPerformanceMonitor(server)
199 if perfMon.renderurl.startswith('http'):
200 remoteUrl = '%s/receiveRRDFiles' % (perfMon.renderurl)
201 urllib.urlopen(remoteUrl, params)
202
203
220
221 security.declareProtected('View', 'plugin')
223 "render a custom graph and return it"
224 try:
225 dmd = self.dmd
226 m = zenPath('Products/ZenRRD/plugins/%s.py' % name)
227 graph = None
228 exec open(m)
229 return graph
230 except Exception, ex:
231 log.exception("failed generating graph from plugin %s" % name)
232 raise
233
234
235 security.declareProtected('GenSummary', 'summary')
237 """return summary information as a list but no graph"""
238 gopts.insert(0, '/dev/null')
239 try:
240 values = rrdtool.graph(*gopts)[2]
241 except Exception, ex:
242 if ex.args[0].find('No such file or directory') > -1:
243 return None
244 log.exception("failed generating summary")
245 log.warn(" ".join(gopts))
246 raise
247 return values
248
249
250 security.declareProtected('GenSummary', 'currentValues')
252 """return latest values"""
253 try:
254 def value(p):
255 v = None
256 info = None
257 try:
258 info = rrdtool.info(p)
259 except:
260 log.debug('%s not found' % p)
261 if info:
262 last = info['last_update']
263 step = info['step']
264 v = rrdtool.graph('/dev/null',
265 'DEF:x=%s:ds0:AVERAGE' % p,
266 'VDEF:v=x,LAST',
267 'PRINT:v:%.2lf',
268 '--start=%d'%(last-step),
269 '--end=%d'%last)
270 v = float(v[2][0])
271 if str(v) == 'nan': v = None
272 return v
273 return map(value, paths)
274 except NameError:
275 log.warn("It appears that the rrdtool bindings are not installed properly.")
276 values = []
277 except Exception, ex:
278 if ex.args[0].find('No such file or directory') > -1:
279 return None
280 log.exception("failed generating summary")
281 raise
282
283
284 - def rrdcmd(self, gopts, ftype='PNG'):
285 filename, gopts = self._setfile(gopts, ftype)
286 return "rrdtool graph " + " ".join(gopts)
287
288
289 - def graphId(self, gopts, drange, ftype):
290 import md5
291 id = md5.new(''.join(gopts)).hexdigest()
292 id += str(drange) + '.' + ftype.lower()
293 return id
294
304
305
315
316
331
332
333 - def getGraph(self, id, ftype, REQUEST):
334 """get a previously generated graph"""
335 cache = self.setupCache()
336 ftype = ftype.lower()
337 mimetype = mimetypes.guess_type('.%s'%ftype)[0]
338 if not mimetype: mimetype = 'image/%s' % ftype
339 if REQUEST:
340 response = REQUEST.RESPONSE
341 response.setHeader('Content-Type', mimetype)
342 return cache.checkCache(id)
343
344
345 InitializeClass(RenderServer)
346