Statistics
| Branch: | Tag: | Revision:

root / snf-stats / synnefo_stats / grapher.py @ 7fcec5d7

History | View | Annotate | Download (9.2 kB)

1 7fcec5d7 Stratos Psomadakis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 7fcec5d7 Stratos Psomadakis
#
3 7fcec5d7 Stratos Psomadakis
# Redistribution and use in source and binary forms, with or
4 7fcec5d7 Stratos Psomadakis
# without modification, are permitted provided that the following
5 7fcec5d7 Stratos Psomadakis
# conditions are met:
6 7fcec5d7 Stratos Psomadakis
#
7 7fcec5d7 Stratos Psomadakis
#   1. Redistributions of source code must retain the above
8 7fcec5d7 Stratos Psomadakis
#      copyright notice, this list of conditions and the following
9 7fcec5d7 Stratos Psomadakis
#      disclaimer.
10 7fcec5d7 Stratos Psomadakis
#
11 7fcec5d7 Stratos Psomadakis
#   2. Redistributions in binary form must reproduce the above
12 7fcec5d7 Stratos Psomadakis
#      copyright notice, this list of conditions and the following
13 7fcec5d7 Stratos Psomadakis
#      disclaimer in the documentation and/or other materials
14 7fcec5d7 Stratos Psomadakis
#      provided with the distribution.
15 7fcec5d7 Stratos Psomadakis
#
16 7fcec5d7 Stratos Psomadakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 7fcec5d7 Stratos Psomadakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 7fcec5d7 Stratos Psomadakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 7fcec5d7 Stratos Psomadakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 7fcec5d7 Stratos Psomadakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 7fcec5d7 Stratos Psomadakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 7fcec5d7 Stratos Psomadakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 7fcec5d7 Stratos Psomadakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 7fcec5d7 Stratos Psomadakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 7fcec5d7 Stratos Psomadakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 7fcec5d7 Stratos Psomadakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 7fcec5d7 Stratos Psomadakis
# POSSIBILITY OF SUCH DAMAGE.
28 7fcec5d7 Stratos Psomadakis
#
29 7fcec5d7 Stratos Psomadakis
# The views and conclusions contained in the software and
30 7fcec5d7 Stratos Psomadakis
# documentation are those of the authors and should not be
31 7fcec5d7 Stratos Psomadakis
# interpreted as representing official policies, either expressed
32 7fcec5d7 Stratos Psomadakis
# or implied, of GRNET S.A.
33 7fcec5d7 Stratos Psomadakis
34 7fcec5d7 Stratos Psomadakis
from django.http import HttpResponse
35 7fcec5d7 Stratos Psomadakis
from django.views.decorators.http import require_http_methods
36 7fcec5d7 Stratos Psomadakis
37 7fcec5d7 Stratos Psomadakis
import gd
38 7fcec5d7 Stratos Psomadakis
import os
39 7fcec5d7 Stratos Psomadakis
import sys
40 7fcec5d7 Stratos Psomadakis
import subprocess
41 7fcec5d7 Stratos Psomadakis
42 7fcec5d7 Stratos Psomadakis
from cgi import escape
43 7fcec5d7 Stratos Psomadakis
from cStringIO import StringIO
44 7fcec5d7 Stratos Psomadakis
#from flup.server.fcgi import WSGIServer
45 7fcec5d7 Stratos Psomadakis
46 7fcec5d7 Stratos Psomadakis
import rrdtool
47 7fcec5d7 Stratos Psomadakis
48 7fcec5d7 Stratos Psomadakis
from synnefo_stats import settings
49 7fcec5d7 Stratos Psomadakis
50 7fcec5d7 Stratos Psomadakis
class InternalError(Exception):
51 7fcec5d7 Stratos Psomadakis
    pass
52 7fcec5d7 Stratos Psomadakis
53 7fcec5d7 Stratos Psomadakis
class NotFound(Exception):
54 7fcec5d7 Stratos Psomadakis
    pass
