blob: eecb577da47cb8622cf2d5f4470a89d00e33c29b [file] [log] [blame]
koder aka kdanilov0f0546c2015-02-17 20:42:05 -08001# <koder>: order imports in usual way
2
gstepanov94531b82015-02-11 14:20:34 +02003from urlparse import urlparse
gstepanov6ce6bf02015-02-16 19:04:14 +02004from flask import Flask, render_template, url_for, request, g, make_response
gstepanov2164d822015-02-04 19:49:40 +02005from flask_bootstrap import Bootstrap
gstepanov725cc302015-02-09 15:08:06 +02006from config import TEST_PATH
gstepanov200d3b42015-02-06 14:01:49 +02007from report import build_vertical_bar, build_lines_chart
gstepanovec9048c2015-02-16 19:17:09 +02008from storage_api import builds_list, collect_builds, create_measurement
gstepanov81a52ee2015-02-10 16:22:20 +02009from logging import getLogger, INFO
10
11import json
12import os.path
gstepanov6ce6bf02015-02-16 19:04:14 +020013import math
gstepanov94531b82015-02-11 14:20:34 +020014from web_app.keystone import KeystoneAuth
gstepanov2164d822015-02-04 19:49:40 +020015
16app = Flask(__name__)
17Bootstrap(app)
18
19
gstepanov3ce37b82015-02-12 16:20:56 +020020def get_resource_as_string(name, charset='utf-8'):
21 with app.open_resource(name) as f:
22 return f.read().decode(charset)
23
24app.jinja_env.globals['get_resource_as_string'] = get_resource_as_string
25
26
gstepanove1ee9dc2015-02-11 18:09:46 +020027def total_lab_info(data):
koder aka kdanilov0f0546c2015-02-17 20:42:05 -080028 # <koder>: give 'd' meaningful name
gstepanove1ee9dc2015-02-11 18:09:46 +020029 d = {}
30 d['nodes_count'] = len(data['nodes'])
31 d['total_memory'] = 0
32 d['total_disk'] = 0
33 d['processor_count'] = 0
34
35 for node in data['nodes']:
36 d['total_memory'] += node['memory']['total']
37 d['processor_count'] += len(node['processors'])
38
39 for disk in node['disks']:
40 d['total_disk'] += disk['size']
41
gstepanov9eb8bf32015-02-11 20:13:14 +020042 to_gb = lambda x: x / (1024 ** 3)
43 d['total_memory'] = format(to_gb(d['total_memory']), ',d')
44 d['total_disk'] = format(to_gb(d['total_disk']), ',d')
gstepanove1ee9dc2015-02-11 18:09:46 +020045 return d
46
gstepanov9eb8bf32015-02-11 20:13:14 +020047
gstepanov9ddc18f2015-02-11 20:28:59 +020048def collect_lab_data(meta):
49 u = urlparse(meta['__meta__'])
50 cred = {"username": "admin", "password": "admin", "tenant_name": "admin"}
51 keystone = KeystoneAuth(root_url=meta['__meta__'], creds=cred, admin_node_ip=u.hostname)
52 lab_info = keystone.do(method='get', path="")
53 nodes = []
54 result = {}
55
56 for node in lab_info:
koder aka kdanilov0f0546c2015-02-17 20:42:05 -080057 # <koder>: give p,i,d,... vars meaningful names
gstepanov9ddc18f2015-02-11 20:28:59 +020058 d = {}
59 d['name'] = node['name']
60 p = []
61 i = []
62 disks = []
63 devices = []
64
65 for processor in node['meta']['cpu']['spec']:
66 p.append(processor)
67
68 for iface in node['meta']['interfaces']:
69 i.append(iface)
70
71 m = node['meta']['memory'].copy()
72
73 for disk in node['meta']['disks']:
74 disks.append(disk)
75
76 d['memory'] = m
77 d['disks'] = disks
78 d['devices'] = devices
79 d['interfaces'] = i
80 d['processors'] = p
81
82 nodes.append(d)
83
84 result['nodes'] = nodes
85 result['name'] = 'Perf-1 Env'
86
87 return result
88
89
gstepanov6c5deb32015-02-12 19:25:46 +020090def merge_builds(b1, b2):
91 d = {}
92
93 for pair in b2.items():
gstepanov8053b012015-02-16 17:25:27 +020094 if pair[0] in b1 and type(pair[1]) is list:
95 b1[pair[0]].extend(pair[1])
96 else:
97 b1[pair[0]] = pair[1]
gstepanov6c5deb32015-02-12 19:25:46 +020098
99
gstepanov9ddc18f2015-02-11 20:28:59 +0200100@app.route("/", methods=['GET', 'POST'])
101def index():
102 data = builds_list()
103 return render_template("index.html", tests=data)
104
105
gstepanov6ce6bf02015-02-16 19:04:14 +0200106@app.route("/images/<image_name>")
107def get_image(image_name):
108 with open("static/images/" + image_name, 'rb') as f:
109 image_binary = f.read()
110
111 response = make_response(image_binary)
112 response.headers['Content-Type'] = 'image/png'
113 response.headers['Content-Disposition'] = 'attachment; filename=img.png'
114
115 return response
116
117
gstepanov2164d822015-02-04 19:49:40 +0200118@app.route("/tests/<test_name>", methods=['GET'])
119def render_test(test_name):
gstepanov9eb8bf32015-02-11 20:13:14 +0200120 tests = []
121 header_keys = ['build_id', 'iso_md5', 'type', 'date']
gstepanov0a8fdd32015-02-05 15:54:11 +0200122 table = [[]]
gstepanovbdc406b2015-02-11 17:35:55 +0200123 builds = collect_builds()
gstepanova0cb9252015-02-12 17:53:31 +0200124
koder aka kdanilov0f0546c2015-02-17 20:42:05 -0800125 # <koder>: rename
gstepanova0cb9252015-02-12 17:53:31 +0200126 l = filter(lambda x: x['name'] == test_name, builds)
127
128 if l[0]['type'] == 'GA':
129 builds = filter(lambda x: x['type'] == 'GA', builds)
130 else:
131 l.extend(filter(lambda x: x['type'] in ['GA', 'master'] and x not in l, builds))
132 builds = l
133
gstepanovbdc406b2015-02-11 17:35:55 +0200134 results = {}
koder aka kdanilov0f0546c2015-02-17 20:42:05 -0800135 # <koder>: magik ip? fixme
gstepanove1ee9dc2015-02-11 18:09:46 +0200136 meta = {"__meta__": "http://172.16.52.112:8000/api/nodes"}
137 data = collect_lab_data(meta)
138 lab_meta = total_lab_info(data)
gstepanovbdc406b2015-02-11 17:35:55 +0200139
140 for build in builds:
koder aka kdanilov0f0546c2015-02-17 20:42:05 -0800141 # <koder>: don't use name 'type'
gstepanova0cb9252015-02-12 17:53:31 +0200142 type = build['type']
koder aka kdanilov0f0546c2015-02-17 20:42:05 -0800143 results[type] = create_measurement(build)
gstepanovbdc406b2015-02-11 17:35:55 +0200144
koder aka kdanilov0f0546c2015-02-17 20:42:05 -0800145 urls = build_vertical_bar(results) + build_lines_chart(results)
gstepanov6ce6bf02015-02-16 19:04:14 +0200146
147 urls = [url_for("get_image", image_name=os.path.basename(url)) if not url.startswith('http') else url for url in urls]
148
gstepanov2164d822015-02-04 19:49:40 +0200149 if len(tests) > 0:
150 sorted_keys = sorted(tests[0].keys())
151
gstepanov0a8fdd32015-02-05 15:54:11 +0200152 for key in sorted_keys:
153 if key not in header_keys:
154 header_keys.append(key)
gstepanov2164d822015-02-04 19:49:40 +0200155
gstepanov0a8fdd32015-02-05 15:54:11 +0200156 for test in tests:
157 row = []
gstepanov2164d822015-02-04 19:49:40 +0200158
gstepanov0a8fdd32015-02-05 15:54:11 +0200159 for header in header_keys:
160 if isinstance(test[header], list):
koder aka kdanilov0f0546c2015-02-17 20:42:05 -0800161 # <koder>: make a named constant from unichr(0x00B1)
162 # <koder>: use format in this line
gstepanov0a8fdd32015-02-05 15:54:11 +0200163 row.append(str(test[header][0]) + unichr(0x00B1) + str(test[header][1]))
164 else:
165 row.append(test[header])
gstepanov2164d822015-02-04 19:49:40 +0200166
gstepanov0a8fdd32015-02-05 15:54:11 +0200167 table.append(row)
gstepanov2164d822015-02-04 19:49:40 +0200168
gstepanov9eb8bf32015-02-11 20:13:14 +0200169 return render_template("test.html", urls=urls, table_url=url_for('render_table', test_name=test_name),
170 index_url=url_for('index'), lab_meta=lab_meta)
gstepanovcd77d5a2015-02-06 14:49:34 +0200171
172
173@app.route("/tests/table/<test_name>/")
174def render_table(test_name):
gstepanovbdc406b2015-02-11 17:35:55 +0200175 builds = collect_builds()
gstepanov6e4a7eb2015-02-12 17:57:59 +0200176 l = filter(lambda x: x['name'] == test_name, builds)
177 if l[0]['type'] == 'GA':
178 builds = filter(lambda x: x['type'] == 'GA', builds)
gstepanov3ce37b82015-02-12 16:20:56 +0200179 else:
gstepanov6e4a7eb2015-02-12 17:57:59 +0200180 l.extend(filter(lambda x: x['type'] in ['GA', 'master'] and x not in l, builds))
181 builds = l
gstepanov3ce37b82015-02-12 16:20:56 +0200182
gstepanov9eb8bf32015-02-11 20:13:14 +0200183 header_keys = ['build_id', 'iso_md5', 'type' ,'date']
gstepanovcd77d5a2015-02-06 14:49:34 +0200184 table = [[]]
gstepanov94531b82015-02-11 14:20:34 +0200185 meta = {"__meta__": "http://172.16.52.112:8000/api/nodes"}
gstepanove1ee9dc2015-02-11 18:09:46 +0200186 data = collect_lab_data(meta)
gstepanovbdc406b2015-02-11 17:35:55 +0200187
188 if len(builds) > 0:
189 sorted_keys = sorted(builds[0].keys())
gstepanovcd77d5a2015-02-06 14:49:34 +0200190
191 for key in sorted_keys:
192 if key not in header_keys:
193 header_keys.append(key)
194
gstepanovbdc406b2015-02-11 17:35:55 +0200195 for test in builds:
gstepanovcd77d5a2015-02-06 14:49:34 +0200196 row = []
197
198 for header in header_keys:
199 if isinstance(test[header], list):
200 row.append(str(test[header][0]) + unichr(0x00B1) + str(test[header][1]))
201 else:
202 row.append(test[header])
203
204 table.append(row)
205
gstepanovbb854922015-02-09 18:18:17 +0200206 return render_template("table.html", headers=header_keys, table=table,
207 back_url=url_for('render_test', test_name=test_name), lab=data)
gstepanov2164d822015-02-04 19:49:40 +0200208
209
gstepanov3ce37b82015-02-12 16:20:56 +0200210@app.route("/api/tests/<test_name>", methods=['POST'])
gstepanov2164d822015-02-04 19:49:40 +0200211def add_test(test_name):
gstepanov6c5deb32015-02-12 19:25:46 +0200212 test = json.loads(request.data)
gstepanov2164d822015-02-04 19:49:40 +0200213
gstepanov6c5deb32015-02-12 19:25:46 +0200214 file_name = TEST_PATH + '/' + 'storage' + ".json"
gstepanov2164d822015-02-04 19:49:40 +0200215
gstepanov6c5deb32015-02-12 19:25:46 +0200216 if not os.path.exists(file_name):
217 with open(file_name, "w+") as f:
218 f.write(json.dumps([]))
219
220 builds = collect_builds()
221 res = None
222
223 for b in builds:
224 if b['name'] == test['name']:
225 res = b
226 break
227
228 if res is None:
229 builds.append(test)
230 else:
231 merge_builds(res, test)
232
233 with open(TEST_PATH + '/' + 'storage' + ".json", 'w+') as f:
koder aka kdanilov0f0546c2015-02-17 20:42:05 -0800234 f.write(json.dumps(builds))
gstepanov6c5deb32015-02-12 19:25:46 +0200235
gstepanov2164d822015-02-04 19:49:40 +0200236 return "Created", 201
237
238
gstepanov3ce37b82015-02-12 16:20:56 +0200239@app.route("/api/tests", methods=['GET'])
240def get_all_tests():
241 return json.dumps(collect_builds())
242
243
244@app.route("/api/tests/<test_name>", methods=['GET'])
245def get_test(test_name):
246 builds = collect_builds()
247
248 for build in builds:
249 if build["type"] == test_name:
250 return json.dumps(build)
251 return "Not Found", 404
252
253
gstepanov2164d822015-02-04 19:49:40 +0200254if __name__ == "__main__":
gstepanov81a52ee2015-02-10 16:22:20 +0200255 logger = getLogger("logger")
256 app.logger.setLevel(INFO)
257 app.logger.addHandler(logger)
koder aka kdanilov0f0546c2015-02-17 20:42:05 -0800258 app.run(host='0.0.0.0', debug=True)