blob: a1503d4a7fc3bd381359b345c532fa736bd7a71e [file] [log] [blame]
stgleb75c70412015-02-17 02:52:00 +02001import datetime
2import math
gstepanov15681d62015-02-23 17:17:50 +02003from urlparse import urlparse
stgleb75c70412015-02-17 02:52:00 +02004
5from flask import json
gstepanov15681d62015-02-23 17:17:50 +02006from persistance.keystone import KeystoneAuth
stgleb75c70412015-02-17 02:52:00 +02007from sqlalchemy import sql
8from persistance.models import *
9
10
11#class displays measurement. Moved from storage_api_v_1 to avoid circular imports.
12class Measurement(object):
13 def __init__(self):
14 self.build = ""
15 self.build_type = 0 # GA/Master/Other
16 self.md5 = ""
17 self.name = ""
18 self.date = None
19 self.results = {
20 "": (float, float)
21 }
22
23 def __str__(self):
24 return self.build + " " + self.build_type + " " + \
25 self.md5 + " " + str(self.results)
26
27
28def mean(l):
29 n = len(l)
30
31 return sum(l) / n
32
33
34def stdev(l):
35 m = mean(l)
36 return math.sqrt(sum(map(lambda x: (x - m) ** 2, l)))
37
38
gstepanov15681d62015-02-23 17:17:50 +020039
40def total_lab_info(data):
41 # <koder>: give 'd' meaningful name
42 d = {}
43 d['nodes_count'] = len(data['nodes'])
44 d['total_memory'] = 0
45 d['total_disk'] = 0
46 d['processor_count'] = 0
47
48 for node in data['nodes']:
49 d['total_memory'] += node['memory']['total']
50 d['processor_count'] += len(node['processors'])
51
52 for disk in node['disks']:
53 d['total_disk'] += disk['size']
54
55 to_gb = lambda x: x / (1024 ** 3)
56 d['total_memory'] = format(to_gb(d['total_memory']), ',d')
57 d['total_disk'] = format(to_gb(d['total_disk']), ',d')
58 return d
59
60
61def collect_lab_data(url, cred):
62 u = urlparse(url)
63 keystone = KeystoneAuth(root_url=url, creds=cred, admin_node_ip=u.hostname)
64 lab_info = keystone.do(method='get', path="/api/nodes")
65 fuel_version = keystone.do(method='get', path="/api/version/")
66
67 nodes = []
68 result = {}
69
70 for node in lab_info:
71 # <koder>: give p,i,d,... vars meaningful names
72 d = {}
73 d['name'] = node['name']
74 p = []
75 i = []
76 disks = []
77 devices = []
78
79 for processor in node['meta']['cpu']['spec']:
80 p.append(processor)
81
82 for iface in node['meta']['interfaces']:
83 i.append(iface)
84
85 m = node['meta']['memory'].copy()
86
87 for disk in node['meta']['disks']:
88 disks.append(disk)
89
90 d['memory'] = m
91 d['disks'] = disks
92 d['devices'] = devices
93 d['interfaces'] = i
94 d['processors'] = p
95
96 nodes.append(d)
97
98 result['nodes'] = nodes
99 # result['name'] = 'Perf-1 Env'
100 result['fuel_version'] = fuel_version['release']
101
102 return result
103
104
105def get_build_info(build_name):
106 session = db.session()
107 result = session.query(Result, Build).join(Build).filter(Build.name == build_name).first()
108 lab = session.query(Lab).filter(Lab.id == result[0].lab_id).first()
109 return eval(lab.lab_general_info)
110
111
112def get_build_detailed_info(build_name):
113 data = get_build_info(build_name)
114 return total_lab_info(data)
115
116
stgleb75c70412015-02-17 02:52:00 +0200117def process_build_data(build):
118 for item in build.items():
119 if type(item[1]) is list:
120 m = mean(item[1])
121 s = stdev(item[1])
122 build[item[0]] = [m, s]
123
124
125#filling Param table with initial parameters.
126def add_io_params(session):
127 param1 = Param(name="operation", type='{"write", "randwrite", "read", "randread"}', descr="type of write operation")
128 param2 = Param(name="sync", type='{"a", "s"}', descr="Write mode synchronous/asynchronous")
129 param3 = Param(name="block size", type='{"1k", "2k", "4k", "8k", "16k", "32k", "64k", "128k", "256k"}')
130
131 session.add(param1)
132 session.add(param2)
133 session.add(param3)
134
135 session.commit()
136
137
138#function which adds particular build to database.
139def add_build(session, build_id, build_name, build_type, md5):
140 build = Build(type=build_type, build_id=build_id, name=build_name, md5=md5)
141 session.add(build)
142 session.commit()
143
144 return build.id
145
146
147#function insert particular result.
148def insert_results(session, build_id, lab_id, params_combination_id,
149 time=None, bandwith=0.0, meta=""):
150 result = Result(build_id=build_id, lab_id=lab_id, params_combination_id=params_combination_id, time=time,
151 bandwith=bandwith, meta=meta)
152 session.add(result)
153 session.commit()
154
155
156#function responsible for adding particular params combination to database
157def add_param_comb(session, *params):
158 params_names = sorted([s for s in dir(ParamCombination) if s.startswith('param_')])
159 d = zip(params_names, params)
160 where = ""
161
162 for item in d:
163 where = sql.and_(where, getattr(ParamCombination, item[0]) == item[1])
164
165 query = session.query(ParamCombination).filter(where)
166 rs = session.execute(query).fetchall()
167
168
169 if len(rs) == 0:
170 param_comb = ParamCombination()
171
172 for p in params_names:
173 i = int(p.split('_')[1])
174 param_comb.__setattr__('param_' + str(i), params[i - 1])
175
176 param = session.query(Param).filter(Param.id == i).one()
177 values = eval(param.type)
178
179 if params[i - 1] not in values:
180 values.add(params[i - 1])
181 param.type = str(values)
182
183 session.add(param_comb)
184 session.commit()
185 return param_comb.id
186 else:
187 return rs[0][0]
188
189
gstepanov15681d62015-02-23 17:17:50 +0200190def add_lab(session, lab_url, lab_name, ceph_version, fuel_version, data, info):
191 result = session.query(Lab).filter(Lab.name == lab_name).all()
stgleb75c70412015-02-17 02:52:00 +0200192
gstepanov15681d62015-02-23 17:17:50 +0200193 if len(result) != 0:
194 return result[0].id
195 else:
196 lab = Lab(name=lab_name, url=lab_url, ceph_version=ceph_version,
197 fuel_version=fuel_version, lab_general_info=str(data), lab_meta=str(info))
198 session.add(lab)
199 session.commit()
200 return lab.id
stgleb75c70412015-02-17 02:52:00 +0200201
202#function store list of builds in database
203def add_data(data):
204 data = json.loads(data)
205 session = db.session()
206 add_io_params(session)
207
208 for build_data in data:
209 build_id = add_build(session,
210 build_data.pop("build_id"),
211 build_data.pop("name"),
212 build_data.pop("type"),
213 build_data.pop("iso_md5"),
214 )
gstepanov15681d62015-02-23 17:17:50 +0200215 creds = {"username": build_data.pop("username"),
216 "password": build_data.pop("password"),
217 "tenant_name": build_data.pop("tenant_name")
218 }
219 lab_url = build_data.pop("lab_url")
220 lab_name = build_data.pop("lab_name")
221 ceph_version = build_data.pop("ceph_version")
222 data = collect_lab_data(lab_url, creds)
223 data['name'] = lab_name
224 info = total_lab_info(data)
225 lab_id = add_lab(session, lab_url=lab_name, lab_name=lab_url,
226 ceph_version=ceph_version, fuel_version=data['fuel_version'], data=data, info=info)
227
stgleb75c70412015-02-17 02:52:00 +0200228 date = build_data.pop("date")
229 date = datetime.datetime.strptime(date, "%a %b %d %H:%M:%S %Y")
230
231 for params, [bw, dev] in build_data.items():
232 param_comb_id = add_param_comb(session, *params.split(" "))
gstepanov15681d62015-02-23 17:17:50 +0200233 result = Result(param_combination_id=param_comb_id, build_id=build_id,
234 bandwith=bw, date=date, lab_id=lab_id)
stgleb75c70412015-02-17 02:52:00 +0200235 session.add(result)
236 session.commit()
237
238
239#function loads data by parametres described in *params tuple.
240def load_data(*params):
241 session = db.session()
242 params_names = sorted([s for s in dir(ParamCombination) if s.startswith('param_')])
243 d = zip(params_names, params)
244 where = ""
245
246 for item in d:
247 where = sql.and_(where, getattr(ParamCombination, item[0]) == item[1])
248
249 query = session.query(ParamCombination).filter(where)
250 rs = session.execute(query).fetchall()
251
252 ids = [r[0] for r in rs]
253
254 results = session.query(Result).filter(Result.param_combination_id.in_(ids))
255 rs = session.execute(results).fetchall()
256
257 return [r[5] for r in rs]
258
259
260#load all builds from database
261def load_all():
262 session = db.session()
263 r = session.query(Param).filter(Param.id == 1).all()
264 results = session.query(Result, Build, ParamCombination).join(Build).join(ParamCombination).all()
265
266 return results
267
268
269#function collecting all builds from database and filter it by names
270def collect_builds_from_db(*names):
271 results = load_all()
272 d = {}
273
274 for item in results:
275 result_data = item[0]
276 build_data = item[1]
277 param_combination_data = item[2]
278
279 if build_data.name not in d:
280 d[build_data.name] = [build_data, result_data, param_combination_data]
281 else:
282 d[build_data.name].append(result_data)
283 d[build_data.name].append(param_combination_data)
284
285 if len(names) == 0:
286 return {k: v for k, v in d.items()}
287
288 return {k: v for k, v in d.items() if k in names}
289
290
291#function creates measurement from data was extracted from database.
292def create_measurement(data):
293 build_data = data[0]
294
295 m = Measurement()
296 m.build = build_data.build_id
297 m.build_type = build_data.type
298 m.name = build_data.name
299 m.results = {}
300
301 for i in range(1, len(data), 2):
302 result = data[i]
303 param_combination = data[i + 1]
304
305 if not str(param_combination) in m.results:
306 m.results[str(param_combination)] = [result.bandwith]
307 else:
308 m.results[str(param_combination)] += [result.bandwith]
309
310 for k in m.results.keys():
311 m.results[k] = [mean(m.results[k]), stdev(m.results[k])]
312
313 return m
314
315
316#function preparing data for display plots.
317#Format {build_name : Measurement}
318def prepare_build_data(build_name):
319 session = db.session()
320 build = session.query(Build).filter(Build.name == build_name).first()
321 names = []
322
323 if build.type == 'GA':
324 names = [build_name]
325 else:
326 res = session.query(Build).filter(Build.type.in_(['GA', 'master', build.type])).all()
327 for r in res:
328 names.append(r.name)
329
330
331 d = collect_builds_from_db()
332 d = {k: v for k, v in d.items() if k in names}
333 results = {}
334
335 for data in d.keys():
336 m = create_measurement(d[data])
337 results[m.build_type] = m
338
339 return results
340
341
342#function getting list of all builds available to index page
343#returns list of dicts which contains data to display on index page.
344def builds_list():
345 res = []
346 builds = set()
347 data = load_all()
348
349 for item in data:
350 build = item[1]
351 result = item[0]
352
353 if not build.name in builds:
354 builds.add(build.name)
355 d = {}
356 d["type"] = build.type
357 d["url"] = build.name
358 d["date"] = result.date
359 d["name"] = build.name
360 res.append(d)
361
362 return res
363
364
365#Processing data from database.
366#List of dicts, where each dict contains build meta info and kev-value measurements.
367#key - param combination.
368#value - [mean, deviation]
369def get_builds_data(names=None):
370 d = collect_builds_from_db()
371
372 if not names is None:
373 d = {k: v for k, v in d.items() if k in names}
374 else:
375 d = {k: v for k, v in d.items()}
376 output = []
377
378 for key, value in d.items():
379 result = {}
380 build = value[0]
381 result["build_id"] = build.build_id
382 result["iso_md5"] = build.md5
383 result["type"] = build.type
384 result["date"] = "Date must be here"
385
386 for i in range(1, len(value), 2):
387 r = value[i]
388 param_combination = value[i + 1]
389
390 if not str(param_combination) in result:
391 result[str(param_combination)] = [r.bandwith]
392 else:
393 result[str(param_combination)].append(r.bandwith)
394
395 output.append(result)
396
397 for build in output:
398 process_build_data(build)
399
400 return output
401
402
403#Function for getting result to display table
404def get_data_for_table(build_name=""):
405 session = db.session()
406 build = session.query(Build).filter(Build.name == build_name).one()
407 names = []
408
409 #Get names of build that we need.
410 if build.type == 'GA':
411 names = [build_name]
412 else:
413 res = session.query(Build).filter(Build.type.in_(['GA', 'master', build.type])).all()
414 for r in res:
415 names.append(r.name)
416 #get data for particular builds.
417 return get_builds_data(names)
418
419
420if __name__ == '__main__':
421 # add_build("Some build", "GA", "bla bla")
gstepanov15681d62015-02-23 17:17:50 +0200422 cred = {"username": "admin", "password": "admin", "tenant_name": "admin"}
stgleb75c70412015-02-17 02:52:00 +0200423 json_data = '[{\
gstepanov15681d62015-02-23 17:17:50 +0200424 "username": "admin",\
425 "password": "admin", \
426 "tenant_name": "admin",\
427 "lab_url": "http://172.16.52.112:8000",\
428 "lab_name": "Perf-1-Env",\
429 "ceph_version": "v0.80 Firefly",\
stgleb75c70412015-02-17 02:52:00 +0200430 "randwrite a 256k": [16885, 1869],\
431 "randwrite s 4k": [79, 2],\
432 "read a 64k": [74398, 11618],\
433 "write s 1024k": [7490, 193],\
434 "randwrite a 64k": [14167, 4665],\
435 "build_id": "1",\
436 "randread a 1024k": [68683, 8604],\
437 "randwrite s 256k": [3277, 146],\
438 "write a 1024k": [24069, 660],\
439 "type": "GA",\
440 "write a 64k": [24555, 1006],\
441 "write s 64k": [1285, 57],\
442 "write a 256k": [24928, 503],\
443 "write s 256k": [4029, 192],\
444 "randwrite a 1024k": [23980, 1897],\
445 "randread a 64k": [27257, 17268],\
446 "randwrite s 1024k": [8504, 238],\
447 "randread a 256k": [60868, 2637],\
448 "randread a 4k": [3612, 1355],\
449 "read a 1024k": [71122, 9217],\
450 "date": "Thu Feb 12 19:11:56 2015",\
451 "write s 4k": [87, 3],\
452 "read a 4k": [88367, 6471],\
453 "read a 256k": [80904, 8930],\
454 "name": "GA - 6.0 GA",\
455 "randwrite s 1k": [20, 0],\
456 "randwrite s 64k": [1029, 34],\
457 "write s 1k": [21, 0],\
458 "iso_md5": "bla bla"\
459 },\
460 {\
gstepanov15681d62015-02-23 17:17:50 +0200461 "username": "admin",\
462 "password": "admin", \
463 "tenant_name": "admin",\
464 "lab_url": "http://172.16.52.112:8000",\
465 "ceph_version": "v0.80 Firefly",\
466 "lab_name": "Perf-1-Env",\
stgleb75c70412015-02-17 02:52:00 +0200467 "randwrite a 256k": [20212, 5690],\
468 "randwrite s 4k": [83, 6],\
469 "read a 64k": [89394, 3912],\
470 "write s 1024k": [8054, 280],\
471 "randwrite a 64k": [14595, 3245],\
472 "build_id": "2",\
473 "randread a 1024k": [83277, 9310],\
474 "randwrite s 256k": [3628, 433],\
475 "write a 1024k": [29226, 8624],\
476 "type": "master",\
477 "write a 64k": [25089, 790],\
478 "write s 64k": [1236, 30],\
479 "write a 256k": [30327, 9799],\
480 "write s 256k": [4049, 172],\
481 "randwrite a 1024k": [29000, 9302],\
482 "randread a 64k": [26775, 16319],\
483 "randwrite s 1024k": [8665, 1457],\
484 "randread a 256k": [63608, 16126],\
485 "randread a 4k": [3212, 1620],\
486 "read a 1024k": [89676, 4401],\
487 "date": "Thu Feb 12 19:11:56 2015",\
488 "write s 4k": [88, 3],\
489 "read a 4k": [92263, 5186],\
490 "read a 256k": [94505, 6868],\
491 "name": "6.1 Dev",\
492 "randwrite s 1k": [22, 3],\
493 "randwrite s 64k": [1105, 46],\
494 "write s 1k": [22, 0],\
495 "iso_md5": "bla bla"\
496 },\
497 {\
gstepanov15681d62015-02-23 17:17:50 +0200498 "username": "admin",\
499 "password": "admin", \
500 "tenant_name": "admin",\
501 "lab_url": "http://172.16.52.112:8000",\
502 "ceph_version": "v0.80 Firefly",\
503 "lab_name": "Perf-1-Env",\
stgleb75c70412015-02-17 02:52:00 +0200504 "randwrite a 256k": [16885, 1869],\
505 "randwrite s 4k": [79, 2],\
506 "read a 64k": [74398, 11618],\
507 "write s 1024k": [7490, 193],\
508 "randwrite a 64k": [14167, 4665],\
509 "build_id": "1",\
510 "randread a 1024k": [68683, 8604],\
511 "randwrite s 256k": [3277, 146],\
512 "write a 1024k": [24069, 660],\
513 "type": "sometype",\
514 "write a 64k": [24555, 1006],\
515 "write s 64k": [1285, 57],\
516 "write a 256k": [24928, 503],\
517 "write s 256k": [4029, 192],\
518 "randwrite a 1024k": [23980, 1897],\
519 "randread a 64k": [27257, 17268],\
520 "randwrite s 1024k": [8504, 238],\
521 "randread a 256k": [60868, 2637],\
522 "randread a 4k": [3612, 1355],\
523 "read a 1024k": [71122, 9217],\
524 "date": "Thu Feb 12 19:11:56 2015",\
525 "write s 4k": [87, 3],\
526 "read a 4k": [88367, 6471],\
527 "read a 256k": [80904, 8930],\
528 "name": "somedev",\
529 "randwrite s 1k": [20, 0],\
530 "randwrite s 64k": [1029, 34],\
531 "write s 1k": [21, 0],\
532 "iso_md5": "bla bla"\
533 }]'
534
535 # json_to_db(json_data)
536 # print load_data()
537 add_data(json_data)
538
539 print collect_builds_from_db()
540 print prepare_build_data('6.1 Dev')
541 print builds_list()
542 print get_data_for_table('somedev')