55 7fcec5d7 Stratos Psomadakis
56 7fcec5d7 Stratos Psomadakis
def read_file(filepath):
57 7fcec5d7 Stratos Psomadakis
    try:
58 7fcec5d7 Stratos Psomadakis
        f = open(filepath, "r")
59 7fcec5d7 Stratos Psomadakis
    except EnvironmentError, e:
60 7fcec5d7 Stratos Psomadakis
        raise InternalError(str(e))
61 7fcec5d7 Stratos Psomadakis
62 7fcec5d7 Stratos Psomadakis
    try:
63 7fcec5d7 Stratos Psomadakis
        data = f.read()
64 7fcec5d7 Stratos Psomadakis
    except EnvironmentError, e:
65 7fcec5d7 Stratos Psomadakis
        raise InternalError(str(e))
66 7fcec5d7 Stratos Psomadakis
    finally:
67 7fcec5d7 Stratos Psomadakis
        f.close()
68 7fcec5d7 Stratos Psomadakis
69 7fcec5d7 Stratos Psomadakis
    return data
70 7fcec5d7 Stratos Psomadakis
71 7fcec5d7 Stratos Psomadakis
72 7fcec5d7 Stratos Psomadakis
def draw_cpu_bar(hostname):
73 7fcec5d7 Stratos Psomadakis
    fname = os.path.join(settings.RRD_PREFIX, os.path.basename(hostname), "cpu", "virt_cpu_total.rrd")
74 7fcec5d7 Stratos Psomadakis
75 7fcec5d7 Stratos Psomadakis
    try:
76 7fcec5d7 Stratos Psomadakis
        values = rrdtool.fetch(fname, "AVERAGE")[2][-20:]
77 7fcec5d7 Stratos Psomadakis
    except rrdtool.error, e:
78 7fcec5d7 Stratos Psomadakis
        #raise InternalError(str(e))
79 7fcec5d7 Stratos Psomadakis
        values = [(0.0, )]
80 7fcec5d7 Stratos Psomadakis
81 7fcec5d7 Stratos Psomadakis
    v = [x[0] for x in values if x[0] is not None]
82 7fcec5d7 Stratos Psomadakis
    if not v:
83 7fcec5d7 Stratos Psomadakis
        # Fallback in case we only get NaNs
84 7fcec5d7 Stratos Psomadakis
        v = [0.0]
85 7fcec5d7 Stratos Psomadakis
    # Pick the last value
86 7fcec5d7 Stratos Psomadakis
    value = v[-1]
87 7fcec5d7 Stratos Psomadakis
88 7fcec5d7 Stratos Psomadakis
    image = gd.image((settings.IMAGE_WIDTH, settings.HEIGHT))
89 7fcec5d7 Stratos Psomadakis
90 7fcec5d7 Stratos Psomadakis
    border_color = image.colorAllocate(settings.BAR_BORDER_COLOR)
91 7fcec5d7 Stratos Psomadakis
    white = image.colorAllocate((0xff, 0xff, 0xff))
92 7fcec5d7 Stratos Psomadakis
    background_color = image.colorAllocate(settings.BAR_BG_COLOR)
93 7fcec5d7 Stratos Psomadakis
94 7fcec5d7 Stratos Psomadakis
    if value >= 90.0:
95 7fcec5d7 Stratos Psomadakis
        line_color = image.colorAllocate((0xff, 0x00, 0x00))
96 7fcec5d7 Stratos Psomadakis
    elif value >= 75.0:
97 7fcec5d7 Stratos Psomadakis
        line_color = image.colorAllocate((0xda, 0xaa, 0x00))
98 7fcec5d7 Stratos Psomadakis
    else:
99 7fcec5d7 Stratos Psomadakis
        line_color = image.colorAllocate((0x00, 0xa1, 0x00))
100 7fcec5d7 Stratos Psomadakis
101 7fcec5d7 Stratos Psomadakis
    image.rectangle((0,0), (settings.WIDTH-1, settings.HEIGHT-1), border_color, background_color)
102 7fcec5d7 Stratos Psomadakis
    image.rectangle((1,1), (int(value/100.0 * (settings.WIDTH - 2)), settings.HEIGHT - 2), line_color, line_color)
