blob: b931929fdeead9dff3cdee71adf1d2d94b473e4f [file] [log] [blame]
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +03001import os
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +03002import time
3import signal
koder aka kdanilov7f59d562016-12-26 01:34:23 +02004import pprint
koder aka kdanilovf2865172016-12-30 03:35:11 +02005import getpass
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +03006import logging
koder aka kdanilov108ac362017-01-19 20:17:16 +02007import tempfile
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +03008import argparse
9import functools
koder aka kdanilov108ac362017-01-19 20:17:16 +020010import subprocess
koder aka kdanilov39e449e2016-12-17 15:15:26 +020011import contextlib
12from typing import List, Tuple, Any, Callable, IO, cast, Optional, Iterator
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030013from yaml import load as _yaml_load
14
koder aka kdanilov22d134e2016-11-08 11:33:19 +020015
16YLoader = Callable[[IO], Any]
17yaml_load = None # type: YLoader
18
19
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030020try:
21 from yaml import CLoader
koder aka kdanilov22d134e2016-11-08 11:33:19 +020022 yaml_load = cast(YLoader, functools.partial(_yaml_load, Loader=CLoader))
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030023except ImportError:
koder aka kdanilov22d134e2016-11-08 11:33:19 +020024 yaml_load = cast(YLoader, _yaml_load)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030025
26
27import texttable
28
29try:
30 import faulthandler
31except ImportError:
32 faulthandler = None
33
kdanylov aka koder150b2192017-04-01 16:53:01 +030034from cephlib.common import setup_logging
35
koder aka kdanilove7e1a4d2016-12-17 20:29:52 +020036from . import utils, node
koder aka kdanilov108ac362017-01-19 20:17:16 +020037from .node_utils import log_nodes_statistic
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +020038from .storage import make_storage, Storage
koder aka kdanilov22d134e2016-11-08 11:33:19 +020039from .config import Config
koder aka kdanilov39e449e2016-12-17 15:15:26 +020040from .stage import Stage
koder aka kdanilov22d134e2016-11-08 11:33:19 +020041from .test_run_class import TestRun
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020042from .ssh import set_ssh_key_passwd
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030043
44
koder aka kdanilov39e449e2016-12-17 15:15:26 +020045# stages
46from .ceph import DiscoverCephStage
47from .openstack import DiscoverOSStage
48from .fuel import DiscoverFuelStage
koder aka kdanilov23e6bdf2016-12-24 02:18:54 +020049from .run_test import (CollectInfoStage, ExplicitNodesStage, SaveNodesStage,
koder aka kdanilov7f59d562016-12-26 01:34:23 +020050 RunTestsStage, ConnectStage, SleepStage, PrepareNodes,
51 LoadStoredNodesStage)
kdanylov aka koder150b2192017-04-01 16:53:01 +030052
53from .report import HtmlReportStage
koder aka kdanilov39e449e2016-12-17 15:15:26 +020054from .sensors import StartSensorsStage, CollectSensorsStage
kdanylov aka koder150b2192017-04-01 16:53:01 +030055from .console_report import ConsoleReportStage
koder aka kdanilov39e449e2016-12-17 15:15:26 +020056
57
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030058logger = logging.getLogger("wally")
59
60
koder aka kdanilov39e449e2016-12-17 15:15:26 +020061@contextlib.contextmanager
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020062def log_stage(stage: Stage, cleanup: bool = False) -> Iterator[None]:
63 logger.info("Start " + stage.name() + ("::cleanup" if cleanup else ""))
koder aka kdanilov39e449e2016-12-17 15:15:26 +020064 try:
65 yield
66 except utils.StopTestError as exc:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020067 raise
koder aka kdanilov39e449e2016-12-17 15:15:26 +020068 except Exception:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +020069 logger.exception("During %s", stage.name() + ("::cleanup" if cleanup else ""))
70 raise
koder aka kdanilov39e449e2016-12-17 15:15:26 +020071
72
koder aka kdanilov22d134e2016-11-08 11:33:19 +020073def list_results(path: str) -> List[Tuple[str, str, str, str]]:
koder aka kdanilov73084622016-11-16 21:51:08 +020074 results = [] # type: List[Tuple[float, str, str, str, str]]
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030075
koder aka kdanilov22d134e2016-11-08 11:33:19 +020076 for dir_name in os.listdir(path):
77 full_path = os.path.join(path, dir_name)
78
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030079 try:
koder aka kdanilov22d134e2016-11-08 11:33:19 +020080 stor = make_storage(full_path, existing=True)
81 except Exception as exc:
82 logger.warning("Can't load folder {}. Error {}".format(full_path, exc))
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030083
koder aka kdanilov7f59d562016-12-26 01:34:23 +020084 comment = cast(str, stor.get('info/comment'))
85 run_uuid = cast(str, stor.get('info/run_uuid'))
86 run_time = cast(float, stor.get('info/run_time'))
koder aka kdanilov22d134e2016-11-08 11:33:19 +020087 test_types = ""
koder aka kdanilov73084622016-11-16 21:51:08 +020088 results.append((run_time,
koder aka kdanilov22d134e2016-11-08 11:33:19 +020089 run_uuid,
90 test_types,
koder aka kdanilov73084622016-11-16 21:51:08 +020091 time.ctime(run_time),
koder aka kdanilov22d134e2016-11-08 11:33:19 +020092 '-' if comment is None else comment))
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030093
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030094 results.sort()
koder aka kdanilov22d134e2016-11-08 11:33:19 +020095 return [i[1:] for i in results]
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030096
97
koder aka kdanilov22d134e2016-11-08 11:33:19 +020098def log_nodes_statistic_stage(ctx: TestRun) -> None:
koder aka kdanilov108ac362017-01-19 20:17:16 +020099 log_nodes_statistic(ctx.nodes)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300100
101
102def parse_args(argv):
103 descr = "Disk io performance test suite"
104 parser = argparse.ArgumentParser(prog='wally', description=descr)
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200105 parser.add_argument("-l", '--log-level', help="print some extra log info")
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200106 parser.add_argument("--ssh-key-passwd", default=None, help="Pass ssh key password")
koder aka kdanilovf2865172016-12-30 03:35:11 +0200107 parser.add_argument("--ssh-key-passwd-kbd", action="store_true", help="Enter ssh key password interactivelly")
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200108 parser.add_argument("-s", '--settings-dir', default=None,
109 help="Folder to store key/settings/history files")
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300110
111 subparsers = parser.add_subparsers(dest='subparser_name')
112
113 # ---------------------------------------------------------------------
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200114 report_parser = subparsers.add_parser('ls', help='list all results')
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300115 report_parser.add_argument("result_storage", help="Folder with test results")
116
117 # ---------------------------------------------------------------------
118 compare_help = 'compare two results'
119 report_parser = subparsers.add_parser('compare', help=compare_help)
120 report_parser.add_argument("data_path1", help="First folder with test results")
121 report_parser.add_argument("data_path2", help="Second folder with test results")
122
123 # ---------------------------------------------------------------------
124 report_help = 'run report on previously obtained results'
125 report_parser = subparsers.add_parser('report', help=report_help)
kdanylov aka koder150b2192017-04-01 16:53:01 +0300126 report_parser.add_argument('-R', '--reporters', help="Comma-separated list of reportes - html,txt",
127 default='html,txt')
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300128 report_parser.add_argument("data_dir", help="folder with rest results")
129
130 # ---------------------------------------------------------------------
koder aka kdanilov108ac362017-01-19 20:17:16 +0200131 ipython_help = 'run ipython in prepared environment'
132 ipython_parser = subparsers.add_parser('ipython', help=ipython_help)
133 ipython_parser.add_argument("storage_dir", help="Storage path")
134 # ---------------------------------------------------------------------
135 jupyter_help = 'run ipython in prepared environment'
136 jupyter_parser = subparsers.add_parser('jupyter', help=jupyter_help)
137 jupyter_parser.add_argument("storage_dir", help="Storage path")
138
139 # ---------------------------------------------------------------------
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300140 test_parser = subparsers.add_parser('test', help='run tests')
kdanylov aka koder150b2192017-04-01 16:53:01 +0300141 test_parser.add_argument("-d", '--dont-discover-nodes', action='store_true', help="Don't discover nodes")
142 test_parser.add_argument('-D', '--dont-collect', action='store_true', help="Don't collect cluster info")
143 test_parser.add_argument("-k", '--keep-vm', action='store_true', help="Don't remove test vm's")
144 test_parser.add_argument('-L', '--load-report', action='store_true', help="Create cluster load report")
145 test_parser.add_argument('-n', '--no-tests', action='store_true', help="Don't run tests")
146 test_parser.add_argument('-N', '--no-report', action='store_true', help="Skip report stages")
147 test_parser.add_argument('-r', '--result-dir', default=None, help="Save results to DIR", metavar="DIR")
148 test_parser.add_argument('-R', '--reporters', help="Comma-separated list of reportes - html,txt",
149 default='html,txt')
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200150 test_parser.add_argument('--build-description', type=str, default="Build info")
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300151 test_parser.add_argument('--build-id', type=str, default="id")
152 test_parser.add_argument('--build-type', type=str, default="GA")
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300153 test_parser.add_argument("comment", help="Test information")
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200154 test_parser.add_argument("config_file", help="Yaml config file")
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300155
156 # ---------------------------------------------------------------------
koder aka kdanilove7e1a4d2016-12-17 20:29:52 +0200157 test_parser = subparsers.add_parser('resume', help='resume tests')
158 test_parser.add_argument("storage_dir", help="Path to test directory")
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300159
koder aka kdanilov7f59d562016-12-26 01:34:23 +0200160 # ---------------------------------------------------------------------
koder aka kdanilov108ac362017-01-19 20:17:16 +0200161 test_parser = subparsers.add_parser('db', help='Exec command on DB')
koder aka kdanilov7f59d562016-12-26 01:34:23 +0200162 test_parser.add_argument("cmd", choices=("show",), help="Command to execute")
163 test_parser.add_argument("params", nargs='*', help="Command params")
164 test_parser.add_argument("storage_dir", help="Storage path")
165
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300166 return parser.parse_args(argv[1:])
167
168
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200169def get_config_path(config: Config, opts_value: Optional[str]) -> str:
170 if opts_value is None and 'settings_dir' not in config:
171 val = "~/.wally"
172 elif opts_value is not None:
173 val = opts_value
174 else:
175 val = config.settings_dir
176
177 return os.path.abspath(os.path.expanduser(val))
178
179
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200180def find_cfg_file(name: str, included_from: str = None) -> str:
181 paths = [".", os.path.expanduser('~/.wally')]
182 if included_from is not None:
183 paths.append(os.path.dirname(included_from))
184
185 search_paths = set(os.path.abspath(path) for path in paths if os.path.isdir(path))
186
187 for folder in search_paths:
188 path = os.path.join(folder, name)
189 if os.path.exists(path):
190 return path
191
192 raise FileNotFoundError(name)
193
194
195def load_config(path: str) -> Config:
196 path = os.path.abspath(path)
197 cfg_dict = yaml_load(open(path).read())
198
199 while 'include' in cfg_dict:
200 inc = cfg_dict.pop('include')
201 if isinstance(inc, str):
202 inc = [inc]
203
204 for fname in inc:
205 inc_path = find_cfg_file(fname, path)
206 inc_dict = yaml_load(open(inc_path).read())
207 inc_dict.update(cfg_dict)
208 cfg_dict = inc_dict
209
210 return Config(cfg_dict)
211
212
koder aka kdanilov7f59d562016-12-26 01:34:23 +0200213def get_run_stages() -> List[Stage]:
214 return [DiscoverCephStage(),
215 DiscoverOSStage(),
216 DiscoverFuelStage(),
217 ExplicitNodesStage(),
218 StartSensorsStage(),
219 RunTestsStage(),
220 CollectSensorsStage(),
221 ConnectStage(),
222 SleepStage(),
223 PrepareNodes()]
224
225
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200226def main(argv: List[str]) -> int:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300227 if faulthandler is not None:
228 faulthandler.register(signal.SIGUSR1, all_threads=True)
229
230 opts = parse_args(argv)
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200231 stages = [] # type: List[Stage]
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200232
233 # stop mypy from telling that config & storage might be undeclared
234 config = None # type: Config
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200235 storage = None # type: Storage
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300236
237 if opts.subparser_name == 'test':
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200238 config = load_config(opts.config_file)
kdanylov aka koder150b2192017-04-01 16:53:01 +0300239 config.storage_url, config.run_uuid = utils.get_uniq_path_uuid(config.results_storage)
koder aka kdanilove7e1a4d2016-12-17 20:29:52 +0200240 config.comment = opts.comment
241 config.keep_vm = opts.keep_vm
242 config.no_tests = opts.no_tests
243 config.dont_discover_nodes = opts.dont_discover_nodes
244 config.build_id = opts.build_id
245 config.build_description = opts.build_description
246 config.build_type = opts.build_type
247 config.settings_dir = get_config_path(config, opts.settings_dir)
kdanylov aka koder150b2192017-04-01 16:53:01 +0300248 config.discovery = set(config.get('discovery', '').split(","))
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300249
koder aka kdanilove7e1a4d2016-12-17 20:29:52 +0200250 storage = make_storage(config.storage_url)
koder aka kdanilov7f59d562016-12-26 01:34:23 +0200251 storage.put(config, 'config')
koder aka kdanilovffaf48d2016-12-27 02:25:29 +0200252
koder aka kdanilov7f59d562016-12-26 01:34:23 +0200253 stages.extend(get_run_stages())
koder aka kdanilovffaf48d2016-12-27 02:25:29 +0200254 stages.append(SaveNodesStage())
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300255
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200256 if not opts.dont_collect:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200257 stages.append(CollectInfoStage())
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300258
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200259 argv2 = argv[:]
260 if '--ssh-key-passwd' in argv2:
261 # don't save ssh key password to storage
262 argv2[argv2.index("--ssh-key-passwd") + 1] = "<removed from output>"
koder aka kdanilov7f59d562016-12-26 01:34:23 +0200263 storage.put(argv2, 'cli')
koder aka kdanilove7e1a4d2016-12-17 20:29:52 +0200264
265 elif opts.subparser_name == 'resume':
koder aka kdanilov7f59d562016-12-26 01:34:23 +0200266 opts.resumed = True
koder aka kdanilove7e1a4d2016-12-17 20:29:52 +0200267 storage = make_storage(opts.storage_dir, existing=True)
268 config = storage.load(Config, 'config')
koder aka kdanilov7f59d562016-12-26 01:34:23 +0200269 stages.extend(get_run_stages())
270 stages.append(LoadStoredNodesStage())
koder aka kdanilov108ac362017-01-19 20:17:16 +0200271 prev_opts = storage.get('cli') # type: List[str]
272
koder aka kdanilov7f59d562016-12-26 01:34:23 +0200273 if '--ssh-key-passwd' in prev_opts and opts.ssh_key_passwd:
274 prev_opts[prev_opts.index("--ssh-key-passwd") + 1] = opts.ssh_key_passwd
275
276 restored_opts = parse_args(prev_opts)
277 opts.__dict__.update(restored_opts.__dict__)
278 opts.subparser_name = 'resume'
koder aka kdanilove7e1a4d2016-12-17 20:29:52 +0200279
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300280 elif opts.subparser_name == 'ls':
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200281 tab = texttable.Texttable(max_width=200)
282 tab.set_deco(tab.HEADER | tab.VLINES | tab.BORDER)
283 tab.set_cols_align(["l", "l", "l", "l"])
284 tab.header(["Name", "Tests", "Run at", "Comment"])
285 tab.add_rows(list_results(opts.result_storage))
286 print(tab.draw())
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300287 return 0
288
289 elif opts.subparser_name == 'report':
koder aka kdanilovffaf48d2016-12-27 02:25:29 +0200290 if getattr(opts, "no_report", False):
291 print(" --no-report option can't be used with 'report' cmd")
292 return 1
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200293 storage = make_storage(opts.data_dir, existing=True)
koder aka kdanilovffaf48d2016-12-27 02:25:29 +0200294 config = storage.load(Config, 'config')
295 stages.append(LoadStoredNodesStage())
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300296
297 elif opts.subparser_name == 'compare':
koder aka kdanilov73084622016-11-16 21:51:08 +0200298 # x = run_test.load_data_from_path(opts.data_path1)
299 # y = run_test.load_data_from_path(opts.data_path2)
300 # print(run_test.IOPerfTest.format_diff_for_console(
301 # [x['io'][0], y['io'][0]]))
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300302 return 0
303
koder aka kdanilov7f59d562016-12-26 01:34:23 +0200304 elif opts.subparser_name == 'db':
305 storage = make_storage(opts.storage_dir, existing=True)
306 if opts.cmd == 'show':
307 if len(opts.params) != 1:
308 print("'show' command requires parameter - key to show")
309 return 1
310 pprint.pprint(storage.get(opts.params[0]))
311 else:
312 print("Unknown/not_implemented command {!r}".format(opts.cmd))
313 return 1
314 return 0
koder aka kdanilov108ac362017-01-19 20:17:16 +0200315 elif opts.subparser_name == 'ipython':
316 storage = make_storage(opts.storage_dir, existing=True)
317 from .hlstorage import ResultStorage
318 rstorage = ResultStorage(storage=storage)
319
320 import IPython
321 IPython.embed()
322
323 return 0
koder aka kdanilova732a602017-02-01 20:29:56 +0200324 # elif opts.subparser_name == 'jupyter':
325 # with tempfile.NamedTemporaryFile() as fd:
326 # fd.write(notebook_kern.replace("$STORAGE", opts.storage_dir))
327 # subprocess.call("jupyter notebook ", shell=True)
328 # return 0
329 else:
330 print("Subparser {!r} is not supported".format(opts.subparser_name))
331 return 1
koder aka kdanilov7f59d562016-12-26 01:34:23 +0200332
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200333 report_stages = [] # type: List[Stage]
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200334 if not getattr(opts, "no_report", False):
kdanylov aka koder150b2192017-04-01 16:53:01 +0300335 reporters = opts.reporters.split(",")
336 assert len(set(reporters)) == len(reporters)
337 assert set(reporters).issubset({'txt', 'html'})
338 if 'txt' in reporters:
339 report_stages.append(ConsoleReportStage())
340 if 'html' in reporters:
341 report_stages.append(HtmlReportStage())
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300342
kdanylov aka koder150b2192017-04-01 16:53:01 +0300343 log_config_obj = config.raw().get('logging')
344 assert isinstance(log_config_obj, dict) or log_config_obj is None, "Broken 'logging' option in config"
345 setup_logging(log_config_obj=log_config_obj, log_level=opts.log_level, log_file=storage.get_fname('log'))
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200346
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200347 logger.info("All info would be stored into %r", config.storage_url)
348
349 ctx = TestRun(config, storage)
koder aka kdanilove7e1a4d2016-12-17 20:29:52 +0200350 ctx.rpc_code, ctx.default_rpc_plugins = node.get_rpc_server_code()
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300351
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200352 if opts.ssh_key_passwd is not None:
353 set_ssh_key_passwd(opts.ssh_key_passwd)
koder aka kdanilovf2865172016-12-30 03:35:11 +0200354 elif opts.ssh_key_passwd_kbd:
355 set_ssh_key_passwd(getpass.getpass("Ssh key password: ").strip())
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200356
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200357 stages.sort(key=lambda x: x.priority)
358
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200359 # TODO: run only stages, which have config
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200360 failed = False
361 cleanup_stages = []
koder aka kdanilov7f59d562016-12-26 01:34:23 +0200362
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300363 for stage in stages:
koder aka kdanilove7e1a4d2016-12-17 20:29:52 +0200364 if stage.config_block is not None:
365 if stage.config_block not in ctx.config:
kdanylov aka koder150b2192017-04-01 16:53:01 +0300366 logger.debug("Skip stage %r, as config has no required block %r", stage.name(), stage.config_block)
koder aka kdanilove7e1a4d2016-12-17 20:29:52 +0200367 continue
368
369 cleanup_stages.append(stage)
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200370 try:
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200371 with log_stage(stage):
372 stage.run(ctx)
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200373 except (Exception, KeyboardInterrupt):
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200374 failed = True
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300375 break
koder aka kdanilov7f59d562016-12-26 01:34:23 +0200376 ctx.storage.sync()
377 ctx.storage.sync()
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300378
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200379 logger.debug("Start cleanup")
380 cleanup_failed = False
381 for stage in cleanup_stages[::-1]:
382 try:
koder aka kdanilov962ee5f2016-12-19 02:40:08 +0200383 with log_stage(stage, cleanup=True):
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200384 stage.cleanup(ctx)
385 except:
386 cleanup_failed = True
koder aka kdanilov7f59d562016-12-26 01:34:23 +0200387 ctx.storage.sync()
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300388
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200389 if not failed:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300390 for report_stage in report_stages:
391 with log_stage(report_stage):
koder aka kdanilovffaf48d2016-12-27 02:25:29 +0200392 try:
393 report_stage.run(ctx)
394 except utils.StopTestError:
395 logger.error("Report stage %s requested stop execution", report_stage.name())
396 failed = True
397 break
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300398
koder aka kdanilov7f59d562016-12-26 01:34:23 +0200399 ctx.storage.sync()
400
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200401 logger.info("All info is stored into %r", config.storage_url)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300402
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200403 if failed or cleanup_failed:
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200404 logger.error("Tests are failed. See error details in log above")
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300405 return 1
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200406 else:
407 logger.info("Tests finished successfully")
408 return 0