blob: ad2fe42f6a30319bc8485037bba6255a8adcad2e [file] [log] [blame]
gstepanov94531b82015-02-11 14:20:34 +02001from urlparse import urlparse
gstepanov6ce6bf02015-02-16 19:04:14 +02002from flask import Flask, render_template, url_for, request, g, make_response
gstepanov2164d822015-02-04 19:49:40 +02003from flask_bootstrap import Bootstrap
gstepanov725cc302015-02-09 15:08:06 +02004from config import TEST_PATH
gstepanov200d3b42015-02-06 14:01:49 +02005from report import build_vertical_bar, build_lines_chart
gstepanov8053b012015-02-16 17:25:27 +02006from storage_api import Measurement
gstepanov81a52ee2015-02-10 16:22:20 +02007from logging import getLogger, INFO
8
9import json
10import os.path
gstepanov6ce6bf02015-02-16 19:04:14 +020011import math
gstepanov94531b82015-02-11 14:20:34 +020012from web_app.keystone import KeystoneAuth
gstepanov2164d822015-02-04 19:49:40 +020013
14app = Flask(__name__)
15Bootstrap(app)
16
17
gstepanov3ce37b82015-02-12 16:20:56 +020018def get_resource_as_string(name, charset='utf-8'):
19 with app.open_resource(name) as f:
20 return f.read().decode(charset)
21
22app.jinja_env.globals['get_resource_as_string'] = get_resource_as_string
23
24
gstepanov9ddc18f2015-02-11 20:28:59 +020025def load_test(test_name):
26 test_name += '.json'
27
28 with open(TEST_PATH + "/" + test_name, 'rt') as f:
29 raw = f.read()
30
31 if raw != "":
32 test = json.loads(raw)
33 else:
34 test = []
35 import time
36 creation_time = os.path.getmtime(TEST_PATH + "/" + test_name)
37
38 for t in test:
39 t['date'] = time.ctime(creation_time)
40
41 return test
42
43
gstepanov2164d822015-02-04 19:49:40 +020044def collect_tests():
45 result = []
46
gstepanovc3ffac72015-02-05 15:39:45 +020047 for file in os.listdir(TEST_PATH):
gstepanov2164d822015-02-04 19:49:40 +020048 if file.endswith(".json"):
49 result.append(file.split('.')[0])
50
51 return result
52
53
gstepanov6ce6bf02015-02-16 19:04:14 +020054def mean(l):
55 n = len(l)
56
57 return sum(l) / n
58
59
60def stdev(l):
61 m = mean(l)
62 return math.sqrt(sum(map(lambda x: (x - m) ** 2, l)))
63
64
65def prepare_build_data(build):
66 for item in build.items():
67 if type(item[1]) is list:
68 m = mean(item[1])
69 s = stdev(item[1])
70 build[item[0]] = [m, s]
71
72
gstepanovbdc406b2015-02-11 17:35:55 +020073def collect_builds():
74 builds = []
75 build_set = set()
76 tests = collect_tests()
77
78 for t in tests:
79 test = load_test(t)
80
81 for build in test:
82 if build["type"] not in build_set:
83 build_set.add(build["type"])
84 builds.append(build)
85
gstepanov6ce6bf02015-02-16 19:04:14 +020086 for build in builds:
87 prepare_build_data(build)
88
gstepanovbdc406b2015-02-11 17:35:55 +020089 return builds
90
91
gstepanov9eb8bf32015-02-11 20:13:14 +020092def builds_list():
gstepanov2164d822015-02-04 19:49:40 +020093 data = []
gstepanovbdc406b2015-02-11 17:35:55 +020094
95 for build in collect_builds():
gstepanov2164d822015-02-04 19:49:40 +020096 d = {}
gstepanov612159f2015-02-12 17:15:29 +020097 d["type"] = build['type']
gstepanova0cb9252015-02-12 17:53:31 +020098 d["url"] = url_for("render_test", test_name=build['name'])
gstepanov9eb8bf32015-02-11 20:13:14 +020099 d["date"] = build['date']
gstepanovdff5ad92015-02-12 17:13:09 +0200100 d["name"] = build['name']
gstepanov2164d822015-02-04 19:49:40 +0200101 data.append(d)
102
gstepanov9eb8bf32015-02-11 20:13:14 +0200103 return data
104
gstepanov2164d822015-02-04 19:49:40 +0200105
gstepanovbdc406b2015-02-11 17:35:55 +0200106def create_measurement(build):
107 m = Measurement()
108 m.build = build.pop("build_id")
109 m.build_type = build.pop("type")
110 m.md5 = build.pop("iso_md5")
gstepanov9eb8bf32015-02-11 20:13:14 +0200111 m.date = build.pop("date")
gstepanovdff5ad92015-02-12 17:13:09 +0200112 m.date = build.pop("name")
gstepanovbdc406b2015-02-11 17:35:55 +0200113 m.results = {k: v for k, v in build.items()}
114
115 return m
116
117
gstepanove1ee9dc2015-02-11 18:09:46 +0200118def total_lab_info(data):
119 d = {}
120 d['nodes_count'] = len(data['nodes'])
121 d['total_memory'] = 0
122 d['total_disk'] = 0
123 d['processor_count'] = 0
124
125 for node in data['nodes']:
126 d['total_memory'] += node['memory']['total']
127 d['processor_count'] += len(node['processors'])
128
129 for disk in node['disks']:
130 d['total_disk'] += disk['size']
131
gstepanov9eb8bf32015-02-11 20:13:14 +0200132 to_gb = lambda x: x / (1024 ** 3)
133 d['total_memory'] = format(to_gb(d['total_memory']), ',d')
134 d['total_disk'] = format(to_gb(d['total_disk']), ',d')
gstepanove1ee9dc2015-02-11 18:09:46 +0200135 return d
136
gstepanov9eb8bf32015-02-11 20:13:14 +0200137
gstepanov9ddc18f2015-02-11 20:28:59 +0200138def collect_lab_data(meta):
139 u = urlparse(meta['__meta__'])
140 cred = {"username": "admin", "password": "admin", "tenant_name": "admin"}
141 keystone = KeystoneAuth(root_url=meta['__meta__'], creds=cred, admin_node_ip=u.hostname)
142 lab_info = keystone.do(method='get', path="")
143 nodes = []
144 result = {}
145
146 for node in lab_info:
147 d = {}
148 d['name'] = node['name']
149 p = []
150 i = []
151 disks = []
152 devices = []
153
154 for processor in node['meta']['cpu']['spec']:
155 p.append(processor)
156
157 for iface in node['meta']['interfaces']:
158 i.append(iface)
159
160 m = node['meta']['memory'].copy()
161
162 for disk in node['meta']['disks']:
163 disks.append(disk)
164
165 d['memory'] = m
166 d['disks'] = disks
167 d['devices'] = devices
168 d['interfaces'] = i
169 d['processors'] = p
170
171 nodes.append(d)
172
173 result['nodes'] = nodes
174 result['name'] = 'Perf-1 Env'
175
176 return result
177
178
gstepanov6c5deb32015-02-12 19:25:46 +0200179def merge_builds(b1, b2):
180 d = {}
181
182 for pair in b2.items():
gstepanov8053b012015-02-16 17:25:27 +0200183 if pair[0] in b1 and type(pair[1]) is list:
184 b1[pair[0]].extend(pair[1])
185 else:
186 b1[pair[0]] = pair[1]
gstepanov6c5deb32015-02-12 19:25:46 +0200187
188
gstepanov9ddc18f2015-02-11 20:28:59 +0200189@app.route("/", methods=['GET', 'POST'])
190def index():
191 data = builds_list()
192 return render_template("index.html", tests=data)
193
194
gstepanov6ce6bf02015-02-16 19:04:14 +0200195@app.route("/images/<image_name>")
196def get_image(image_name):
197 with open("static/images/" + image_name, 'rb') as f:
198 image_binary = f.read()
199
200 response = make_response(image_binary)
201 response.headers['Content-Type'] = 'image/png'
202 response.headers['Content-Disposition'] = 'attachment; filename=img.png'
203
204 return response
205
206
gstepanov2164d822015-02-04 19:49:40 +0200207@app.route("/tests/<test_name>", methods=['GET'])
208def render_test(test_name):
gstepanov9eb8bf32015-02-11 20:13:14 +0200209 tests = []
210 header_keys = ['build_id', 'iso_md5', 'type', 'date']
gstepanov0a8fdd32015-02-05 15:54:11 +0200211 table = [[]]
gstepanovbdc406b2015-02-11 17:35:55 +0200212 builds = collect_builds()
gstepanova0cb9252015-02-12 17:53:31 +0200213
214 l = filter(lambda x: x['name'] == test_name, builds)
215
216 if l[0]['type'] == 'GA':
217 builds = filter(lambda x: x['type'] == 'GA', builds)
218 else:
219 l.extend(filter(lambda x: x['type'] in ['GA', 'master'] and x not in l, builds))
220 builds = l
221
gstepanovbdc406b2015-02-11 17:35:55 +0200222 results = {}
gstepanove1ee9dc2015-02-11 18:09:46 +0200223 meta = {"__meta__": "http://172.16.52.112:8000/api/nodes"}
224 data = collect_lab_data(meta)
225 lab_meta = total_lab_info(data)
gstepanovbdc406b2015-02-11 17:35:55 +0200226
227 for build in builds:
gstepanova0cb9252015-02-12 17:53:31 +0200228 type = build['type']
229 m = create_measurement(build)
230 results[type] = m
gstepanovbdc406b2015-02-11 17:35:55 +0200231
gstepanov200d3b42015-02-06 14:01:49 +0200232 bars = build_vertical_bar(results)
233 lines = build_lines_chart(results)
234 urls = bars + lines
gstepanov6ce6bf02015-02-16 19:04:14 +0200235
236 urls = [url_for("get_image", image_name=os.path.basename(url)) if not url.startswith('http') else url for url in urls]
237
gstepanov2164d822015-02-04 19:49:40 +0200238 if len(tests) > 0:
239 sorted_keys = sorted(tests[0].keys())
240
gstepanov0a8fdd32015-02-05 15:54:11 +0200241 for key in sorted_keys:
242 if key not in header_keys:
243 header_keys.append(key)
gstepanov2164d822015-02-04 19:49:40 +0200244
gstepanov0a8fdd32015-02-05 15:54:11 +0200245 for test in tests:
246 row = []
gstepanov2164d822015-02-04 19:49:40 +0200247
gstepanov0a8fdd32015-02-05 15:54:11 +0200248 for header in header_keys:
249 if isinstance(test[header], list):
250 row.append(str(test[header][0]) + unichr(0x00B1) + str(test[header][1]))
251 else:
252 row.append(test[header])
gstepanov2164d822015-02-04 19:49:40 +0200253
gstepanov0a8fdd32015-02-05 15:54:11 +0200254 table.append(row)
gstepanov2164d822015-02-04 19:49:40 +0200255
gstepanov9eb8bf32015-02-11 20:13:14 +0200256 return render_template("test.html", urls=urls, table_url=url_for('render_table', test_name=test_name),
257 index_url=url_for('index'), lab_meta=lab_meta)
gstepanovcd77d5a2015-02-06 14:49:34 +0200258
259
260@app.route("/tests/table/<test_name>/")
261def render_table(test_name):
gstepanovbdc406b2015-02-11 17:35:55 +0200262 builds = collect_builds()
gstepanov6e4a7eb2015-02-12 17:57:59 +0200263 l = filter(lambda x: x['name'] == test_name, builds)
264 if l[0]['type'] == 'GA':
265 builds = filter(lambda x: x['type'] == 'GA', builds)
gstepanov3ce37b82015-02-12 16:20:56 +0200266 else:
gstepanov6e4a7eb2015-02-12 17:57:59 +0200267 l.extend(filter(lambda x: x['type'] in ['GA', 'master'] and x not in l, builds))
268 builds = l
gstepanov3ce37b82015-02-12 16:20:56 +0200269
gstepanov9eb8bf32015-02-11 20:13:14 +0200270 header_keys = ['build_id', 'iso_md5', 'type' ,'date']
gstepanovcd77d5a2015-02-06 14:49:34 +0200271 table = [[]]
gstepanov94531b82015-02-11 14:20:34 +0200272 meta = {"__meta__": "http://172.16.52.112:8000/api/nodes"}
gstepanove1ee9dc2015-02-11 18:09:46 +0200273 data = collect_lab_data(meta)
gstepanovbdc406b2015-02-11 17:35:55 +0200274
275 if len(builds) > 0:
276 sorted_keys = sorted(builds[0].keys())
gstepanovcd77d5a2015-02-06 14:49:34 +0200277
278 for key in sorted_keys:
279 if key not in header_keys:
280 header_keys.append(key)
281
gstepanovbdc406b2015-02-11 17:35:55 +0200282 for test in builds:
gstepanovcd77d5a2015-02-06 14:49:34 +0200283 row = []
284
285 for header in header_keys:
286 if isinstance(test[header], list):
287 row.append(str(test[header][0]) + unichr(0x00B1) + str(test[header][1]))
288 else:
289 row.append(test[header])
290
291 table.append(row)
292
gstepanovbb854922015-02-09 18:18:17 +0200293 return render_template("table.html", headers=header_keys, table=table,
294 back_url=url_for('render_test', test_name=test_name), lab=data)
gstepanov2164d822015-02-04 19:49:40 +0200295
296
gstepanov3ce37b82015-02-12 16:20:56 +0200297@app.route("/api/tests/<test_name>", methods=['POST'])
gstepanov2164d822015-02-04 19:49:40 +0200298def add_test(test_name):
gstepanov6c5deb32015-02-12 19:25:46 +0200299 test = json.loads(request.data)
gstepanov2164d822015-02-04 19:49:40 +0200300
gstepanov6c5deb32015-02-12 19:25:46 +0200301 file_name = TEST_PATH + '/' + 'storage' + ".json"
gstepanov2164d822015-02-04 19:49:40 +0200302
gstepanov6c5deb32015-02-12 19:25:46 +0200303 if not os.path.exists(file_name):
304 with open(file_name, "w+") as f:
305 f.write(json.dumps([]))
306
307 builds = collect_builds()
308 res = None
309
310 for b in builds:
311 if b['name'] == test['name']:
312 res = b
313 break
314
315 if res is None:
316 builds.append(test)
317 else:
318 merge_builds(res, test)
319
320 with open(TEST_PATH + '/' + 'storage' + ".json", 'w+') as f:
321 f.write(json.dumps(builds))
322
gstepanov2164d822015-02-04 19:49:40 +0200323 return "Created", 201
324
325
gstepanov3ce37b82015-02-12 16:20:56 +0200326@app.route("/api/tests", methods=['GET'])
327def get_all_tests():
328 return json.dumps(collect_builds())
329
330
331@app.route("/api/tests/<test_name>", methods=['GET'])
332def get_test(test_name):
333 builds = collect_builds()
334
335 for build in builds:
336 if build["type"] == test_name:
337 return json.dumps(build)
338 return "Not Found", 404
339
340
gstepanov2164d822015-02-04 19:49:40 +0200341if __name__ == "__main__":
gstepanov81a52ee2015-02-10 16:22:20 +0200342 logger = getLogger("logger")
343 app.logger.setLevel(INFO)
344 app.logger.addHandler(logger)
gstepanov6f7167d2015-02-06 12:51:58 +0200345 app.run(host='0.0.0.0', debug=True)