103 7fcec5d7 Stratos Psomadakis
    image.string_ttf(settings.FONT, 8.0, 0.0, (settings.WIDTH + 1, settings.HEIGHT - 1), "CPU: %.1f%%" % value, white)
104 7fcec5d7 Stratos Psomadakis
105 7fcec5d7 Stratos Psomadakis
    io = StringIO()
106 7fcec5d7 Stratos Psomadakis
    image.writePng(io)
107 7fcec5d7 Stratos Psomadakis
    io.seek(0)
108 7fcec5d7 Stratos Psomadakis
    data = io.getvalue()
109 7fcec5d7 Stratos Psomadakis
    io.close()
110 7fcec5d7 Stratos Psomadakis
    return data
111 7fcec5d7 Stratos Psomadakis
112 7fcec5d7 Stratos Psomadakis
113 7fcec5d7 Stratos Psomadakis
def draw_net_bar(hostname):
114 7fcec5d7 Stratos Psomadakis
    fname = os.path.join(settings.RRD_PREFIX, os.path.basename(hostname),
115 7fcec5d7 Stratos Psomadakis
                         "interface", "if_octets-eth0.rrd")
116 7fcec5d7 Stratos Psomadakis
117 7fcec5d7 Stratos Psomadakis
    try:
118 7fcec5d7 Stratos Psomadakis
        values = rrdtool.fetch(fname, "AVERAGE")[2][-20:]
119 7fcec5d7 Stratos Psomadakis
    except rrdtool.error, e:
120 7fcec5d7 Stratos Psomadakis
        #raise InternalError(str(e))
121 7fcec5d7 Stratos Psomadakis
        values = [(0.0, 0.0)]
122 7fcec5d7 Stratos Psomadakis
123 7fcec5d7 Stratos Psomadakis
    v = [x for x in values if x[0] is not None and x[1] is not None]
124 7fcec5d7 Stratos Psomadakis
    if not v:
125 7fcec5d7 Stratos Psomadakis
        # Fallback in case we only get NaNs
126 7fcec5d7 Stratos Psomadakis
        v = [(0.0, 0.0)]
127 7fcec5d7 Stratos Psomadakis
128 7fcec5d7 Stratos Psomadakis
    rx_value, tx_value = v[-1]
129 7fcec5d7 Stratos Psomadakis
130 7fcec5d7 Stratos Psomadakis
    # Convert to bits
131 7fcec5d7 Stratos Psomadakis
    rx_value = rx_value * 8 / 10**6
132 7fcec5d7 Stratos Psomadakis
    tx_value = tx_value * 8 / 10**6
133 7fcec5d7 Stratos Psomadakis
134 7fcec5d7 Stratos Psomadakis
    max_value = (int(max(rx_value, tx_value)/50) + 1) * 50.0
135 7fcec5d7 Stratos Psomadakis
136 7fcec5d7 Stratos Psomadakis
    image = gd.image((settings.IMAGE_WIDTH, settings.HEIGHT))
137 7fcec5d7 Stratos Psomadakis
138 7fcec5d7 Stratos Psomadakis
    border_color = image.colorAllocate(settings.BAR_BORDER_COLOR)
139 7fcec5d7 Stratos Psomadakis
    white = image.colorAllocate((0xff, 0xff, 0xff))
140 7fcec5d7 Stratos Psomadakis
    background_color = image.colorAllocate(settings.BAR_BG_COLOR)
141 7fcec5d7 Stratos Psomadakis
142 7fcec5d7 Stratos Psomadakis
    tx_line_color = image.colorAllocate((0x00, 0xa1, 0x00))
143 7fcec5d7 Stratos Psomadakis
    rx_line_color = image.colorAllocate((0x00, 0x00, 0xa1))
144 7fcec5d7 Stratos Psomadakis
145 7fcec5d7 Stratos Psomadakis
    image.rectangle((0,0), (settings.WIDTH-1, settings.HEIGHT-1), border_color, background_color)
