Overview
The purpose of this article is do outline how to use the Zenoss RenderServer via its REST API to create and display graphs. The ZenossRender server is the zenoss application which takes performance data in its raw database form and generates a viewable image. There is a standard API to access this functionality and with a little bit of work we will be able to render graphs for ourselves.
Quick Start
If you want to bypass the technical details and just get a URL for a graph you care about, you can browse to the graph in Zenoss, right click and choose "Copy Image URL." You can then use the URL to reproduce a similar graph. You can edit the options in this URL to alter the graph.
Details
URL
The RenderServer takes a URL (with standard GET arguments) as input and provides a rendered graph as output. The render URL normally begins like this:
http://zenoss.example.com:8080/zport/RenderServer/render
Arguments
We must also pass some options to the URL. You MUST pass: gopts, start, end, drange and width. The full variety of the available options is listed here:
- gopts -- RRD graph creation options
- start -- requested start of data to graph (passed as the rrdtool --start option)
- end -- requested start of data to graph (passed as the rrdtool --end option)
- drange -- difference of time (in seconds) between start and end
- remoteUrl -- if the RRD is not here, where it lives
- width -- size of graphic to create (passed as the rrdtool --width option)
- ftype -- file type of graphic (eg PNG)
- getImage -- return the graph or a script location
- graphid -- (hopefully) unique identifier of a graph
- comment -- RRD graph comment
- ms -- a timestamp used to force IE to reload images
gopts contains options to pass to the "rrdtool graph" command. For the full range of possible options to use here, please see the RRDtool documentation. gopts is a compressed and encoded field. This means that you will most often see a long unreadable string of characters passed to this option. That is because this is first compressed with zlib and then encoded using a URL safe version of the base64 algorithm. A full example of rendering the bandwidth utilization of an interface on 'localhost' might look like this:
1. First we create our rrdtool command (for full details, see the RRDtool website):
rrdtool graph -F -E --height=100 --lower-limit=0 --rigid --vertical-label=bits/sec \'DEF:ifInOctets-raw=/opt/zenoss/perf/Devices/localhost/os/interfaces/eth0/ifInOctets_ifInOctets.rrd:ds0:AVERAGE' \'DEF:ifInOctets-raw-max=/opt/zenoss/perf/Devices/localhost/os/interfaces/eth0/ifInOctets_ifInOctets.rrd:ds0:MAX' \'CDEF:ifInOctets-rpn=ifInOctets-raw,8,*' \'CDEF:ifInOctets-rpn-max=ifInOctets-raw-max,8,*' \'CDEF:ifInOctets=ifInOctets-rpn' \'AREA:ifInOctets-rpn#00cc00ff:Inbound' \'GPRINT:ifInOctets-rpn:LAST:cur\\:%5.2lf%s' \'GPRINT:ifInOctets-rpn:AVERAGE:avg\\:%5.2lf%s' \'GPRINT:ifInOctets-rpn-max:MAX:max\\:%5.2lf%s\\j' \'DEF:ifOutOctets-raw=/opt/zenoss/perf/Devices/localhost/os/interfaces/eth0/ifOutOctets_ifOutOctets.rrd:ds0:AVERAGE' \'DEF:ifOutOctets-raw-max=/opt/zenoss/perf/Devices/localhost/os/interfaces/eth0/ifOutOctets_ifOutOctets.rrd:ds0:MAX' \'CDEF:ifOutOctets-rpn=ifOutOctets-raw,8,*' \'CDEF:ifOutOctets-rpn-max=ifOutOctets-raw-max,8,*' \'CDEF:ifOutOctets=ifOutOctets-rpn' \'LINE1:ifOutOctets-rpn#0000ff99:Outbound' \'GPRINT:ifOutOctets-rpn:LAST:cur\\:%5.2lf%s' \'GPRINT:ifOutOctets-rpn:AVERAGE:avg\\:%5.2lf%s' \'GPRINT:ifOutOctets-rpn-max:MAX:max\\:%5.2lf%s\\j'
2. Take the above command. Remove "rrdtool graph" and join the rest of the options with the '|' character (shown in python below):
>>> rrdGraphCommand = """-F|-E|--height=100|--lower-limit=0|--rigid|--vertical-label=bits/sec|DEF:ifInOctets-raw=/opt/zenoss/perf/Devices/localhost/os/interfaces/eth0/ifInOctets_ifInOctets.rrd:ds0:AVERAGE|DEF:ifInOctets-raw-max=/opt/zenoss/perf/Devices/localhost/os/interfaces/eth0/ifInOctets_ifInOctets.rrd:ds0:MAX|CDEF:ifInOctets-rpn=ifInOctets-raw,8,*|CDEF:ifInOctets-rpn-max=ifInOctets-raw-max,8,*|CDEF:ifInOctets=ifInOctets-rpn|AREA:ifInOctets-rpn#00cc00ff:Inbound|GPRINT:ifInOctets-rpn:LAST:cur\\:%5.2lf%s|GPRINT:ifInOctets-rpn:AVERAGE:avg\\:%5.2lf%s|GPRINT:ifInOctets-rpn-max:MAX:max\\:%5.2lf%s\\j|DEF:ifOutOctets-raw=/opt/zenoss/perf/Devices/localhost/os/interfaces/eth0/ifOutOctets_ifOutOctets.rrd:ds0:AVERAGE|DEF:ifOutOctets-raw-max=/opt/zenoss/perf/Devices/localhost/os/interfaces/eth0/ifOutOctets_ifOutOctets.rrd:ds0:MAX|CDEF:ifOutOctets-rpn=ifOutOctets-raw,8,*|CDEF:ifOutOctets-rpn-max=ifOutOctets-raw-max,8,*|CDEF:ifOutOctets=ifOutOctets-rpn|LINE1:ifOutOctets-rpn#0000ff99:Outbound|GPRINT:ifOutOctets-rpn:LAST:cur\\:%5.2lf%s|GPRINT:ifOutOctets-rpn:AVERAGE:avg\\:%5.2lf%s|GPRINT:ifOutOctets-rpn-max:MAX:max\\:%5.2lf%s\\j"""
3. Convert the above command to our compressed and encoded version (again, in python):
>>> import base64>>> import zlib>>> compressedGraphCommand = base64.urlsafe_b64encode(zlib.compress(rrdGraphCommand))>>> print compressedGraphCommand'eJy1Ul9rwjAc_DDDl2FMHAxmIA9lVik4HU7GHgSpaWozYiNJ1DHy4ZeKaNNWfdj2lD-93901d2BgQWgByBhfZYZ0EXIHIfdMAcHX3JDirPiKJ27dMWU4jQUQ8ZIJsuRGQ82o7YcDzNMon1DDjAYq3hMoNwZ-s1xqDTdMpbDPdpwyDYV0BJnUBkoNeW7ct7i4ZyZD8EyyOG87SiU40QgH7-E0GIYNcmAdf_2L5EvwYZ-repuc-PLtp_Z9E-xgq-60CU78SRtMw6DCdocQpQilKY7ypdzmiR2-TqPxrALDo-BthulWzXHrsfMg0pa-ADy-J453q1vYwnbxGNitZ-z885jFZGv-IPsTy6K0v5C-p_ir-K-rlgpQkjw0wLNQztQDHjtQ89s4QCrDdhSNw26V0hWhqEGvh911pQke8GoVfOSNLtR-qakMPyq2iAA='
4. This compressedGraphCommand is what will be passed as the gopts option. You may also specify other options.
5. This example shows the graph rendered using the above command, for the last 36 hours, with a width of 500 pixels:
http://zenoss.example.com:8080/zport/RenderServer/render?gopts=eJy1Ul9rwjAc_DDDl2FMHAxmIA9lVik4HU7GHgSpaWozYiNJ1DHy4ZeKaNNWfdj2lD-93901d2BgQWgByBhfZYZ0EXIHIfdMAcHX3JDirPiKJ27dMWU4jQUQ8ZIJsuRGQ82o7YcDzNMon1DDjAYq3hMoNwZ-s1xqDTdMpbDPdpwyDYV0BJnUBkoNeW7ct7i4ZyZD8EyyOG87SiU40QgH7-E0GIYNcmAdf_2L5EvwYZ-repuc-PLtp_Z9E-xgq-60CU78SRtMw6DCdocQpQilKY7ypdzmiR2-TqPxrALDo-BthulWzXHrsfMg0pa-ADy-J453q1vYwnbxGNitZ-z885jFZGv-IPsTy6K0v5C-p_ir-K-rlgpQkjw0wLNQztQDHjtQ89s4QCrDdhSNw26V0hWhqEGvh911pQke8GoVfOSNLtR-qakMPyq2iAA=&drange=129600&width=500&start=end-129600s&end=now-0s