Statistics
| Branch: | Tag: | Revision:

root / snf-stats-app / synnefo_stats / grapher.py @ 2439c9d6

History | View | Annotate | Download (8.6 kB)

1 e6ad6878 Stratos Psomadakis
# Copyright 2011-2013 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
36 7fcec5d7 Stratos Psomadakis
import gd
37 7fcec5d7 Stratos Psomadakis
import os
38 7fcec5d7 Stratos Psomadakis
39 7fcec5d7 Stratos Psomadakis
from cStringIO import StringIO
40 7fcec5d7 Stratos Psomadakis
41 7fcec5d7 Stratos Psomadakis
import rrdtool
42 7fcec5d7 Stratos Psomadakis
43 bd16bf3e Stratos Psomadakis
from Crypto.Cipher import AES
44 bd16bf3e Stratos Psomadakis
from base64 import urlsafe_b64decode
45 bd16bf3e Stratos Psomadakis
from hashlib import sha256
46 bd16bf3e Stratos Psomadakis
47 7fcec5d7 Stratos Psomadakis
from synnefo_stats import settings
48 7fcec5d7 Stratos Psomadakis
49 592bfc3b Stratos Psomadakis
from synnefo.util.text import uenc
50 592bfc3b Stratos Psomadakis
from snf_django.lib.api import faults, api_method
51 592bfc3b Stratos Psomadakis
52 592bfc3b Stratos Psomadakis
from logging import getLogger
53 592bfc3b Stratos Psomadakis
log = getLogger(__name__)
54 7fcec5d7 Stratos Psomadakis
55 7fcec5d7 Stratos Psomadakis
56 7fcec5d7 Stratos Psomadakis
def read_file(filepath):
57 592bfc3b Stratos Psomadakis
    f = open(filepath, "r")
58 7fcec5d7 Stratos Psomadakis
59 7fcec5d7 Stratos Psomadakis
    try:
60 7fcec5d7 Stratos Psomadakis
        data = f.read()
61 7fcec5d7 Stratos Psomadakis
    finally:
62 7fcec5d7 Stratos Psomadakis
        f.close()
63 7fcec5d7 Stratos Psomadakis
64 7fcec5d7 Stratos Psomadakis
    return data
65 7fcec5d7 Stratos Psomadakis
66 7fcec5d7 Stratos Psomadakis
67 592bfc3b Stratos Psomadakis
def draw_cpu_bar(fname, outfname=None):
68 592bfc3b Stratos Psomadakis
    fname = os.path.join(fname, "cpu", "virt_cpu_total.rrd")
69 7fcec5d7 Stratos Psomadakis
70 7fcec5d7 Stratos Psomadakis
    try:
71 7fcec5d7 Stratos Psomadakis
        values = rrdtool.fetch(fname, "AVERAGE")[2][-20:]
72 2439c9d6 Stratos Psomadakis
    except rrdtool.error:
73 7fcec5d7 Stratos Psomadakis
        values = [(0.0, )]
74 7fcec5d7 Stratos Psomadakis
75 7fcec5d7 Stratos Psomadakis
    v = [x[0] for x in values if x[0] is not None]
76 7fcec5d7 Stratos Psomadakis
    if not v:
77 7fcec5d7 Stratos Psomadakis
        # Fallback in case we only get NaNs
78 7fcec5d7 Stratos Psomadakis
        v = [0.0]
79 7fcec5d7 Stratos Psomadakis
    # Pick the last value
80 7fcec5d7 Stratos Psomadakis
    value = v[-1]
81 7fcec5d7 Stratos Psomadakis
82 7fcec5d7 Stratos Psomadakis
    image = gd.image((settings.IMAGE_WIDTH, settings.HEIGHT))
83 7fcec5d7 Stratos Psomadakis
84 7fcec5d7 Stratos Psomadakis
    border_color = image.colorAllocate(settings.BAR_BORDER_COLOR)
85 7fcec5d7 Stratos Psomadakis
    white = image.colorAllocate((0xff, 0xff, 0xff))