146 7fcec5d7 Stratos Psomadakis
    image.rectangle((1,1), (int(tx_value/max_value * (settings.WIDTH-2)), settings.HEIGHT/2 - 1), tx_line_color, tx_line_color)
147 7fcec5d7 Stratos Psomadakis
    image.rectangle((1,settings.HEIGHT/2), (int(rx_value/max_value * (settings.WIDTH-2)), settings.HEIGHT - 2), rx_line_color, rx_line_color)
148 7fcec5d7 Stratos Psomadakis
    image.string_ttf(settings.FONT, 8.0, 0.0, (settings.WIDTH + 1, settings.HEIGHT - 1), "TX/RX: %.2f/%.2f Mbps" % (tx_value, rx_value), white)
149 7fcec5d7 Stratos Psomadakis
150 7fcec5d7 Stratos Psomadakis
    io = StringIO()
151 7fcec5d7 Stratos Psomadakis
    image.writePng(io)
152 7fcec5d7 Stratos Psomadakis
    io.seek(0)
153 7fcec5d7 Stratos Psomadakis
    data = io.getvalue()
154 7fcec5d7 Stratos Psomadakis
    io.close()
155 7fcec5d7 Stratos Psomadakis
    return data
156 7fcec5d7 Stratos Psomadakis
157 7fcec5d7 Stratos Psomadakis
158 7fcec5d7 Stratos Psomadakis
def draw_cpu_ts(hostname):
159 7fcec5d7 Stratos Psomadakis
    fname = os.path.join(settings.RRD_PREFIX, os.path.basename(hostname), "cpu", "virt_cpu_total.rrd")
160 7fcec5d7 Stratos Psomadakis
    outfname = os.path.join(settings.GRAPH_PREFIX, os.path.basename(hostname) + "-cpu.png")
161 7fcec5d7 Stratos Psomadakis
162 7fcec5d7 Stratos Psomadakis
    try:
163 7fcec5d7 Stratos Psomadakis
        rrdtool.graph(outfname, "-s", "-1d", "-e", "-20s",
164 7fcec5d7 Stratos Psomadakis
                      #"-t", "CPU usage",
165 7fcec5d7 Stratos Psomadakis
                      "-v", "%",
166 7fcec5d7 Stratos Psomadakis
                      #"--lazy",
167 7fcec5d7 Stratos Psomadakis
                      "DEF:cpu=%s:ns:AVERAGE" % fname,
168 7fcec5d7 Stratos Psomadakis
                      "LINE1:cpu#00ff00:")
169 7fcec5d7 Stratos Psomadakis
    except rrdtool.error, e:
170 7fcec5d7 Stratos Psomadakis
        raise InternalError(str(e))
171 7fcec5d7 Stratos Psomadakis
172 7fcec5d7 Stratos Psomadakis
    return read_file(outfname)
173 7fcec5d7 Stratos Psomadakis
174 7fcec5d7 Stratos Psomadakis
175 7fcec5d7 Stratos Psomadakis
def draw_cpu_ts_w(hostname):
176 7fcec5d7 Stratos Psomadakis
    fname = os.path.join(settings.RRD_PREFIX, os.path.basename(hostname), "cpu", "virt_cpu_total.rrd")
177 7fcec5d7 Stratos Psomadakis
    outfname = os.path.join(settings.GRAPH_PREFIX, os.path.basename(hostname) + "-cpu-weekly.png")
178 7fcec5d7 Stratos Psomadakis
179 7fcec5d7 Stratos Psomadakis
    try:
180 7fcec5d7 Stratos Psomadakis
        rrdtool.graph(outfname, "-s", "-1w", "-e", "-20s",
181 7fcec5d7 Stratos Psomadakis
                      #"-t", "CPU usage",
182 7fcec5d7 Stratos Psomadakis
                      "-v", "%",
183 7fcec5d7 Stratos Psomadakis
                      #"--lazy",
184 7fcec5d7 Stratos Psomadakis
                      "DEF:cpu=%s:ns:AVERAGE" % fname,
185 7fcec5d7 Stratos Psomadakis
                      "LINE1:cpu#00ff00:")
