blob: 00c108448e0e65096908706116af9706e6455e98 [file] [log] [blame]
gstepanov94531b82015-02-11 14:20:34 +02001from urlparse import urlparse
gstepanov2164d822015-02-04 19:49:40 +02002from flask import Flask, render_template, url_for, request, g
3from 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
gstepanov94531b82015-02-11 14:20:34 +020011from web_app.keystone import KeystoneAuth
gstepanov2164d822015-02-04 19:49:40 +020012
13app = Flask(__name__)
14Bootstrap(app)
15
16
gstepanov3ce37b82015-02-12 16:20:56 +020017def get_resource_as_string(name, charset='utf-8'):
18 with app.open_resource(name) as f:
19 return f.read().decode(charset)
20
21app.jinja_env.globals['get_resource_as_string'] = get_resource_as_string
22
23
gstepanov9ddc18f2015-02-11 20:28:59 +020024def load_test(test_name):
25 test_name += '.json'
26
27 with open(TEST_PATH + "/" + test_name, 'rt') as f:
28 raw = f.read()
29
30 if raw != "":
31 test = json.loads(raw)
32 else:
33 test = []
34 import time
35 creation_time = os.path.getmtime(TEST_PATH + "/" + test_name)
36
37 for t in test:
38 t['date'] = time.ctime(creation_time)
39
40 return test
41
42
gstepanov2164d822015-02-04 19:49:40 +020043def collect_tests():
44 result = []
45
gstepanovc3ffac72015-02-05 15:39:45 +020046 for file in os.listdir(TEST_PATH):
gstepanov2164d822015-02-04 19:49:40 +020047 if file.endswith(".json"):
48 result.append(file.split('.')[0])
49
50 return result
51
52
gstepanovbdc406b2015-02-11 17:35:55 +020053def collect_builds():
54 builds = []
55 build_set = set()
56 tests = collect_tests()
57
58 for t in tests:
59 test = load_test(t)
60
61 for build in test:
62 if build["type"] not in build_set:
63 build_set.add(build["type"])
64 builds.append(build)
65
66 return builds
67
68
gstepanov9eb8bf32015-02-11 20:13:14 +020069def builds_list():
gstepanov2164d822015-02-04 19:49:40 +020070 data = []
gstepanovbdc406b2015-02-11 17:35:55 +020071
72 for build in collect_builds():
gstepanov2164d822015-02-04 19:49:40 +020073 d = {}
gstepanov612159f2015-02-12 17:15:29 +020074 d["type"] = build['type']
gstepanova0cb9252015-02-12 17:53:31 +020075 d["url"] = url_for("render_test", test_name=build['name'])
gstepanov9eb8bf32015-02-11 20:13:14 +020076 d["date"] = build['date']
gstepanovdff5ad92015-02-12 17:13:09 +020077 d["name"] = build['name']
gstepanov2164d822015-02-04 19:49:40 +020078 data.append(d)
79
gstepanov9eb8bf32015-02-11 20:13:14 +020080 return data
81
gstepanov2164d822015-02-04 19:49:40 +020082
gstepanovbdc406b2015-02-11 17:35:55 +020083def create_measurement(build):
84 m = Measurement()
85 m.build = build.pop("build_id")
86 m.build_type = build.pop("type")
87 m.md5 = build.pop("iso_md5")
gstepanov9eb8bf32015-02-11 20:13:14 +020088 m.date = build.pop("date")
gstepanovdff5ad92015-02-12 17:13:09 +020089 m.date = build.pop("name")
gstepanovbdc406b2015-02-11 17:35:55 +020090 m.results = {k: v for k, v in build.items()}
91
92 return m
93
94
gstepanove1ee9dc2015-02-11 18:09:46 +020095def total_lab_info(data):
96 d = {}
97 d['nodes_count'] = len(data['nodes'])
98 d['total_memory'] = 0
99 d['total_disk'] = 0
100 d['processor_count'] = 0
101
102 for node in data['nodes']:
103 d['total_memory'] += node['memory']['total']
104 d['processor_count'] += len(node['processors'])
105
106 for disk in node['disks']:
107 d['total_disk'] += disk['size']
108
gstepanov9eb8bf32015-02-11 20:13:14 +0200109 to_gb = lambda x: x / (1024 ** 3)
110 d['total_memory'] = format(to_gb(d['total_memory']), ',d')
111 d['total_disk'] = format(to_gb(d['total_disk']), ',d')
gstepanove1ee9dc2015-02-11 18:09:46 +0200112 return d
113
gstepanov9eb8bf32015-02-11 20:13:14 +0200114
gstepanov9ddc18f2015-02-11 20:28:59 +0200115def collect_lab_data(meta):
116 u = urlparse(meta['__meta__'])
117 cred = {"username": "admin", "password": "admin", "tenant_name": "admin"}
118 keystone = KeystoneAuth(root_url=meta['__meta__'], creds=cred, admin_node_ip=u.hostname)
119 lab_info = keystone.do(method='get', path="")
120 nodes = []
121 result = {}
122
123 for node in lab_info:
124 d = {}
125 d['name'] = node['name']
126 p = []
127 i = []
128 disks = []
129 devices = []
130
131 for processor in node['meta']['cpu']['spec']:
132 p.append(processor)
133
134 for iface in node['meta']['interfaces']:
135 i.append(iface)
136
137 m = node['meta']['memory'].copy()
138
139 for disk in node['meta']['disks']:
140 disks.append(disk)
141
142 d['memory'] = m
143 d['disks'] = disks
144 d['devices'] = devices
145 d['interfaces'] = i
146 d['processors'] = p
147
148 nodes.append(d)
149
150 result['nodes'] = nodes
151 result['name'] = 'Perf-1 Env'
152
153 return result
154
155
gstepanov6c5deb32015-02-12 19:25:46 +0200156def merge_builds(b1, b2):
157 d = {}
158
159 for pair in b2.items():
gstepanov8053b012015-02-16 17:25:27 +0200160 if pair[0] in b1 and type(pair[1]) is list:
161 b1[pair[0]].extend(pair[1])
162 else:
163 b1[pair[0]] = pair[1]
gstepanov6c5deb32015-02-12 19:25:46 +0200164
165
gstepanov9ddc18f2015-02-11 20:28:59 +0200166@app.route("/", methods=['GET', 'POST'])
167def index():
168 data = builds_list()
169 return render_template("index.html", tests=data)
170
171
gstepanov2164d822015-02-04 19:49:40 +0200172@app.route("/tests/<test_name>", methods=['GET'])
173def render_test(test_name):
gstepanov9eb8bf32015-02-11 20:13:14 +0200174 tests = []
175 header_keys = ['build_id', 'iso_md5', 'type', 'date']
gstepanov0a8fdd32015-02-05 15:54:11 +0200176 table = [[]]
gstepanovbdc406b2015-02-11 17:35:55 +0200177 builds = collect_builds()
gstepanova0cb9252015-02-12 17:53:31 +0200178
179 l = filter(lambda x: x['name'] == test_name, builds)
180
181 if l[0]['type'] == 'GA':
182 builds = filter(lambda x: x['type'] == 'GA', builds)
183 else:
184 l.extend(filter(lambda x: x['type'] in ['GA', 'master'] and x not in l, builds))
185 builds = l
186
gstepanovbdc406b2015-02-11 17:35:55 +0200187 results = {}
gstepanove1ee9dc2015-02-11 18:09:46 +0200188 meta = {"__meta__": "http://172.16.52.112:8000/api/nodes"}
189 data = collect_lab_data(meta)
190 lab_meta = total_lab_info(data)
gstepanovbdc406b2015-02-11 17:35:55 +0200191
192 for build in builds:
gstepanova0cb9252015-02-12 17:53:31 +0200193 type = build['type']
194 m = create_measurement(build)
195 results[type] = m
gstepanovbdc406b2015-02-11 17:35:55 +0200196
gstepanov200d3b42015-02-06 14:01:49 +0200197 bars = build_vertical_bar(results)
198 lines = build_lines_chart(results)
199 urls = bars + lines
gstepanov2164d822015-02-04 19:49:40 +0200200 if len(tests) > 0:
201 sorted_keys = sorted(tests[0].keys())
202
gstepanov0a8fdd32015-02-05 15:54:11 +0200203 for key in sorted_keys:
204 if key not in header_keys:
205 header_keys.append(key)
gstepanov2164d822015-02-04 19:49:40 +0200206
gstepanov0a8fdd32015-02-05 15:54:11 +0200207 for test in tests:
208 row = []
gstepanov2164d822015-02-04 19:49:40 +0200209
gstepanov0a8fdd32015-02-05 15:54:11 +0200210 for header in header_keys:
211 if isinstance(test[header], list):
212 row.append(str(test[header][0]) + unichr(0x00B1) + str(test[header][1]))
213 else:
214 row.append(test[header])
gstepanov2164d822015-02-04 19:49:40 +0200215
gstepanov0a8fdd32015-02-05 15:54:11 +0200216 table.append(row)
gstepanov2164d822015-02-04 19:49:40 +0200217
gstepanov9eb8bf32015-02-11 20:13:14 +0200218 return render_template("test.html", urls=urls, table_url=url_for('render_table', test_name=test_name),
219 index_url=url_for('index'), lab_meta=lab_meta)
gstepanovcd77d5a2015-02-06 14:49:34 +0200220
221
222@app.route("/tests/table/<test_name>/")
223def render_table(test_name):
gstepanovbdc406b2015-02-11 17:35:55 +0200224 builds = collect_builds()
gstepanov6e4a7eb2015-02-12 17:57:59 +0200225 l = filter(lambda x: x['name'] == test_name, builds)
226 if l[0]['type'] == 'GA':
227 builds = filter(lambda x: x['type'] == 'GA', builds)
gstepanov3ce37b82015-02-12 16:20:56 +0200228 else:
gstepanov6e4a7eb2015-02-12 17:57:59 +0200229 l.extend(filter(lambda x: x['type'] in ['GA', 'master'] and x not in l, builds))
230 builds = l
gstepanov3ce37b82015-02-12 16:20:56 +0200231
gstepanov9eb8bf32015-02-11 20:13:14 +0200232 header_keys = ['build_id', 'iso_md5', 'type' ,'date']
gstepanovcd77d5a2015-02-06 14:49:34 +0200233 table = [[]]
gstepanov94531b82015-02-11 14:20:34 +0200234 meta = {"__meta__": "http://172.16.52.112:8000/api/nodes"}
gstepanove1ee9dc2015-02-11 18:09:46 +0200235 data = collect_lab_data(meta)
gstepanovbdc406b2015-02-11 17:35:55 +0200236
237 if len(builds) > 0:
238 sorted_keys = sorted(builds[0].keys())
gstepanovcd77d5a2015-02-06 14:49:34 +0200239
240 for key in sorted_keys:
241 if key not in header_keys:
242 header_keys.append(key)
243
gstepanovbdc406b2015-02-11 17:35:55 +0200244 for test in builds:
gstepanovcd77d5a2015-02-06 14:49:34 +0200245 row = []
246
247 for header in header_keys:
248 if isinstance(test[header], list):
249 row.append(str(test[header][0]) + unichr(0x00B1) + str(test[header][1]))
250 else:
251 row.append(test[header])
252
253 table.append(row)
254
gstepanovbb854922015-02-09 18:18:17 +0200255 return render_template("table.html", headers=header_keys, table=table,
256 back_url=url_for('render_test', test_name=test_name), lab=data)
gstepanov2164d822015-02-04 19:49:40 +0200257
258
gstepanov3ce37b82015-02-12 16:20:56 +0200259@app.route("/api/tests/<test_name>", methods=['POST'])
gstepanov2164d822015-02-04 19:49:40 +0200260def add_test(test_name):
gstepanov6c5deb32015-02-12 19:25:46 +0200261 test = json.loads(request.data)
gstepanov2164d822015-02-04 19:49:40 +0200262
gstepanov6c5deb32015-02-12 19:25:46 +0200263 file_name = TEST_PATH + '/' + 'storage' + ".json"
gstepanov2164d822015-02-04 19:49:40 +0200264
gstepanov6c5deb32015-02-12 19:25:46 +0200265 if not os.path.exists(file_name):
266 with open(file_name, "w+") as f:
267 f.write(json.dumps([]))
268
269 builds = collect_builds()
270 res = None
271
272 for b in builds:
273 if b['name'] == test['name']:
274 res = b
275 break
276
277 if res is None:
278 builds.append(test)
279 else:
280 merge_builds(res, test)
281
282 with open(TEST_PATH + '/' + 'storage' + ".json", 'w+') as f:
283 f.write(json.dumps(builds))
284
gstepanov2164d822015-02-04 19:49:40 +0200285 return "Created", 201
286
287
gstepanov3ce37b82015-02-12 16:20:56 +0200288@app.route("/api/tests", methods=['GET'])
289def get_all_tests():
290 return json.dumps(collect_builds())
291
292
293@app.route("/api/tests/<test_name>", methods=['GET'])
294def get_test(test_name):
295 builds = collect_builds()
296
297 for build in builds:
298 if build["type"] == test_name:
299 return json.dumps(build)
300 return "Not Found", 404
301
302
gstepanov2164d822015-02-04 19:49:40 +0200303if __name__ == "__main__":
gstepanov81a52ee2015-02-10 16:22:20 +0200304 logger = getLogger("logger")
305 app.logger.setLevel(INFO)
306 app.logger.addHandler(logger)
gstepanov6f7167d2015-02-06 12:51:58 +0200307 app.run(host='0.0.0.0', debug=True)