86 7fcec5d7 Stratos Psomadakis
    background_color = image.colorAllocate(settings.BAR_BG_COLOR)
87 7fcec5d7 Stratos Psomadakis
88 7fcec5d7 Stratos Psomadakis
    if value >= 90.0:
89 7fcec5d7 Stratos Psomadakis
        line_color = image.colorAllocate((0xff, 0x00, 0x00))
90 7fcec5d7 Stratos Psomadakis
    elif value >= 75.0:
91 7fcec5d7 Stratos Psomadakis
        line_color = image.colorAllocate((0xda, 0xaa, 0x00))
92 7fcec5d7 Stratos Psomadakis
    else:
93 7fcec5d7 Stratos Psomadakis
        line_color = image.colorAllocate((0x00, 0xa1, 0x00))
94 7fcec5d7 Stratos Psomadakis
95 592bfc3b Stratos Psomadakis
    image.rectangle((0, 0),
96 592bfc3b Stratos Psomadakis
                    (settings.WIDTH - 1, settings.HEIGHT - 1),
97 592bfc3b Stratos Psomadakis
                    border_color, background_color)
98 592bfc3b Stratos Psomadakis
    image.rectangle((1, 1),
99 592bfc3b Stratos Psomadakis
                    (int(value / 100.0 * (settings.WIDTH - 2)),
100 592bfc3b Stratos Psomadakis
                     settings.HEIGHT - 2),
101 592bfc3b Stratos Psomadakis
                    line_color, line_color)
102 592bfc3b Stratos Psomadakis
    image.string_ttf(settings.FONT, 8.0, 0.0,
103 592bfc3b Stratos Psomadakis
                     (settings.WIDTH + 1, settings.HEIGHT - 1),
104 592bfc3b Stratos Psomadakis
                     "CPU: %.1f%%" % value, white)
105 7fcec5d7 Stratos Psomadakis
106 7fcec5d7 Stratos Psomadakis
    io = StringIO()
107 7fcec5d7 Stratos Psomadakis
    image.writePng(io)
108 7fcec5d7 Stratos Psomadakis
    io.seek(0)
109 7fcec5d7 Stratos Psomadakis
    data = io.getvalue()
110 7fcec5d7 Stratos Psomadakis
    io.close()
111 7fcec5d7 Stratos Psomadakis
    return data