186 7fcec5d7 Stratos Psomadakis
    except rrdtool.error, e:
187 7fcec5d7 Stratos Psomadakis
        raise InternalError(str(e))
188 7fcec5d7 Stratos Psomadakis
189 7fcec5d7 Stratos Psomadakis
    return read_file(outfname)
190 7fcec5d7 Stratos Psomadakis
191 7fcec5d7 Stratos Psomadakis
192 7fcec5d7 Stratos Psomadakis
def draw_net_ts(hostname):
193 7fcec5d7 Stratos Psomadakis
    fname = os.path.join(settings.RRD_PREFIX, os.path.basename(hostname), "interface", "if_octets-eth0.rrd")
194 7fcec5d7 Stratos Psomadakis
    outfname = os.path.join(settings.GRAPH_PREFIX, os.path.basename(hostname) + "-net.png")
195 7fcec5d7 Stratos Psomadakis
    try:
196 7fcec5d7 Stratos Psomadakis
        rrdtool.graph(outfname, "-s", "-1d", "-e", "-20s",
197 7fcec5d7 Stratos Psomadakis
                  #"-t", "Network traffic",
198 7fcec5d7 Stratos Psomadakis
                  "--units", "si",
199 7fcec5d7 Stratos Psomadakis
                  "-v", "Bits/s",
200 7fcec5d7 Stratos Psomadakis
                  #"--lazy",
201 7fcec5d7 Stratos Psomadakis
                  "COMMENT:\t\t\tAverage network traffic\\n",
202 7fcec5d7 Stratos Psomadakis
                  "DEF:rx=%s:rx:AVERAGE" % fname,
203 7fcec5d7 Stratos Psomadakis
                  "DEF:tx=%s:tx:AVERAGE" % fname,
204 7fcec5d7 Stratos Psomadakis
                  "CDEF:rxbits=rx,8,*",
205 7fcec5d7 Stratos Psomadakis
                  "CDEF:txbits=tx,8,*",
206 7fcec5d7 Stratos Psomadakis
                  "LINE1:rxbits#00ff00:Incoming",
207 7fcec5d7 Stratos Psomadakis
                  "GPRINT:rxbits:AVERAGE:\t%4.0lf%sbps\t\g",
208 7fcec5d7 Stratos Psomadakis
                  "LINE1:txbits#0000ff:Outgoing",
209 7fcec5d7 Stratos Psomadakis
                  "GPRINT:txbits:AVERAGE:\t%4.0lf%sbps\\n")
210 7fcec5d7 Stratos Psomadakis
    except rrdtool.error, e:
211 7fcec5d7 Stratos Psomadakis
        raise InternalError(str(e))
212 7fcec5d7 Stratos Psomadakis
213 7fcec5d7 Stratos Psomadakis
    return read_file(outfname)
214 7fcec5d7 Stratos Psomadakis
215 7fcec5d7 Stratos Psomadakis
216 7fcec5d7 Stratos Psomadakis
def draw_net_ts_w(hostname):
217 7fcec5d7 Stratos Psomadakis
    fname = os.path.join(settings.RRD_PREFIX, os.path.basename(hostname), "interface", "if_octets-eth0.rrd")
218 7fcec5d7 Stratos Psomadakis
    outfname = os.path.join(settings.GRAPH_PREFIX, os.path.basename(hostname) + "-net-weekly.png")
219 7fcec5d7 Stratos Psomadakis
    try:
