blob: 891b9d3b7e0f29cc38a30dcc1af9e3737d6310d3 [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 kdanilov2c473092015-03-29 17:12:13 +03005import Queue
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -08006import pprint
koder aka kdanilove21d7472015-02-14 19:02:04 -08007import logging
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -08008import argparse
koder aka kdanilov168f6092015-04-19 02:33:38 +03009import functools
koder aka kdanilov2c473092015-03-29 17:12:13 +030010import threading
koder aka kdanilov168f6092015-04-19 02:33:38 +030011import contextlib
koder aka kdanilov7306c642015-04-23 15:29:45 +030012import subprocess
koder aka kdanilov2c473092015-03-29 17:12:13 +030013import collections
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080014
koder aka kdanilov66839a92015-04-11 13:22:31 +030015import yaml
koder aka kdanilov2c473092015-03-29 17:12:13 +030016from concurrent.futures import ThreadPoolExecutor
koder aka kdanilov6c491062015-04-09 22:33:13 +030017
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030018from wally import pretty_yaml
koder aka kdanilove87ae652015-04-20 02:14:35 +030019from wally.sensors_utils import deploy_sensors_stage
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030020from wally.discover import discover, Node, undiscover
21from wally import utils, report, ssh_utils, start_vms
22from wally.suits.itest import IOPerfTest, PgBenchTest
23from wally.config import cfg_dict, load_config, setup_loggers
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 kdanilov168f6092015-04-19 02:33:38 +030043 self.sensors_mon_q = None
koder aka kdanilov1c2b5112015-04-10 16:53:51 +030044
45
koder aka kdanilov168f6092015-04-19 02:33:38 +030046def connect_one(node, vm=False):
koder aka kdanilov0c598a12015-04-21 03:01:40 +030047 if node.conn_url == 'local':
48 node.connection = ssh_utils.connect(node.conn_url)
49 return
50
koder aka kdanilov5d589b42015-03-26 12:25:51 +020051 try:
koder aka kdanilov2c473092015-03-29 17:12:13 +030052 ssh_pref = "ssh://"
53 if node.conn_url.startswith(ssh_pref):
54 url = node.conn_url[len(ssh_pref):]
koder aka kdanilov168f6092015-04-19 02:33:38 +030055
56 if vm:
koder aka kdanilov6b1341a2015-04-21 22:44:21 +030057 conn_timeout = 240
koder aka kdanilov168f6092015-04-19 02:33:38 +030058 else:
koder aka kdanilov6b1341a2015-04-21 22:44:21 +030059 conn_timeout = 30
koder aka kdanilov168f6092015-04-19 02:33:38 +030060
61 node.connection = ssh_utils.connect(url,
koder aka kdanilov6b1341a2015-04-21 22:44:21 +030062 conn_timeout=conn_timeout)
koder aka kdanilov2c473092015-03-29 17:12:13 +030063 else:
64 raise ValueError("Unknown url type {0}".format(node.conn_url))
koder aka kdanilove87ae652015-04-20 02:14:35 +030065 except Exception as exc:
66 # logger.exception("During connect to " + node.get_conn_id())
koder aka kdanilovec1b9732015-04-23 20:43:29 +030067 msg = "During connect to {0}: {1!s}".format(node.get_conn_id(),
68 exc)
koder aka kdanilove87ae652015-04-20 02:14:35 +030069 logger.error(msg)
koder aka kdanilov168f6092015-04-19 02:33:38 +030070 node.connection = None
koder aka kdanilov5d589b42015-03-26 12:25:51 +020071
72
koder aka kdanilov168f6092015-04-19 02:33:38 +030073def connect_all(nodes, vm=False):
koder aka kdanilov2c473092015-03-29 17:12:13 +030074 logger.info("Connecting to nodes")
75 with ThreadPoolExecutor(32) as pool:
koder aka kdanilov168f6092015-04-19 02:33:38 +030076 connect_one_f = functools.partial(connect_one, vm=vm)
77 list(pool.map(connect_one_f, nodes))
koder aka kdanilov2c473092015-03-29 17:12:13 +030078
79
koder aka kdanilov652cd802015-04-13 12:21:07 +030080def test_thread(test, node, barrier, res_q):
koder aka kdanilov4d4771c2015-04-23 01:32:02 +030081 exc = None
koder aka kdanilov2c473092015-03-29 17:12:13 +030082 try:
koder aka kdanilova047e1b2015-04-21 23:16:59 +030083 logger.debug("Run preparation for {0}".format(node.get_conn_id()))
koder aka kdanilov4d4771c2015-04-23 01:32:02 +030084 test.pre_run()
koder aka kdanilova047e1b2015-04-21 23:16:59 +030085 logger.debug("Run test for {0}".format(node.get_conn_id()))
koder aka kdanilov4d4771c2015-04-23 01:32:02 +030086 test.run(barrier)
koder aka kdanilove2de58c2015-04-24 22:59:36 +030087 except utils.StopTestError as exc:
88 pass
koder aka kdanilov652cd802015-04-13 12:21:07 +030089 except Exception as exc:
koder aka kdanilove2de58c2015-04-24 22:59:36 +030090 msg = "In test {0} for node {1}"
91 msg = msg.format(test, node.get_conn_id())
92 logger.exception(msg)
93 exc = utils.StopTestError(msg, exc)
koder aka kdanilov2c473092015-03-29 17:12:13 +030094
koder aka kdanilov4500a5f2015-04-17 16:55:17 +030095 try:
koder aka kdanilov4d4771c2015-04-23 01:32:02 +030096 test.cleanup()
koder aka kdanilove2de58c2015-04-24 22:59:36 +030097 except utils.StopTestError as exc1:
98 if exc is None:
99 exc = exc1
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300100 except:
101 msg = "Duringf cleanup - in test {0} for node {1}"
102 logger.exception(msg.format(test, node))
103
koder aka kdanilov4d4771c2015-04-23 01:32:02 +0300104 if exc is not None:
105 res_q.put(exc)
koder aka kdanilov2c473092015-03-29 17:12:13 +0300106
koder aka kdanilov4d4771c2015-04-23 01:32:02 +0300107
koder aka kdanilov2066daf2015-04-23 21:05:41 +0300108def run_tests(cfg, test_block, nodes):
koder aka kdanilov2c473092015-03-29 17:12:13 +0300109 tool_type_mapper = {
110 "io": IOPerfTest,
111 "pgbench": PgBenchTest,
112 }
113
114 test_nodes = [node for node in nodes
115 if 'testnode' in node.roles]
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300116 test_number_per_type = {}
koder aka kdanilov2c473092015-03-29 17:12:13 +0300117 res_q = Queue.Queue()
118
koder aka kdanilovcee43342015-04-14 22:52:53 +0300119 for name, params in test_block.items():
120 logger.info("Starting {0} tests".format(name))
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300121 test_num = test_number_per_type.get(name, 0)
122 test_number_per_type[name] = test_num + 1
koder aka kdanilovcee43342015-04-14 22:52:53 +0300123 threads = []
124 barrier = utils.Barrier(len(test_nodes))
koder aka kdanilovec1b9732015-04-23 20:43:29 +0300125 coord_q = Queue.Queue()
126 test_cls = tool_type_mapper[name]
koder aka kdanilov2066daf2015-04-23 21:05:41 +0300127 rem_folder = cfg['default_test_local_folder'].format(name=name)
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300128
koder aka kdanilovabd6ead2015-04-24 02:03:07 +0300129 for idx, node in enumerate(test_nodes):
koder aka kdanilovcee43342015-04-14 22:52:53 +0300130 msg = "Starting {0} test on {1} node"
131 logger.debug(msg.format(name, node.conn_url))
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300132
133 dr = os.path.join(
134 cfg_dict['test_log_directory'],
135 "{0}_{1}_{2}".format(name, test_num, node.get_ip())
136 )
137
138 if not os.path.exists(dr):
139 os.makedirs(dr)
140
koder aka kdanilovabd6ead2015-04-24 02:03:07 +0300141 test = test_cls(options=params,
142 is_primary=(idx == 0),
143 on_result_cb=res_q.put,
144 test_uuid=cfg['run_uuid'],
145 node=node,
koder aka kdanilov2066daf2015-04-23 21:05:41 +0300146 remote_dir=rem_folder,
koder aka kdanilovec1b9732015-04-23 20:43:29 +0300147 log_directory=dr,
148 coordination_queue=coord_q)
koder aka kdanilovcee43342015-04-14 22:52:53 +0300149 th = threading.Thread(None, test_thread, None,
150 (test, node, barrier, res_q))
151 threads.append(th)
152 th.daemon = True
153 th.start()
koder aka kdanilov2c473092015-03-29 17:12:13 +0300154
koder aka kdanilovec1b9732015-04-23 20:43:29 +0300155 th = threading.Thread(None, test_cls.coordination_th, None,
156 (coord_q, barrier, len(threads)))
157 threads.append(th)
158 th.daemon = True
159 th.start()
160
koder aka kdanilovcee43342015-04-14 22:52:53 +0300161 def gather_results(res_q, results):
162 while not res_q.empty():
163 val = res_q.get()
koder aka kdanilov66839a92015-04-11 13:22:31 +0300164
koder aka kdanilove2de58c2015-04-24 22:59:36 +0300165 if isinstance(val, utils.StopTestError):
166 raise val
167
koder aka kdanilovcee43342015-04-14 22:52:53 +0300168 if isinstance(val, Exception):
koder aka kdanilovec1b9732015-04-23 20:43:29 +0300169 msg = "Exception during test execution: {0!s}"
170 raise ValueError(msg.format(val))
koder aka kdanilov652cd802015-04-13 12:21:07 +0300171
koder aka kdanilovcee43342015-04-14 22:52:53 +0300172 results.append(val)
koder aka kdanilov652cd802015-04-13 12:21:07 +0300173
koder aka kdanilovcee43342015-04-14 22:52:53 +0300174 results = []
koder aka kdanilov652cd802015-04-13 12:21:07 +0300175
koder aka kdanilove87ae652015-04-20 02:14:35 +0300176 # MAX_WAIT_TIME = 10
177 # end_time = time.time() + MAX_WAIT_TIME
178
179 # while time.time() < end_time:
koder aka kdanilovcee43342015-04-14 22:52:53 +0300180 while True:
181 for th in threads:
182 th.join(1)
183 gather_results(res_q, results)
koder aka kdanilove87ae652015-04-20 02:14:35 +0300184 # if time.time() > end_time:
185 # break
koder aka kdanilov652cd802015-04-13 12:21:07 +0300186
koder aka kdanilovcee43342015-04-14 22:52:53 +0300187 if all(not th.is_alive() for th in threads):
188 break
koder aka kdanilov652cd802015-04-13 12:21:07 +0300189
koder aka kdanilove87ae652015-04-20 02:14:35 +0300190 # if any(th.is_alive() for th in threads):
191 # logger.warning("Some test threads still running")
192
koder aka kdanilovcee43342015-04-14 22:52:53 +0300193 gather_results(res_q, results)
194 yield name, test.merge_results(results)
koder aka kdanilov2c473092015-03-29 17:12:13 +0300195
196
koder aka kdanilovda45e882015-04-06 02:24:42 +0300197def log_nodes_statistic(_, ctx):
198 nodes = ctx.nodes
koder aka kdanilov2c473092015-03-29 17:12:13 +0300199 logger.info("Found {0} nodes total".format(len(nodes)))
200 per_role = collections.defaultdict(lambda: 0)
201 for node in nodes:
202 for role in node.roles:
203 per_role[role] += 1
204
205 for role, count in sorted(per_role.items()):
206 logger.debug("Found {0} nodes with role {1}".format(count, role))
207
208
koder aka kdanilovda45e882015-04-06 02:24:42 +0300209def connect_stage(cfg, ctx):
210 ctx.clear_calls_stack.append(disconnect_stage)
211 connect_all(ctx.nodes)
212
koder aka kdanilov168f6092015-04-19 02:33:38 +0300213 all_ok = True
koder aka kdanilovda45e882015-04-06 02:24:42 +0300214
koder aka kdanilov168f6092015-04-19 02:33:38 +0300215 for node in ctx.nodes:
216 if node.connection is None:
217 if 'testnode' in node.roles:
218 msg = "Can't connect to testnode {0}"
219 raise RuntimeError(msg.format(node.get_conn_id()))
220 else:
221 msg = "Node {0} would be excluded - can't connect"
222 logger.warning(msg.format(node.get_conn_id()))
223 all_ok = False
224
225 if all_ok:
226 logger.info("All nodes connected successfully")
227
228 ctx.nodes = [node for node in ctx.nodes
229 if node.connection is not None]
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300230
231
koder aka kdanilovda45e882015-04-06 02:24:42 +0300232def discover_stage(cfg, ctx):
koder aka kdanilov652cd802015-04-13 12:21:07 +0300233 if cfg.get('discover') is not None:
koder aka kdanilovda45e882015-04-06 02:24:42 +0300234 discover_objs = [i.strip() for i in cfg['discover'].strip().split(",")]
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300235
koder aka kdanilove87ae652015-04-20 02:14:35 +0300236 nodes, clean_data = discover(ctx,
237 discover_objs,
238 cfg['clouds'],
239 cfg['var_dir'],
240 not cfg['dont_discover_nodes'])
koder aka kdanilov168f6092015-04-19 02:33:38 +0300241
242 def undiscover_stage(cfg, ctx):
243 undiscover(clean_data)
244
245 ctx.clear_calls_stack.append(undiscover_stage)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300246 ctx.nodes.extend(nodes)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300247
248 for url, roles in cfg.get('explicit_nodes', {}).items():
249 ctx.nodes.append(Node(url, roles.split(",")))
250
251
koder aka kdanilove87ae652015-04-20 02:14:35 +0300252def get_OS_credentials(cfg, ctx, creds_type):
koder aka kdanilovcee43342015-04-14 22:52:53 +0300253 creds = None
koder aka kdanilovda45e882015-04-06 02:24:42 +0300254
koder aka kdanilovcee43342015-04-14 22:52:53 +0300255 if creds_type == 'clouds':
koder aka kdanilov46d4f392015-04-24 11:35:00 +0300256 logger.info("Using OS credentials from 'cloud' section")
koder aka kdanilovcee43342015-04-14 22:52:53 +0300257 if 'openstack' in cfg['clouds']:
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300258 os_cfg = cfg['clouds']['openstack']
koder aka kdanilovcee43342015-04-14 22:52:53 +0300259
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300260 tenant = os_cfg['OS_TENANT_NAME'].strip()
261 user = os_cfg['OS_USERNAME'].strip()
262 passwd = os_cfg['OS_PASSWORD'].strip()
263 auth_url = os_cfg['OS_AUTH_URL'].strip()
264
koder aka kdanilovcee43342015-04-14 22:52:53 +0300265 elif 'fuel' in cfg['clouds'] and \
266 'openstack_env' in cfg['clouds']['fuel']:
267 creds = ctx.fuel_openstack_creds
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300268
koder aka kdanilovcee43342015-04-14 22:52:53 +0300269 elif creds_type == 'ENV':
koder aka kdanilov46d4f392015-04-24 11:35:00 +0300270 logger.info("Using OS credentials from shell environment")
koder aka kdanilovcee43342015-04-14 22:52:53 +0300271 user, passwd, tenant, auth_url = start_vms.ostack_get_creds()
272 elif os.path.isfile(creds_type):
koder aka kdanilov46d4f392015-04-24 11:35:00 +0300273 logger.info("Using OS credentials from " + creds_type)
koder aka kdanilov7306c642015-04-23 15:29:45 +0300274 fc = open(creds_type).read()
275
276 echo = 'echo "$OS_TENANT_NAME:$OS_USERNAME:$OS_PASSWORD@$OS_AUTH_URL"'
277
278 p = subprocess.Popen(['/bin/bash'], shell=False,
279 stdout=subprocess.PIPE,
280 stdin=subprocess.PIPE,
281 stderr=subprocess.STDOUT)
282 p.stdin.write(fc + "\n" + echo)
283 p.stdin.close()
284 code = p.wait()
285 data = p.stdout.read().strip()
286
287 if code != 0:
288 msg = "Failed to get creads from openrc file: " + data
289 logger.error(msg)
290 raise RuntimeError(msg)
291
292 try:
293 user, tenant, passwd_auth_url = data.split(':', 2)
294 passwd, auth_url = passwd_auth_url.rsplit("@", 1)
295 assert (auth_url.startswith("https://") or
296 auth_url.startswith("http://"))
297 except Exception:
298 msg = "Failed to get creads from openrc file: " + data
299 logger.exception(msg)
300 raise
301
koder aka kdanilovcee43342015-04-14 22:52:53 +0300302 else:
303 msg = "Creds {0!r} isn't supported".format(creds_type)
304 raise ValueError(msg)
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300305
koder aka kdanilovcee43342015-04-14 22:52:53 +0300306 if creds is None:
307 creds = {'name': user,
308 'passwd': passwd,
309 'tenant': tenant,
310 'auth_url': auth_url}
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300311
koder aka kdanilov46d4f392015-04-24 11:35:00 +0300312 msg = "OS_CREDS: user={name} tenant={tenant} auth_url={auth_url}"
313 logger.debug(msg.format(**creds))
koder aka kdanilovcee43342015-04-14 22:52:53 +0300314 return creds
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300315
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300316
koder aka kdanilov168f6092015-04-19 02:33:38 +0300317@contextlib.contextmanager
318def create_vms_ctx(ctx, cfg, config):
319 params = config['vm_params'].copy()
320 os_nodes_ids = []
321
322 os_creds_type = config['creds']
koder aka kdanilove87ae652015-04-20 02:14:35 +0300323 os_creds = get_OS_credentials(cfg, ctx, os_creds_type)
koder aka kdanilov168f6092015-04-19 02:33:38 +0300324
325 start_vms.nova_connect(**os_creds)
326
327 logger.info("Preparing openstack")
328 start_vms.prepare_os_subpr(**os_creds)
329
330 new_nodes = []
331 try:
332 params['group_name'] = cfg_dict['run_uuid']
333 for new_node, node_id in start_vms.launch_vms(params):
334 new_node.roles.append('testnode')
335 ctx.nodes.append(new_node)
336 os_nodes_ids.append(node_id)
337 new_nodes.append(new_node)
338
339 store_nodes_in_log(cfg, os_nodes_ids)
340 ctx.openstack_nodes_ids = os_nodes_ids
341
342 yield new_nodes
343
344 finally:
345 if not cfg['keep_vm']:
346 shut_down_vms_stage(cfg, ctx)
347
348
koder aka kdanilovcee43342015-04-14 22:52:53 +0300349def run_tests_stage(cfg, ctx):
350 ctx.results = []
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300351
koder aka kdanilovcee43342015-04-14 22:52:53 +0300352 if 'tests' not in cfg:
353 return
gstepanov023c1e42015-04-08 15:50:19 +0300354
koder aka kdanilovcee43342015-04-14 22:52:53 +0300355 for group in cfg['tests']:
356
357 assert len(group.items()) == 1
358 key, config = group.items()[0]
359
360 if 'start_test_nodes' == key:
koder aka kdanilov168f6092015-04-19 02:33:38 +0300361 with create_vms_ctx(ctx, cfg, config) as new_nodes:
362 connect_all(new_nodes, True)
koder aka kdanilovcee43342015-04-14 22:52:53 +0300363
koder aka kdanilov168f6092015-04-19 02:33:38 +0300364 for node in new_nodes:
365 if node.connection is None:
366 msg = "Failed to connect to vm {0}"
367 raise RuntimeError(msg.format(node.get_conn_id()))
koder aka kdanilovcee43342015-04-14 22:52:53 +0300368
koder aka kdanilov168f6092015-04-19 02:33:38 +0300369 deploy_sensors_stage(cfg_dict,
370 ctx,
371 nodes=new_nodes,
372 undeploy=False)
koder aka kdanilov12ae0632015-04-15 01:13:43 +0300373
koder aka kdanilove87ae652015-04-20 02:14:35 +0300374 if not cfg['no_tests']:
375 for test_group in config.get('tests', []):
koder aka kdanilov2066daf2015-04-23 21:05:41 +0300376 test_res = run_tests(cfg, test_group, ctx.nodes)
koder aka kdanilov4d4771c2015-04-23 01:32:02 +0300377 ctx.results.extend(test_res)
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300378 else:
koder aka kdanilove87ae652015-04-20 02:14:35 +0300379 if not cfg['no_tests']:
koder aka kdanilov2066daf2015-04-23 21:05:41 +0300380 test_res = run_tests(cfg, group, ctx.nodes)
koder aka kdanilov4d4771c2015-04-23 01:32:02 +0300381 ctx.results.extend(test_res)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300382
gstepanov023c1e42015-04-08 15:50:19 +0300383
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300384def shut_down_vms_stage(cfg, ctx):
koder aka kdanilov66839a92015-04-11 13:22:31 +0300385 vm_ids_fname = cfg_dict['vm_ids_fname']
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300386 if ctx.openstack_nodes_ids is None:
koder aka kdanilov66839a92015-04-11 13:22:31 +0300387 nodes_ids = open(vm_ids_fname).read().split()
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300388 else:
389 nodes_ids = ctx.openstack_nodes_ids
390
koder aka kdanilov652cd802015-04-13 12:21:07 +0300391 if len(nodes_ids) != 0:
392 logger.info("Removing nodes")
393 start_vms.clear_nodes(nodes_ids)
394 logger.info("Nodes has been removed")
gstepanov023c1e42015-04-08 15:50:19 +0300395
koder aka kdanilov66839a92015-04-11 13:22:31 +0300396 if os.path.exists(vm_ids_fname):
397 os.remove(vm_ids_fname)
gstepanov023c1e42015-04-08 15:50:19 +0300398
koder aka kdanilov66839a92015-04-11 13:22:31 +0300399
400def store_nodes_in_log(cfg, nodes_ids):
401 with open(cfg['vm_ids_fname'], 'w') as fd:
402 fd.write("\n".join(nodes_ids))
gstepanov023c1e42015-04-08 15:50:19 +0300403
404
405def clear_enviroment(cfg, ctx):
koder aka kdanilov66839a92015-04-11 13:22:31 +0300406 if os.path.exists(cfg_dict['vm_ids_fname']):
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300407 shut_down_vms_stage(cfg, ctx)
gstepanov023c1e42015-04-08 15:50:19 +0300408
409
koder aka kdanilovda45e882015-04-06 02:24:42 +0300410def disconnect_stage(cfg, ctx):
koder aka kdanilov652cd802015-04-13 12:21:07 +0300411 ssh_utils.close_all_sessions()
412
koder aka kdanilovda45e882015-04-06 02:24:42 +0300413 for node in ctx.nodes:
414 if node.connection is not None:
415 node.connection.close()
416
417
koder aka kdanilov66839a92015-04-11 13:22:31 +0300418def store_raw_results_stage(cfg, ctx):
419
420 raw_results = os.path.join(cfg_dict['var_dir'], 'raw_results.yaml')
421
422 if os.path.exists(raw_results):
423 cont = yaml.load(open(raw_results).read())
424 else:
425 cont = []
426
koder aka kdanilov168f6092015-04-19 02:33:38 +0300427 cont.extend(utils.yamable(ctx.results))
koder aka kdanilov66839a92015-04-11 13:22:31 +0300428 raw_data = pretty_yaml.dumps(cont)
429
430 with open(raw_results, "w") as fd:
431 fd.write(raw_data)
432
433
434def console_report_stage(cfg, ctx):
435 for tp, data in ctx.results:
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300436 if 'io' == tp and data is not None:
koder aka kdanilove87ae652015-04-20 02:14:35 +0300437 print("\n")
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300438 print(IOPerfTest.format_for_console(data))
koder aka kdanilove87ae652015-04-20 02:14:35 +0300439 print("\n")
koder aka kdanilov66839a92015-04-11 13:22:31 +0300440
441
koder aka kdanilove87ae652015-04-20 02:14:35 +0300442def html_report_stage(cfg, ctx):
Yulia Portnova8ca20572015-04-14 14:09:39 +0300443 html_rep_fname = cfg['html_report_file']
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300444
445 try:
446 fuel_url = cfg['clouds']['fuel']['url']
447 except KeyError:
448 fuel_url = None
449
450 try:
451 creds = cfg['clouds']['fuel']['creds']
452 except KeyError:
453 creds = None
454
gstepanov69339ac2015-04-16 20:09:33 +0300455 report.make_io_report(ctx.results, html_rep_fname, fuel_url, creds=creds)
koder aka kdanilov652cd802015-04-13 12:21:07 +0300456
koder aka kdanilov652cd802015-04-13 12:21:07 +0300457 text_rep_fname = cfg_dict['text_report_file']
458 with open(text_rep_fname, "w") as fd:
459 for tp, data in ctx.results:
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300460 if 'io' == tp and data is not None:
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300461 fd.write(IOPerfTest.format_for_console(data))
koder aka kdanilov652cd802015-04-13 12:21:07 +0300462 fd.write("\n")
463 fd.flush()
464
465 logger.info("Text report were stored in " + text_rep_fname)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300466
467
468def complete_log_nodes_statistic(cfg, ctx):
469 nodes = ctx.nodes
470 for node in nodes:
471 logger.debug(str(node))
472
473
koder aka kdanilov66839a92015-04-11 13:22:31 +0300474def load_data_from(var_dir):
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300475 def load_data_from_file(cfg, ctx):
koder aka kdanilov66839a92015-04-11 13:22:31 +0300476 raw_results = os.path.join(var_dir, 'raw_results.yaml')
477 ctx.results = yaml.load(open(raw_results).read())
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300478 return load_data_from_file
gstepanovcd256d62015-04-07 17:47:32 +0300479
480
koder aka kdanilovcee43342015-04-14 22:52:53 +0300481def parse_args(argv):
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300482 descr = "Disk io performance test suite"
483 parser = argparse.ArgumentParser(prog='wally', description=descr)
koder aka kdanilovcee43342015-04-14 22:52:53 +0300484
485 parser.add_argument("-l", dest='extra_logs',
486 action='store_true', default=False,
487 help="print some extra log info")
koder aka kdanilovcee43342015-04-14 22:52:53 +0300488 parser.add_argument("-b", '--build_description',
489 type=str, default="Build info")
490 parser.add_argument("-i", '--build_id', type=str, default="id")
491 parser.add_argument("-t", '--build_type', type=str, default="GA")
492 parser.add_argument("-u", '--username', type=str, default="admin")
koder aka kdanilove87ae652015-04-20 02:14:35 +0300493 parser.add_argument("-n", '--no-tests', action='store_true',
494 help="Don't run tests", default=False)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300495 parser.add_argument("-p", '--post-process-only', metavar="VAR_DIR",
496 help="Only process data from previour run")
497 parser.add_argument("-k", '--keep-vm', action='store_true',
498 help="Don't remove test vm's", default=False)
koder aka kdanilove87ae652015-04-20 02:14:35 +0300499 parser.add_argument("-d", '--dont-discover-nodes', action='store_true',
500 help="Don't connect/discover fuel nodes",
501 default=False)
koder aka kdanilova047e1b2015-04-21 23:16:59 +0300502 parser.add_argument("-r", '--no-html-report', action='store_true',
503 help="Skip html report", default=False)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300504 parser.add_argument("config_file")
koder aka kdanilovcee43342015-04-14 22:52:53 +0300505
506 return parser.parse_args(argv[1:])
507
508
koder aka kdanilov3f356262015-02-13 08:06:14 -0800509def main(argv):
koder aka kdanilove06762a2015-03-22 23:32:09 +0200510 opts = parse_args(argv)
koder aka kdanilov2c473092015-03-29 17:12:13 +0300511
koder aka kdanilov66839a92015-04-11 13:22:31 +0300512 if opts.post_process_only is not None:
513 stages = [
koder aka kdanilove87ae652015-04-20 02:14:35 +0300514 load_data_from(opts.post_process_only)
koder aka kdanilov66839a92015-04-11 13:22:31 +0300515 ]
516 else:
517 stages = [
518 discover_stage,
519 log_nodes_statistic,
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300520 connect_stage,
koder aka kdanilov66839a92015-04-11 13:22:31 +0300521 deploy_sensors_stage,
522 run_tests_stage,
koder aka kdanilove87ae652015-04-20 02:14:35 +0300523 store_raw_results_stage
koder aka kdanilov66839a92015-04-11 13:22:31 +0300524 ]
525
koder aka kdanilove87ae652015-04-20 02:14:35 +0300526 report_stages = [
527 console_report_stage,
koder aka kdanilove87ae652015-04-20 02:14:35 +0300528 ]
529
koder aka kdanilova047e1b2015-04-21 23:16:59 +0300530 if not opts.no_html_report:
531 report_stages.append(html_report_stage)
532
koder aka kdanilovcee43342015-04-14 22:52:53 +0300533 load_config(opts.config_file, opts.post_process_only)
koder aka kdanilovf4b82c22015-04-11 13:35:25 +0300534
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300535 if cfg_dict.get('logging', {}).get("extra_logs", False) or opts.extra_logs:
536 level = logging.DEBUG
537 else:
538 level = logging.WARNING
539
540 setup_loggers(level, cfg_dict['log_file'])
koder aka kdanilovf4b82c22015-04-11 13:35:25 +0300541
koder aka kdanilov652cd802015-04-13 12:21:07 +0300542 logger.info("All info would be stored into {0}".format(
543 cfg_dict['var_dir']))
gstepanovcd256d62015-04-07 17:47:32 +0300544
koder aka kdanilovda45e882015-04-06 02:24:42 +0300545 ctx = Context()
gstepanovaffcdb12015-04-07 17:18:29 +0300546 ctx.build_meta['build_id'] = opts.build_id
547 ctx.build_meta['build_descrption'] = opts.build_description
548 ctx.build_meta['build_type'] = opts.build_type
549 ctx.build_meta['username'] = opts.username
koder aka kdanilove87ae652015-04-20 02:14:35 +0300550
koder aka kdanilov168f6092015-04-19 02:33:38 +0300551 cfg_dict['keep_vm'] = opts.keep_vm
koder aka kdanilove87ae652015-04-20 02:14:35 +0300552 cfg_dict['no_tests'] = opts.no_tests
553 cfg_dict['dont_discover_nodes'] = opts.dont_discover_nodes
koder aka kdanilov6c491062015-04-09 22:33:13 +0300554
koder aka kdanilovda45e882015-04-06 02:24:42 +0300555 try:
556 for stage in stages:
557 logger.info("Start {0.__name__} stage".format(stage))
558 stage(cfg_dict, ctx)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300559 except Exception as exc:
koder aka kdanilovec1b9732015-04-23 20:43:29 +0300560 msg = "Exception during {0.__name__}: {1!s}".format(stage, exc)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300561 logger.error(msg)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300562 finally:
563 exc, cls, tb = sys.exc_info()
564 for stage in ctx.clear_calls_stack[::-1]:
565 try:
566 logger.info("Start {0.__name__} stage".format(stage))
567 stage(cfg_dict, ctx)
koder aka kdanilove2de58c2015-04-24 22:59:36 +0300568 except utils.StopTestError as exc:
569 msg = "During {0.__name__} stage: {1}".format(stage, exc)
570 logger.error(msg)
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300571 except Exception as exc:
572 logger.exception("During {0.__name__} stage".format(stage))
koder aka kdanilov2c473092015-03-29 17:12:13 +0300573
koder aka kdanilove2de58c2015-04-24 22:59:36 +0300574 # if exc is not None:
575 # raise exc, cls, tb
koder aka kdanilov2c473092015-03-29 17:12:13 +0300576
koder aka kdanilove2de58c2015-04-24 22:59:36 +0300577 if exc is None:
578 for report_stage in report_stages:
579 report_stage(cfg_dict, ctx)
koder aka kdanilove87ae652015-04-20 02:14:35 +0300580
581 logger.info("All info stored in {0} folder".format(cfg_dict['var_dir']))
koder aka kdanilove2de58c2015-04-24 22:59:36 +0300582
583 if exc is None:
584 logger.info("Tests finished successfully")
585 return 0
586 else:
587 logger.error("Tests are failed. See detailed error above")
588 return 1