112 7fcec5d7 Stratos Psomadakis
113 7fcec5d7 Stratos Psomadakis
114 592bfc3b Stratos Psomadakis
def draw_net_bar(fname, outfname=None):
115 592bfc3b Stratos Psomadakis
    fname = os.path.join(fname, "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 2439c9d6 Stratos Psomadakis
    except rrdtool.error:
120 7fcec5d7 Stratos Psomadakis
        values = [(0.0, 0.0)]
121 7fcec5d7 Stratos Psomadakis
122 7fcec5d7 Stratos Psomadakis
    v = [x for x in values if x[0] is not None and x[1] is not None]
123 7fcec5d7 Stratos Psomadakis
    if not v:
124 7fcec5d7 Stratos Psomadakis
        # Fallback in case we only get NaNs
125 7fcec5d7 Stratos Psomadakis
        v = [(0.0, 0.0)]
126 7fcec5d7 Stratos Psomadakis
127 7fcec5d7 Stratos Psomadakis
    rx_value, tx_value = v[-1]
128 7fcec5d7 Stratos Psomadakis
129 7fcec5d7 Stratos Psomadakis
    # Convert to bits
130 592bfc3b Stratos Psomadakis
    rx_value = rx_value * 8 / 10 ** 6
131 592bfc3b Stratos Psomadakis
    tx_value = tx_value * 8 / 10 ** 6
132 7fcec5d7 Stratos Psomadakis
133 592bfc3b Stratos Psomadakis
    max_value = (int(max(rx_value, tx_value) / 50) + 1) * 50.0
134 7fcec5d7 Stratos Psomadakis
135 7fcec5d7 Stratos Psomadakis
    image = gd.image((settings.IMAGE_WIDTH, settings.HEIGHT))
136 7fcec5d7 Stratos Psomadakis
137 7fcec5d7 Stratos Psomadakis
    border_color = image.colorAllocate(settings.BAR_BORDER_COLOR)
138 7fcec5d7 Stratos Psomadakis
    white = image.colorAllocate((0xff, 0xff, 0xff))
139 7fcec5d7 Stratos Psomadakis
    background_color = image.colorAllocate(settings.BAR_BG_COLOR)
140 7fcec5d7 Stratos Psomadakis
141 7fcec5d7 Stratos Psomadakis
    tx_line_color = image.colorAllocate((0x00, 0xa1, 0x00))
142 7fcec5d7 Stratos Psomadakis
    rx_line_color = image.colorAllocate((0x00, 0x00, 0xa1))
143 7fcec5d7 Stratos Psomadakis
144 592bfc3b Stratos Psomadakis
    image.rectangle((0, 0),
145 592bfc3b Stratos Psomadakis
                    (settings.WIDTH - 1, settings.HEIGHT - 1),
146 592bfc3b Stratos Psomadakis
                    border_color, background_color)
147 592bfc3b Stratos Psomadakis
    image.rectangle((1, 1),
148 592bfc3b Stratos Psomadakis
                    (int(tx_value / max_value * (settings.WIDTH - 2)),
149 592bfc3b Stratos Psomadakis
                     settings.HEIGHT / 2 - 1),
150 592bfc3b Stratos Psomadakis
                    tx_line_color, tx_line_color)
151 592bfc3b Stratos Psomadakis
    image.rectangle((1, settings.HEIGHT / 2),
152 592bfc3b Stratos Psomadakis
                    (int(rx_value / max_value * (settings.WIDTH - 2)),
153 592bfc3b Stratos Psomadakis
                     settings.HEIGHT - 2),
154 592bfc3b Stratos Psomadakis
                    rx_line_color, rx_line_color)
155 592bfc3b Stratos Psomadakis
    image.string_ttf(settings.FONT, 8.0, 0.0,
156 592bfc3b Stratos Psomadakis
                     (settings.WIDTH + 1, settings.HEIGHT - 1),
157 592bfc3b Stratos Psomadakis
                     "TX/RX: %.2f/%.2f Mbps" % (tx_value, rx_value), white)
158 7fcec5d7 Stratos Psomadakis
159 7fcec5d7 Stratos Psomadakis
    io = StringIO()
160 7fcec5d7 Stratos Psomadakis
    image.writePng(io)
161 7fcec5d7 Stratos Psomadakis
    io.seek(0)
162 7fcec5d7 Stratos Psomadakis
    data = io.getvalue()
163 7fcec5d7 Stratos Psomadakis
    io.close()
164 7fcec5d7 Stratos Psomadakis
    return data
165 7fcec5d7 Stratos Psomadakis
166 7fcec5d7 Stratos Psomadakis
167 592bfc3b Stratos Psomadakis
def draw_cpu_ts(fname, outfname):
168 592bfc3b Stratos Psomadakis
    fname = os.path.join(fname, "cpu", "virt_cpu_total.rrd")
169 592bfc3b Stratos Psomadakis
    outfname += "-cpu.png"
170 7fcec5d7 Stratos Psomadakis
171 592bfc3b Stratos Psomadakis
    rrdtool.graph(outfname, "-s", "-1d", "-e", "-20s",
172 592bfc3b Stratos Psomadakis
                  #"-t", "CPU usage",
173 592bfc3b Stratos Psomadakis
                  "-v", "%",
174 592bfc3b Stratos Psomadakis
                  #"--lazy",
175 2439c9d6 Stratos Psomadakis
                  "DEF:cpu=%s:value:AVERAGE" % fname,
176 592bfc3b Stratos Psomadakis
                  "LINE1:cpu#00ff00:")
177 7fcec5d7 Stratos Psomadakis
178 7fcec5d7 Stratos Psomadakis
    return read_file(outfname)
179 7fcec5d7 Stratos Psomadakis
180 7fcec5d7 Stratos Psomadakis
181 592bfc3b Stratos Psomadakis
def draw_cpu_ts_w(fname, outfname):
182 592bfc3b Stratos Psomadakis
    fname = os.path.join(fname, "cpu", "virt_cpu_total.rrd")
183 592bfc3b Stratos Psomadakis
    outfname += "-cpu-weekly.png"
184 7fcec5d7 Stratos Psomadakis
185 592bfc3b Stratos Psomadakis
    rrdtool.graph(outfname, "-s", "-1w", "-e", "-20s",
186 592bfc3b Stratos Psomadakis
                  #"-t", "CPU usage",
187 592bfc3b Stratos Psomadakis
                  "-v", "%",
188 592bfc3b Stratos Psomadakis
                  #"--lazy",
189 2439c9d6 Stratos Psomadakis
                  "DEF:cpu=%s:value:AVERAGE" % fname,
190 592bfc3b Stratos Psomadakis
                  "LINE1:cpu#00ff00:")
191 7fcec5d7 Stratos Psomadakis
192 7fcec5d7 Stratos Psomadakis
    return read_file(outfname)
193 7fcec5d7 Stratos Psomadakis
194 7fcec5d7 Stratos Psomadakis
195 592bfc3b Stratos Psomadakis
def draw_net_ts(fname, outfname):
196 592bfc3b Stratos Psomadakis
    fname = os.path.join(fname, "interface", "if_octets-eth0.rrd")
197 592bfc3b Stratos Psomadakis
    outfname += "-net.png"
198 592bfc3b Stratos Psomadakis
199 592bfc3b Stratos Psomadakis
    rrdtool.graph(outfname, "-s", "-1d", "-e", "-20s",
200 2439c9d6 Stratos Psomadakis
                  "--units", "si",
201 2439c9d6 Stratos Psomadakis
                  "-v", "Bits/s",
202 2439c9d6 Stratos Psomadakis
                  "COMMENT:\t\t\tAverage network traffic\\n",
203 2439c9d6 Stratos Psomadakis
                  "DEF:rx=%s:rx:AVERAGE" % fname,
204 2439c9d6 Stratos Psomadakis
                  "DEF:tx=%s:tx:AVERAGE" % fname,
205 2439c9d6 Stratos Psomadakis
                  "CDEF:rxbits=rx,8,*",
206 2439c9d6 Stratos Psomadakis
                  "CDEF:txbits=tx,8,*",
207 2439c9d6 Stratos Psomadakis
                  "LINE1:rxbits#00ff00:Incoming",
208 2439c9d6 Stratos Psomadakis
                  "GPRINT:rxbits:AVERAGE:\t%4.0lf%sbps\t\g",
209 2439c9d6 Stratos Psomadakis
                  "LINE1:txbits#0000ff:Outgoing",
210 2439c9d6 Stratos Psomadakis
                  "GPRINT:txbits:AVERAGE:\t%4.0lf%sbps\\n")
211 7fcec5d7 Stratos Psomadakis
212 7fcec5d7 Stratos Psomadakis
    return read_file(outfname)
213 7fcec5d7 Stratos Psomadakis
214 7fcec5d7 Stratos Psomadakis
215 592bfc3b Stratos Psomadakis
def draw_net_ts_w(fname, outfname):
216 592bfc3b Stratos Psomadakis
    fname = os.path.join(fname, "interface", "if_octets-eth0.rrd")
217 592bfc3b Stratos Psomadakis
    outfname += "-net-weekly.png"
218 592bfc3b Stratos Psomadakis
219 592bfc3b Stratos Psomadakis
    rrdtool.graph(outfname, "-s", "-1w", "-e", "-20s",
220 2439c9d6 Stratos Psomadakis
                  "--units", "si",
221 2439c9d6 Stratos Psomadakis
                  "-v", "Bits/s",
222 2439c9d6 Stratos Psomadakis
                  "COMMENT:\t\t\tAverage network traffic\\n",
223 2439c9d6 Stratos Psomadakis
                  "DEF:rx=%s:rx:AVERAGE" % fname,
224 2439c9d6 Stratos Psomadakis
                  "DEF:tx=%s:tx:AVERAGE" % fname,
225 2439c9d6 Stratos Psomadakis
                  "CDEF:rxbits=rx,8,*",
226 2439c9d6 Stratos Psomadakis
                  "CDEF:txbits=tx,8,*",
227 2439c9d6 Stratos Psomadakis
                  "LINE1:rxbits#00ff00:Incoming",
228 2439c9d6 Stratos Psomadakis
                  "GPRINT:rxbits:AVERAGE:\t%4.0lf%sbps\t\g",
229 2439c9d6 Stratos Psomadakis
                  "LINE1:txbits#0000ff:Outgoing",
230 2439c9d6 Stratos Psomadakis
                  "GPRINT:txbits:AVERAGE:\t%4.0lf%sbps\\n")
231 7fcec5d7 Stratos Psomadakis
232 7fcec5d7 Stratos Psomadakis
    return read_file(outfname)
233 7fcec5d7 Stratos Psomadakis
234 7fcec5d7 Stratos Psomadakis
235 bd16bf3e Stratos Psomadakis
def decrypt(secret):
236 bd16bf3e Stratos Psomadakis
    # Make sure key is 32 bytes long
237 bd16bf3e Stratos Psomadakis
    key = sha256(settings.STATS_SECRET_KEY).digest()
238 bd16bf3e Stratos Psomadakis
239 bd16bf3e Stratos Psomadakis
    aes = AES.new(key)
240 bd16bf3e Stratos Psomadakis
    return aes.decrypt(urlsafe_b64decode(secret)).rstrip('\x00')
241 bd16bf3e Stratos Psomadakis
242 bd16bf3e Stratos Psomadakis
243 2439c9d6 Stratos Psomadakis
available_graph_types = {'cpu-bar': draw_cpu_bar,
244 2439c9d6 Stratos Psomadakis
                         'net-bar': draw_net_bar,
245 2439c9d6 Stratos Psomadakis
                         'cpu-ts': draw_cpu_ts,
246 2439c9d6 Stratos Psomadakis
                         'net-ts': draw_net_ts,
247 2439c9d6 Stratos Psomadakis
                         'cpu-ts-w': draw_cpu_ts_w,
248 2439c9d6 Stratos Psomadakis
                         'net-ts-w': draw_net_ts_w
249 2439c9d6 Stratos Psomadakis
                         }
250 7fcec5d7 Stratos Psomadakis
251 592bfc3b Stratos Psomadakis
252 592bfc3b Stratos Psomadakis
@api_method(http_method='GET', token_required=False, user_required=False,
253 592bfc3b Stratos Psomadakis
            format_allowed=False, logger=log)
254 592bfc3b Stratos Psomadakis
def grapher(request, graph_type, hostname):
255 bd16bf3e Stratos Psomadakis
    hostname = decrypt(uenc(hostname))
256 592bfc3b Stratos Psomadakis
    fname = uenc(os.path.join(settings.RRD_PREFIX, hostname))
257 592bfc3b Stratos Psomadakis
    if not os.path.isdir(fname):
258 592bfc3b Stratos Psomadakis
        raise faults.ItemNotFound('No such instance')
259 592bfc3b Stratos Psomadakis
260 592bfc3b Stratos Psomadakis
    outfname = uenc(os.path.join(settings.GRAPH_PREFIX, hostname))
261 592bfc3b Stratos Psomadakis
    draw_func = available_graph_types[graph_type]
262 592bfc3b Stratos Psomadakis
263 592bfc3b Stratos Psomadakis
    response = HttpResponse(draw_func(fname, outfname),
264 592bfc3b Stratos Psomadakis
                            status=200, content_type="image/png")
265 592bfc3b Stratos Psomadakis
    response.override_serialization = True
266 7fcec5d7 Stratos Psomadakis
267 7fcec5d7 Stratos Psomadakis
    return response