220 7fcec5d7 Stratos Psomadakis
        rrdtool.graph(outfname, "-s", "-1w", "-e", "-20s",
221 7fcec5d7 Stratos Psomadakis
                  #"-t", "Network traffic",
222 7fcec5d7 Stratos Psomadakis
                  "--units", "si",
223 7fcec5d7 Stratos Psomadakis
                  "-v", "Bits/s",
224 7fcec5d7 Stratos Psomadakis
                  #"--lazy",
225 7fcec5d7 Stratos Psomadakis
                  "COMMENT:\t\t\tAverage network traffic\\n",
226 7fcec5d7 Stratos Psomadakis
                  "DEF:rx=%s:rx:AVERAGE" % fname,
227 7fcec5d7 Stratos Psomadakis
                  "DEF:tx=%s:tx:AVERAGE" % fname,
228 7fcec5d7 Stratos Psomadakis
                  "CDEF:rxbits=rx,8,*",
229 7fcec5d7 Stratos Psomadakis
                  "CDEF:txbits=tx,8,*",
230 7fcec5d7 Stratos Psomadakis
                  "LINE1:rxbits#00ff00:Incoming",
231 7fcec5d7 Stratos Psomadakis
                  "GPRINT:rxbits:AVERAGE:\t%4.0lf%sbps\t\g",
232 7fcec5d7 Stratos Psomadakis
                  "LINE1:txbits#0000ff:Outgoing",
233 7fcec5d7 Stratos Psomadakis
                  "GPRINT:txbits:AVERAGE:\t%4.0lf%sbps\\n")
234 7fcec5d7 Stratos Psomadakis
    except rrdtool.error, e:
235 7fcec5d7 Stratos Psomadakis
        raise InternalError(str(e))
236 7fcec5d7 Stratos Psomadakis
237 7fcec5d7 Stratos Psomadakis
    return read_file(outfname)
238 7fcec5d7 Stratos Psomadakis
239 7fcec5d7 Stratos Psomadakis
240 7fcec5d7 Stratos Psomadakis
@require_http_methods(["GET"])
241 7fcec5d7 Stratos Psomadakis
def grapher(request, hostname, graph_type):
242 7fcec5d7 Stratos Psomadakis
    hostname = str(hostname)
243 7fcec5d7 Stratos Psomadakis
    graph = ""
244 7fcec5d7 Stratos Psomadakis
    ctype = "text/plain"
245 7fcec5d7 Stratos Psomadakis
    code = 200
246 7fcec5d7 Stratos Psomadakis
247 7fcec5d7 Stratos Psomadakis
    try:
248 7fcec5d7 Stratos Psomadakis
        if graph_type == "cpu-bar":
249 7fcec5d7 Stratos Psomadakis
            graph = draw_cpu_bar(hostname)
250 7fcec5d7 Stratos Psomadakis
        elif graph_type == "cpu-ts":
251 7fcec5d7 Stratos Psomadakis
            graph = draw_cpu_ts(hostname)
252 7fcec5d7 Stratos Psomadakis
        elif graph_type == "net-bar":
253 7fcec5d7 Stratos Psomadakis
            graph = draw_net_bar(hostname)
254 7fcec5d7 Stratos Psomadakis
        elif graph_type == "net-ts":
255 7fcec5d7 Stratos Psomadakis
            graph = draw_net_ts(hostname)
256 7fcec5d7 Stratos Psomadakis
        elif graph_type == "cpu-ts-w":
257 7fcec5d7 Stratos Psomadakis
            graph = draw_cpu_ts_w(hostname)
258 7fcec5d7 Stratos Psomadakis
        elif graph_type == "net-ts-w":
259 7fcec5d7 Stratos Psomadakis
            graph = draw_net_ts_w(hostname)
260 7fcec5d7 Stratos Psomadakis
        else:
261 7fcec5d7 Stratos Psomadakis
            raise NotFound
262 7fcec5d7 Stratos Psomadakis
        ctype = "image/png"
263 7fcec5d7 Stratos Psomadakis
    except InternalError:
264 7fcec5d7 Stratos Psomadakis
        code = 500
265 7fcec5d7 Stratos Psomadakis
    except NotFound:
266 7fcec5d7 Stratos Psomadakis
        code = 404
267 7fcec5d7 Stratos Psomadakis
268 7fcec5d7 Stratos Psomadakis
    response = HttpResponse(graph, content_type=ctype)
269 7fcec5d7 Stratos Psomadakis
    response.status_code = code
270 7fcec5d7 Stratos Psomadakis
271 7fcec5d7 Stratos Psomadakis
    return response