blob: 7899baecfbd7899964e229fe04ff1f847373cd82 [file] [log] [blame]
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +03001from __future__ import print_function
2
gstepanov023c1e42015-04-08 15:50:19 +03003import os
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -08004import sys
koder aka kdanilov12ae0632015-04-15 01:13:43 +03005import time
koder aka kdanilov2c473092015-03-29 17:12:13 +03006import Queue
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -08007import pprint
koder aka kdanilove21d7472015-02-14 19:02:04 -08008import logging
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -08009import argparse
koder aka kdanilov2c473092015-03-29 17:12:13 +030010import threading
11import collections
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080012
koder aka kdanilov66839a92015-04-11 13:22:31 +030013import yaml
koder aka kdanilov2c473092015-03-29 17:12:13 +030014from concurrent.futures import ThreadPoolExecutor
koder aka kdanilov6c491062015-04-09 22:33:13 +030015
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030016from wally import pretty_yaml
17from wally.discover import discover, Node, undiscover
18from wally import utils, report, ssh_utils, start_vms
19from wally.suits.itest import IOPerfTest, PgBenchTest
20from wally.config import cfg_dict, load_config, setup_loggers
21from wally.sensors.api import (start_monitoring,
22 deploy_and_start_sensors,
23 SensorConfig)
koder aka kdanilov2c473092015-03-29 17:12:13 +030024
25
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030026logger = logging.getLogger("wally")
koder aka kdanilovcee43342015-04-14 22:52:53 +030027
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080028
Yulia Portnova7ddfa732015-02-24 17:32:58 +020029def format_result(res, formatter):
koder aka kdanilove21d7472015-02-14 19:02:04 -080030 data = "\n{0}\n".format("=" * 80)
31 data += pprint.pformat(res) + "\n"
32 data += "{0}\n".format("=" * 80)
koder aka kdanilovfe056622015-02-19 08:46:15 -080033 templ = "{0}\n\n====> {1}\n\n{2}\n\n"
Yulia Portnova7ddfa732015-02-24 17:32:58 +020034 return templ.format(data, formatter(res), "=" * 80)
koder aka kdanilove21d7472015-02-14 19:02:04 -080035
36
koder aka kdanilov1c2b5112015-04-10 16:53:51 +030037class Context(object):
38 def __init__(self):
39 self.build_meta = {}
40 self.nodes = []
41 self.clear_calls_stack = []
42 self.openstack_nodes_ids = []
koder aka kdanilov4500a5f2015-04-17 16:55:17 +030043 self.sensor_cm = None
44 self.keep_vm = False
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030045 self.sensors_control_queue = None
46 self.sensor_listen_thread = None
koder aka kdanilov1c2b5112015-04-10 16:53:51 +030047
48
koder aka kdanilov5d589b42015-03-26 12:25:51 +020049def connect_one(node):
50 try:
koder aka kdanilov2c473092015-03-29 17:12:13 +030051 ssh_pref = "ssh://"
52 if node.conn_url.startswith(ssh_pref):
53 url = node.conn_url[len(ssh_pref):]
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030054 logger.debug("Try connect to " + url)
koder aka kdanilov2c473092015-03-29 17:12:13 +030055 node.connection = ssh_utils.connect(url)
56 else:
57 raise ValueError("Unknown url type {0}".format(node.conn_url))
koder aka kdanilov3a6633e2015-03-26 18:20:00 +020058 except Exception:
koder aka kdanilov2c473092015-03-29 17:12:13 +030059 logger.exception("During connect to {0}".format(node))
koder aka kdanilov652cd802015-04-13 12:21:07 +030060 raise
koder aka kdanilov5d589b42015-03-26 12:25:51 +020061
62
63def connect_all(nodes):
koder aka kdanilov2c473092015-03-29 17:12:13 +030064 logger.info("Connecting to nodes")
65 with ThreadPoolExecutor(32) as pool:
66 list(pool.map(connect_one, nodes))
koder aka kdanilovda45e882015-04-06 02:24:42 +030067 logger.info("All nodes connected successfully")
koder aka kdanilov2c473092015-03-29 17:12:13 +030068
69
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030070def save_sensors_data(q, mon_q, fd):
koder aka kdanilov2c473092015-03-29 17:12:13 +030071 logger.info("Start receiving sensors data")
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030072 fd.write("\n")
73
74 observed_nodes = set()
75
76 try:
77 while True:
78 val = q.get()
79 if val is None:
80 break
81
82 addr, data = val
83 if addr not in observed_nodes:
84 mon_q.put(addr)
85 observed_nodes.add(addr)
86
87 fd.write("{0!s} : {1!r}\n".format(time.time(), repr(val)))
88 except Exception:
89 logger.exception("Error in sensors thread")
koder aka kdanilov2c473092015-03-29 17:12:13 +030090 logger.info("Sensors thread exits")
91
92
koder aka kdanilov652cd802015-04-13 12:21:07 +030093def test_thread(test, node, barrier, res_q):
koder aka kdanilov2c473092015-03-29 17:12:13 +030094 try:
95 logger.debug("Run preparation for {0}".format(node.conn_url))
96 test.pre_run(node.connection)
97 logger.debug("Run test for {0}".format(node.conn_url))
98 test.run(node.connection, barrier)
koder aka kdanilov652cd802015-04-13 12:21:07 +030099 except Exception as exc:
koder aka kdanilov2c473092015-03-29 17:12:13 +0300100 logger.exception("In test {0} for node {1}".format(test, node))
koder aka kdanilov652cd802015-04-13 12:21:07 +0300101 res_q.put(exc)
koder aka kdanilov2c473092015-03-29 17:12:13 +0300102
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300103 try:
104 test.cleanup(node.connection)
105 except:
106 msg = "Duringf cleanup - in test {0} for node {1}"
107 logger.exception(msg.format(test, node))
108
koder aka kdanilov2c473092015-03-29 17:12:13 +0300109
koder aka kdanilovcee43342015-04-14 22:52:53 +0300110def run_tests(test_block, nodes):
koder aka kdanilov2c473092015-03-29 17:12:13 +0300111 tool_type_mapper = {
112 "io": IOPerfTest,
113 "pgbench": PgBenchTest,
114 }
115
116 test_nodes = [node for node in nodes
117 if 'testnode' in node.roles]
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300118 test_number_per_type = {}
koder aka kdanilov2c473092015-03-29 17:12:13 +0300119 res_q = Queue.Queue()
120
koder aka kdanilovcee43342015-04-14 22:52:53 +0300121 for name, params in test_block.items():
122 logger.info("Starting {0} tests".format(name))
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300123 test_num = test_number_per_type.get(name, 0)
124 test_number_per_type[name] = test_num + 1
koder aka kdanilovcee43342015-04-14 22:52:53 +0300125 threads = []
126 barrier = utils.Barrier(len(test_nodes))
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300127
koder aka kdanilovcee43342015-04-14 22:52:53 +0300128 for node in test_nodes:
129 msg = "Starting {0} test on {1} node"
130 logger.debug(msg.format(name, node.conn_url))
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300131
132 dr = os.path.join(
133 cfg_dict['test_log_directory'],
134 "{0}_{1}_{2}".format(name, test_num, node.get_ip())
135 )
136
137 if not os.path.exists(dr):
138 os.makedirs(dr)
139
140 test = tool_type_mapper[name](params, res_q.put, dr,
141 node=node.get_ip())
koder aka kdanilovcee43342015-04-14 22:52:53 +0300142 th = threading.Thread(None, test_thread, None,
143 (test, node, barrier, res_q))
144 threads.append(th)
145 th.daemon = True
146 th.start()
koder aka kdanilov2c473092015-03-29 17:12:13 +0300147
koder aka kdanilovcee43342015-04-14 22:52:53 +0300148 def gather_results(res_q, results):
149 while not res_q.empty():
150 val = res_q.get()
koder aka kdanilov66839a92015-04-11 13:22:31 +0300151
koder aka kdanilovcee43342015-04-14 22:52:53 +0300152 if isinstance(val, Exception):
153 msg = "Exception during test execution: {0}"
154 raise ValueError(msg.format(val.message))
koder aka kdanilov652cd802015-04-13 12:21:07 +0300155
koder aka kdanilovcee43342015-04-14 22:52:53 +0300156 results.append(val)
koder aka kdanilov652cd802015-04-13 12:21:07 +0300157
koder aka kdanilovcee43342015-04-14 22:52:53 +0300158 results = []
koder aka kdanilov652cd802015-04-13 12:21:07 +0300159
koder aka kdanilovcee43342015-04-14 22:52:53 +0300160 while True:
161 for th in threads:
162 th.join(1)
163 gather_results(res_q, results)
koder aka kdanilov652cd802015-04-13 12:21:07 +0300164
koder aka kdanilovcee43342015-04-14 22:52:53 +0300165 if all(not th.is_alive() for th in threads):
166 break
koder aka kdanilov652cd802015-04-13 12:21:07 +0300167
koder aka kdanilovcee43342015-04-14 22:52:53 +0300168 gather_results(res_q, results)
169 yield name, test.merge_results(results)
koder aka kdanilov2c473092015-03-29 17:12:13 +0300170
171
koder aka kdanilovda45e882015-04-06 02:24:42 +0300172def log_nodes_statistic(_, ctx):
173 nodes = ctx.nodes
koder aka kdanilov2c473092015-03-29 17:12:13 +0300174 logger.info("Found {0} nodes total".format(len(nodes)))
175 per_role = collections.defaultdict(lambda: 0)
176 for node in nodes:
177 for role in node.roles:
178 per_role[role] += 1
179
180 for role, count in sorted(per_role.items()):
181 logger.debug("Found {0} nodes with role {1}".format(count, role))
182
183
koder aka kdanilovda45e882015-04-06 02:24:42 +0300184def connect_stage(cfg, ctx):
185 ctx.clear_calls_stack.append(disconnect_stage)
186 connect_all(ctx.nodes)
187
188
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300189def make_undiscover_stage(clean_data):
190 def undiscover_stage(cfg, ctx):
191 undiscover(clean_data)
192 return undiscover_stage
193
194
koder aka kdanilovda45e882015-04-06 02:24:42 +0300195def discover_stage(cfg, ctx):
koder aka kdanilov652cd802015-04-13 12:21:07 +0300196 if cfg.get('discover') is not None:
koder aka kdanilovda45e882015-04-06 02:24:42 +0300197 discover_objs = [i.strip() for i in cfg['discover'].strip().split(",")]
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300198
199 nodes, clean_data = discover(ctx, discover_objs,
200 cfg['clouds'], cfg['var_dir'])
201 ctx.clear_calls_stack.append(make_undiscover_stage(clean_data))
202 ctx.nodes.extend(nodes)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300203
204 for url, roles in cfg.get('explicit_nodes', {}).items():
205 ctx.nodes.append(Node(url, roles.split(",")))
206
207
208def deploy_sensors_stage(cfg_dict, ctx):
koder aka kdanilovda45e882015-04-06 02:24:42 +0300209 if 'sensors' not in cfg_dict:
210 return
211
212 cfg = cfg_dict.get('sensors')
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300213
214 sensors_configs = []
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300215 monitored_nodes = []
koder aka kdanilovda45e882015-04-06 02:24:42 +0300216
217 for role, sensors_str in cfg["roles_mapping"].items():
218 sensors = [sens.strip() for sens in sensors_str.split(",")]
219
220 collect_cfg = dict((sensor, {}) for sensor in sensors)
221
222 for node in ctx.nodes:
223 if role in node.roles:
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300224 monitored_nodes.append(node)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300225 sens_cfg = SensorConfig(node.connection,
226 node.get_ip(),
227 collect_cfg)
228 sensors_configs.append(sens_cfg)
229
230 if len(monitored_nodes) == 0:
231 logger.info("Nothing to monitor, no sensors would be installed")
232 return
koder aka kdanilovda45e882015-04-06 02:24:42 +0300233
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300234 ctx.receiver_uri = cfg["receiver_uri"]
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300235 nodes_ips = [node.get_ip() for node in monitored_nodes]
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300236 if '{ip}' in ctx.receiver_uri:
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300237 ips = set(map(utils.get_ip_for_target, nodes_ips))
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300238
239 if len(ips) > 1:
240 raise ValueError("Can't select external ip for sensors server")
241
242 if len(ips) == 0:
243 raise ValueError("Can't find any external ip for sensors server")
244
245 ext_ip = list(ips)[0]
246 ctx.receiver_uri = ctx.receiver_uri.format(ip=ext_ip)
247
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300248 ctx.clear_calls_stack.append(remove_sensors_stage)
249 ctx.sensor_cm = start_monitoring(ctx.receiver_uri, sensors_configs)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300250
251 ctx.sensors_control_queue = ctx.sensor_cm.__enter__()
252
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300253 mon_q = Queue.Queue()
254
koder aka kdanilov12ae0632015-04-15 01:13:43 +0300255 fd = open(cfg_dict['sensor_storage'], "w")
koder aka kdanilovda45e882015-04-06 02:24:42 +0300256 th = threading.Thread(None, save_sensors_data, None,
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300257 (ctx.sensors_control_queue, mon_q, fd))
koder aka kdanilovda45e882015-04-06 02:24:42 +0300258 th.daemon = True
259 th.start()
260 ctx.sensor_listen_thread = th
261
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300262 nodes_ips_set = set(nodes_ips)
263 MAX_WAIT_FOR_SENSORS = 10
264 etime = time.time() + MAX_WAIT_FOR_SENSORS
265
266 msg = "Waiting at most {0}s till all {1} nodes starts report sensors data"
267 logger.debug(msg.format(MAX_WAIT_FOR_SENSORS, len(nodes_ips_set)))
268
269 # wait till all nodes start sending data
270 while len(nodes_ips_set) != 0:
271 tleft = etime - time.time()
272 try:
273 data = mon_q.get(True, tleft)
274 ip, port = data
275 except Queue.Empty:
276 msg = "Node {0} not sending any sensor data in {1}s"
277 msg = msg.format(", ".join(nodes_ips_set), MAX_WAIT_FOR_SENSORS)
278 raise RuntimeError(msg)
279
280 if ip not in nodes_ips_set:
281 logger.warning("Receive sensors from extra node: {0}".format(ip))
282
283 nodes_ips_set.remove(ip)
284
koder aka kdanilovda45e882015-04-06 02:24:42 +0300285
286def remove_sensors_stage(cfg, ctx):
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300287 if ctx.sensor_cm is not None:
288 ctx.sensor_cm.__exit__(None, None, None)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300289
290 if ctx.sensors_control_queue is not None:
291 ctx.sensors_control_queue.put(None)
292
293 if ctx.sensor_listen_thread is not None:
294 ctx.sensor_listen_thread.join()
koder aka kdanilovda45e882015-04-06 02:24:42 +0300295
296
koder aka kdanilovcee43342015-04-14 22:52:53 +0300297def get_os_credentials(cfg, ctx, creds_type):
298 creds = None
koder aka kdanilovda45e882015-04-06 02:24:42 +0300299
koder aka kdanilovcee43342015-04-14 22:52:53 +0300300 if creds_type == 'clouds':
301 if 'openstack' in cfg['clouds']:
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300302 os_cfg = cfg['clouds']['openstack']
koder aka kdanilovcee43342015-04-14 22:52:53 +0300303
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300304 tenant = os_cfg['OS_TENANT_NAME'].strip()
305 user = os_cfg['OS_USERNAME'].strip()
306 passwd = os_cfg['OS_PASSWORD'].strip()
307 auth_url = os_cfg['OS_AUTH_URL'].strip()
308
koder aka kdanilovcee43342015-04-14 22:52:53 +0300309 elif 'fuel' in cfg['clouds'] and \
310 'openstack_env' in cfg['clouds']['fuel']:
311 creds = ctx.fuel_openstack_creds
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300312
koder aka kdanilovcee43342015-04-14 22:52:53 +0300313 elif creds_type == 'ENV':
314 user, passwd, tenant, auth_url = start_vms.ostack_get_creds()
315 elif os.path.isfile(creds_type):
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300316 raise NotImplementedError()
317 # user, passwd, tenant, auth_url = start_vms.ostack_get_creds()
koder aka kdanilovcee43342015-04-14 22:52:53 +0300318 else:
319 msg = "Creds {0!r} isn't supported".format(creds_type)
320 raise ValueError(msg)
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300321
koder aka kdanilovcee43342015-04-14 22:52:53 +0300322 if creds is None:
323 creds = {'name': user,
324 'passwd': passwd,
325 'tenant': tenant,
326 'auth_url': auth_url}
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300327
koder aka kdanilovcee43342015-04-14 22:52:53 +0300328 return creds
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300329
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300330
koder aka kdanilovcee43342015-04-14 22:52:53 +0300331def run_tests_stage(cfg, ctx):
332 ctx.results = []
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300333
koder aka kdanilovcee43342015-04-14 22:52:53 +0300334 if 'tests' not in cfg:
335 return
gstepanov023c1e42015-04-08 15:50:19 +0300336
koder aka kdanilovcee43342015-04-14 22:52:53 +0300337 for group in cfg['tests']:
338
339 assert len(group.items()) == 1
340 key, config = group.items()[0]
341
342 if 'start_test_nodes' == key:
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300343 params = config['vm_params'].copy()
koder aka kdanilovcee43342015-04-14 22:52:53 +0300344 os_nodes_ids = []
345
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300346 os_creds_type = config['creds']
koder aka kdanilovcee43342015-04-14 22:52:53 +0300347 os_creds = get_os_credentials(cfg, ctx, os_creds_type)
348
349 start_vms.nova_connect(**os_creds)
350
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300351 logger.info("Preparing openstack")
352 start_vms.prepare_os_subpr(**os_creds)
koder aka kdanilovcee43342015-04-14 22:52:53 +0300353
354 new_nodes = []
355 try:
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300356 params['group_name'] = cfg_dict['run_uuid']
koder aka kdanilovcee43342015-04-14 22:52:53 +0300357 for new_node, node_id in start_vms.launch_vms(params):
358 new_node.roles.append('testnode')
359 ctx.nodes.append(new_node)
360 os_nodes_ids.append(node_id)
361 new_nodes.append(new_node)
362
363 store_nodes_in_log(cfg, os_nodes_ids)
364 ctx.openstack_nodes_ids = os_nodes_ids
365
366 connect_all(new_nodes)
367
koder aka kdanilov12ae0632015-04-15 01:13:43 +0300368 # deploy sensors on new nodes
369 # unify this code
370 if 'sensors' in cfg:
371 sens_cfg = []
372 sensors_str = cfg["sensors"]["roles_mapping"]['testnode']
373 sensors = [sens.strip() for sens in sensors_str.split(",")]
374
375 collect_cfg = dict((sensor, {}) for sensor in sensors)
376 for node in new_nodes:
377 sens_cfg.append((node.connection, collect_cfg))
378
379 uri = cfg["sensors"]["receiver_uri"]
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300380 logger.debug("Installing sensors on vm's")
koder aka kdanilov12ae0632015-04-15 01:13:43 +0300381 deploy_and_start_sensors(uri, None,
382 connected_config=sens_cfg)
383
koder aka kdanilovcee43342015-04-14 22:52:53 +0300384 for test_group in config.get('tests', []):
385 ctx.results.extend(run_tests(test_group, ctx.nodes))
386
387 finally:
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300388 if not ctx.keep_vm:
389 shut_down_vms_stage(cfg, ctx)
koder aka kdanilovcee43342015-04-14 22:52:53 +0300390
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300391 else:
392 ctx.results.extend(run_tests(group, ctx.nodes))
koder aka kdanilovda45e882015-04-06 02:24:42 +0300393
gstepanov023c1e42015-04-08 15:50:19 +0300394
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300395def shut_down_vms_stage(cfg, ctx):
koder aka kdanilov66839a92015-04-11 13:22:31 +0300396 vm_ids_fname = cfg_dict['vm_ids_fname']
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300397 if ctx.openstack_nodes_ids is None:
koder aka kdanilov66839a92015-04-11 13:22:31 +0300398 nodes_ids = open(vm_ids_fname).read().split()
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300399 else:
400 nodes_ids = ctx.openstack_nodes_ids
401
koder aka kdanilov652cd802015-04-13 12:21:07 +0300402 if len(nodes_ids) != 0:
403 logger.info("Removing nodes")
404 start_vms.clear_nodes(nodes_ids)
405 logger.info("Nodes has been removed")
gstepanov023c1e42015-04-08 15:50:19 +0300406
koder aka kdanilov66839a92015-04-11 13:22:31 +0300407 if os.path.exists(vm_ids_fname):
408 os.remove(vm_ids_fname)
gstepanov023c1e42015-04-08 15:50:19 +0300409
koder aka kdanilov66839a92015-04-11 13:22:31 +0300410
411def store_nodes_in_log(cfg, nodes_ids):
412 with open(cfg['vm_ids_fname'], 'w') as fd:
413 fd.write("\n".join(nodes_ids))
gstepanov023c1e42015-04-08 15:50:19 +0300414
415
416def clear_enviroment(cfg, ctx):
koder aka kdanilov66839a92015-04-11 13:22:31 +0300417 if os.path.exists(cfg_dict['vm_ids_fname']):
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300418 shut_down_vms_stage(cfg, ctx)
gstepanov023c1e42015-04-08 15:50:19 +0300419
420
koder aka kdanilovda45e882015-04-06 02:24:42 +0300421def disconnect_stage(cfg, ctx):
koder aka kdanilov652cd802015-04-13 12:21:07 +0300422 ssh_utils.close_all_sessions()
423
koder aka kdanilovda45e882015-04-06 02:24:42 +0300424 for node in ctx.nodes:
425 if node.connection is not None:
426 node.connection.close()
427
428
koder aka kdanilov66839a92015-04-11 13:22:31 +0300429def yamable(data):
430 if isinstance(data, (tuple, list)):
431 return map(yamable, data)
432
433 if isinstance(data, unicode):
434 return str(data)
435
436 if isinstance(data, dict):
437 res = {}
438 for k, v in data.items():
439 res[yamable(k)] = yamable(v)
440 return res
441
442 return data
443
444
445def store_raw_results_stage(cfg, ctx):
446
447 raw_results = os.path.join(cfg_dict['var_dir'], 'raw_results.yaml')
448
449 if os.path.exists(raw_results):
450 cont = yaml.load(open(raw_results).read())
451 else:
452 cont = []
453
454 cont.extend(yamable(ctx.results))
455 raw_data = pretty_yaml.dumps(cont)
456
457 with open(raw_results, "w") as fd:
458 fd.write(raw_data)
459
460
461def console_report_stage(cfg, ctx):
462 for tp, data in ctx.results:
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300463 if 'io' == tp and data is not None:
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300464 print(IOPerfTest.format_for_console(data))
koder aka kdanilov66839a92015-04-11 13:22:31 +0300465
466
koder aka kdanilovda45e882015-04-06 02:24:42 +0300467def report_stage(cfg, ctx):
Yulia Portnova8ca20572015-04-14 14:09:39 +0300468 html_rep_fname = cfg['html_report_file']
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300469
470 try:
471 fuel_url = cfg['clouds']['fuel']['url']
472 except KeyError:
473 fuel_url = None
474
475 try:
476 creds = cfg['clouds']['fuel']['creds']
477 except KeyError:
478 creds = None
479
gstepanov69339ac2015-04-16 20:09:33 +0300480 report.make_io_report(ctx.results, html_rep_fname, fuel_url, creds=creds)
koder aka kdanilov652cd802015-04-13 12:21:07 +0300481
Yulia Portnova8ca20572015-04-14 14:09:39 +0300482 logger.info("Html report were stored in " + html_rep_fname)
koder aka kdanilov652cd802015-04-13 12:21:07 +0300483
484 text_rep_fname = cfg_dict['text_report_file']
485 with open(text_rep_fname, "w") as fd:
486 for tp, data in ctx.results:
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300487 if 'io' == tp and data is not None:
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300488 fd.write(IOPerfTest.format_for_console(data))
koder aka kdanilov652cd802015-04-13 12:21:07 +0300489 fd.write("\n")
490 fd.flush()
491
492 logger.info("Text report were stored in " + text_rep_fname)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300493
494
495def complete_log_nodes_statistic(cfg, ctx):
496 nodes = ctx.nodes
497 for node in nodes:
498 logger.debug(str(node))
499
500
koder aka kdanilov66839a92015-04-11 13:22:31 +0300501def load_data_from(var_dir):
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300502 def load_data_from_file(cfg, ctx):
koder aka kdanilov66839a92015-04-11 13:22:31 +0300503 raw_results = os.path.join(var_dir, 'raw_results.yaml')
504 ctx.results = yaml.load(open(raw_results).read())
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300505 return load_data_from_file
gstepanovcd256d62015-04-07 17:47:32 +0300506
507
koder aka kdanilovcee43342015-04-14 22:52:53 +0300508def parse_args(argv):
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300509 descr = "Disk io performance test suite"
510 parser = argparse.ArgumentParser(prog='wally', description=descr)
koder aka kdanilovcee43342015-04-14 22:52:53 +0300511
512 parser.add_argument("-l", dest='extra_logs',
513 action='store_true', default=False,
514 help="print some extra log info")
koder aka kdanilovcee43342015-04-14 22:52:53 +0300515 parser.add_argument("-b", '--build_description',
516 type=str, default="Build info")
517 parser.add_argument("-i", '--build_id', type=str, default="id")
518 parser.add_argument("-t", '--build_type', type=str, default="GA")
519 parser.add_argument("-u", '--username', type=str, default="admin")
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300520 parser.add_argument("-p", '--post-process-only', metavar="VAR_DIR",
521 help="Only process data from previour run")
522 parser.add_argument("-k", '--keep-vm', action='store_true',
523 help="Don't remove test vm's", default=False)
524 parser.add_argument("config_file")
koder aka kdanilovcee43342015-04-14 22:52:53 +0300525
526 return parser.parse_args(argv[1:])
527
528
koder aka kdanilov3f356262015-02-13 08:06:14 -0800529def main(argv):
koder aka kdanilove06762a2015-03-22 23:32:09 +0200530 opts = parse_args(argv)
koder aka kdanilov2c473092015-03-29 17:12:13 +0300531
koder aka kdanilov66839a92015-04-11 13:22:31 +0300532 if opts.post_process_only is not None:
533 stages = [
534 load_data_from(opts.post_process_only),
535 console_report_stage,
koder aka kdanilov652cd802015-04-13 12:21:07 +0300536 report_stage
koder aka kdanilov66839a92015-04-11 13:22:31 +0300537 ]
538 else:
539 stages = [
540 discover_stage,
541 log_nodes_statistic,
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300542 connect_stage,
koder aka kdanilov66839a92015-04-11 13:22:31 +0300543 deploy_sensors_stage,
544 run_tests_stage,
545 store_raw_results_stage,
546 console_report_stage,
547 report_stage
548 ]
549
koder aka kdanilovcee43342015-04-14 22:52:53 +0300550 load_config(opts.config_file, opts.post_process_only)
koder aka kdanilovf4b82c22015-04-11 13:35:25 +0300551
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300552 if cfg_dict.get('logging', {}).get("extra_logs", False) or opts.extra_logs:
553 level = logging.DEBUG
554 else:
555 level = logging.WARNING
556
557 setup_loggers(level, cfg_dict['log_file'])
koder aka kdanilovf4b82c22015-04-11 13:35:25 +0300558
koder aka kdanilov652cd802015-04-13 12:21:07 +0300559 logger.info("All info would be stored into {0}".format(
560 cfg_dict['var_dir']))
gstepanovcd256d62015-04-07 17:47:32 +0300561
koder aka kdanilovda45e882015-04-06 02:24:42 +0300562 ctx = Context()
gstepanovaffcdb12015-04-07 17:18:29 +0300563 ctx.build_meta['build_id'] = opts.build_id
564 ctx.build_meta['build_descrption'] = opts.build_description
565 ctx.build_meta['build_type'] = opts.build_type
566 ctx.build_meta['username'] = opts.username
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300567 ctx.keep_vm = opts.keep_vm
koder aka kdanilov6c491062015-04-09 22:33:13 +0300568
koder aka kdanilovda45e882015-04-06 02:24:42 +0300569 try:
570 for stage in stages:
571 logger.info("Start {0.__name__} stage".format(stage))
572 stage(cfg_dict, ctx)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300573 except Exception as exc:
574 msg = "Exception during current stage: {0}".format(exc.message)
575 logger.error(msg)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300576 finally:
577 exc, cls, tb = sys.exc_info()
578 for stage in ctx.clear_calls_stack[::-1]:
579 try:
580 logger.info("Start {0.__name__} stage".format(stage))
581 stage(cfg_dict, ctx)
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300582 except Exception as exc:
583 logger.exception("During {0.__name__} stage".format(stage))
koder aka kdanilov2c473092015-03-29 17:12:13 +0300584
koder aka kdanilovda45e882015-04-06 02:24:42 +0300585 if exc is not None:
586 raise exc, cls, tb
koder aka kdanilov2c473092015-03-29 17:12:13 +0300587
koder aka kdanilovcee43342015-04-14 22:52:53 +0300588 logger.info("All info stored into {0}".format(cfg_dict['var_dir']))
koder aka kdanilove06762a2015-03-22 23:32:09 +0200589 return 0