koder aka kdanilov | 4643fd6 | 2015-02-10 16:20:13 -0800 | [diff] [blame] | 1 | import abc |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 2 | import time |
| 3 | import logging |
koder aka kdanilov | 4643fd6 | 2015-02-10 16:20:13 -0800 | [diff] [blame] | 4 | import os.path |
kdanylov aka koder | 2e5fce1 | 2017-05-23 01:47:36 +0300 | [diff] [blame^] | 5 | from typing import Any, List, Optional, Callable, Iterable, cast |
koder aka kdanilov | 652cd80 | 2015-04-13 12:21:07 +0300 | [diff] [blame] | 6 | |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 7 | from concurrent.futures import ThreadPoolExecutor, wait |
koder aka kdanilov | 4643fd6 | 2015-02-10 16:20:13 -0800 | [diff] [blame] | 8 | |
kdanylov aka koder | 026e5f2 | 2017-05-15 01:04:39 +0300 | [diff] [blame] | 9 | from cephlib.node import IRPCNode |
kdanylov aka koder | 2e5fce1 | 2017-05-23 01:47:36 +0300 | [diff] [blame^] | 10 | from cephlib.units import unit_conversion_coef_f |
kdanylov aka koder | 026e5f2 | 2017-05-15 01:04:39 +0300 | [diff] [blame] | 11 | |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 12 | from ..utils import StopTestError, get_time_interval_printable_info |
kdanylov aka koder | 026e5f2 | 2017-05-15 01:04:39 +0300 | [diff] [blame] | 13 | from ..result_classes import SuiteConfig, JobConfig, TimeSeries, IWallyStorage |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 14 | |
koder aka kdanilov | 4af1c1d | 2015-05-18 15:48:58 +0300 | [diff] [blame] | 15 | |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 16 | logger = logging.getLogger("wally") |
koder aka kdanilov | 88407ff | 2015-05-26 15:35:57 +0300 | [diff] [blame] | 17 | |
| 18 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 19 | __doc__ = "Contains base classes for performance tests" |
| 20 | |
| 21 | |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 22 | class PerfTest(metaclass=abc.ABCMeta): |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 23 | """Base class for all tests""" |
| 24 | name = None # type: str |
| 25 | max_retry = 3 |
| 26 | retry_time = 30 |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 27 | job_config_cls = None # type: type |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 28 | |
kdanylov aka koder | 026e5f2 | 2017-05-15 01:04:39 +0300 | [diff] [blame] | 29 | def __init__(self, storage: IWallyStorage, suite: SuiteConfig, on_idle: Callable[[], None] = None) -> None: |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 30 | self.suite = suite |
koder aka kdanilov | e2de58c | 2015-04-24 22:59:36 +0300 | [diff] [blame] | 31 | self.stop_requested = False |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 32 | self.sorted_nodes_ids = sorted(node.node_id for node in self.suite.nodes) |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 33 | self.on_idle = on_idle |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 34 | self.storage = storage |
koder aka kdanilov | e2de58c | 2015-04-24 22:59:36 +0300 | [diff] [blame] | 35 | |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 36 | def request_stop(self) -> None: |
koder aka kdanilov | e2de58c | 2015-04-24 22:59:36 +0300 | [diff] [blame] | 37 | self.stop_requested = True |
koder aka kdanilov | 2066daf | 2015-04-23 21:05:41 +0300 | [diff] [blame] | 38 | |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 39 | def join_remote(self, path: str) -> str: |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 40 | return os.path.join(self.suite.remote_dir, path) |
koder aka kdanilov | 4500a5f | 2015-04-17 16:55:17 +0300 | [diff] [blame] | 41 | |
koder aka kdanilov | 4af1c1d | 2015-05-18 15:48:58 +0300 | [diff] [blame] | 42 | @abc.abstractmethod |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 43 | def run(self) -> None: |
koder aka kdanilov | 4643fd6 | 2015-02-10 16:20:13 -0800 | [diff] [blame] | 44 | pass |
| 45 | |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 46 | @abc.abstractmethod |
koder aka kdanilov | 39e449e | 2016-12-17 15:15:26 +0200 | [diff] [blame] | 47 | def format_for_console(self, data: Any) -> str: |
koder aka kdanilov | ec1b973 | 2015-04-23 20:43:29 +0300 | [diff] [blame] | 48 | pass |
| 49 | |
koder aka kdanilov | 4643fd6 | 2015-02-10 16:20:13 -0800 | [diff] [blame] | 50 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 51 | class ThreadedTest(PerfTest, metaclass=abc.ABCMeta): |
| 52 | """Base class for tests, which spawn separated thread for each node""" |
| 53 | |
| 54 | # max allowed time difference between starts and stops of run of the same test on different test nodes |
| 55 | # used_max_diff = max((min_run_time * max_rel_time_diff), max_time_diff) |
| 56 | max_time_diff = 5 |
| 57 | max_rel_time_diff = 0.05 |
koder aka kdanilov | ffaf48d | 2016-12-27 02:25:29 +0200 | [diff] [blame] | 58 | load_profile_name = None # type: str |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 59 | |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 60 | def __init__(self, *args, **kwargs) -> None: |
| 61 | PerfTest.__init__(self, *args, **kwargs) |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 62 | self.job_configs = None # type: List[JobConfig] |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 63 | |
| 64 | @abc.abstractmethod |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 65 | def get_expected_runtime(self, iter_cfg: JobConfig) -> Optional[int]: |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 66 | pass |
| 67 | |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 68 | def get_not_done_jobs(self) -> Iterable[JobConfig]: |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 69 | jobs_map = {job.storage_id: job for job in self.job_configs} |
| 70 | already_in_storage = set() |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 71 | for db_config in cast(List[JobConfig], self.storage.iter_job(self.suite)): |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 72 | if db_config.storage_id in jobs_map: |
| 73 | job = jobs_map[db_config.storage_id] |
| 74 | if job != db_config: |
| 75 | logger.error("Test info at '%s.%s' is not equal to expected config for iteration %s.%s." + |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 76 | " Maybe configuration was changed before test was restarted. " + |
| 77 | "DB cfg is:\n %s\nExpected cfg is:\n %s\nFix DB or rerun test from beginning", |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 78 | self.suite.storage_id, job.storage_id, self.name, job.summary, |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 79 | str(db_config).replace("\n", "\n "), |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 80 | str(job).replace("\n", "\n ")) |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 81 | raise StopTestError() |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 82 | |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 83 | logger.info("Test iteration %s.%s found in storage and will be skipped", self.name, job.summary) |
| 84 | already_in_storage.add(db_config.storage_id) |
| 85 | |
| 86 | return [job for job in self.job_configs if job.storage_id not in already_in_storage] |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 87 | |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 88 | def run(self) -> None: |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 89 | self.storage.put_or_check_suite(self.suite) |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 90 | |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 91 | not_in_storage = list(self.get_not_done_jobs()) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 92 | if not not_in_storage: |
| 93 | logger.info("All test iteration in storage already. Skip test") |
| 94 | return |
| 95 | |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 96 | logger.debug("Run test %s with profile %r on nodes %s.", self.name, |
| 97 | self.load_profile_name, |
| 98 | ",".join(self.sorted_nodes_ids)) |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 99 | logger.debug("Prepare nodes") |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 100 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 101 | |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 102 | with ThreadPoolExecutor(len(self.suite.nodes)) as pool: |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 103 | # config nodes |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 104 | list(pool.map(self.config_node, self.suite.nodes)) |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 105 | |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 106 | run_times = list(map(self.get_expected_runtime, not_in_storage)) |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 107 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 108 | if None not in run_times: |
kdanylov aka koder | 84de1e4 | 2017-05-22 14:00:07 +0300 | [diff] [blame] | 109 | # +10s - is a rough estimation for additional operations per iteration |
| 110 | expected_run_time = int(sum(run_times) + 10 * len(not_in_storage)) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 111 | |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 112 | exec_time_s, end_dt_s = get_time_interval_printable_info(expected_run_time) |
kdanylov aka koder | 736e5c1 | 2017-05-07 17:27:14 +0300 | [diff] [blame] | 113 | logger.info("Entire test should takes around %s and finish at %s", exec_time_s, end_dt_s) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 114 | |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 115 | for job in not_in_storage: |
| 116 | results = [] # type: List[TimeSeries] |
| 117 | for retry_idx in range(self.max_retry): |
kdanylov aka koder | 3a9e5db | 2017-05-09 20:00:44 +0300 | [diff] [blame] | 118 | logger.info("Preparing job %s", job.params.summary) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 119 | |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 120 | # prepare nodes for new iterations |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 121 | wait([pool.submit(self.prepare_iteration, node, job) for node in self.suite.nodes]) |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 122 | |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 123 | expected_job_time = self.get_expected_runtime(job) |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 124 | exec_time_s, end_dt_s = get_time_interval_printable_info(expected_job_time) |
kdanylov aka koder | 736e5c1 | 2017-05-07 17:27:14 +0300 | [diff] [blame] | 125 | logger.info("Job should takes around %s and finish at %s", exec_time_s, end_dt_s) |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 126 | |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 127 | jfutures = [pool.submit(self.run_iteration, node, job) for node in self.suite.nodes] |
| 128 | failed = False |
| 129 | for future in jfutures: |
| 130 | try: |
| 131 | results.extend(future.result()) |
| 132 | except EnvironmentError: |
| 133 | failed = True |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 134 | |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 135 | if not failed: |
| 136 | break |
| 137 | |
| 138 | if self.max_retry - 1 == retry_idx: |
| 139 | logger.exception("Fio failed") |
| 140 | raise StopTestError() |
| 141 | |
| 142 | logger.exception("During fio run") |
| 143 | logger.info("Sleeping %ss and retrying job", self.retry_time) |
| 144 | time.sleep(self.retry_time) |
| 145 | results = [] |
| 146 | |
| 147 | # per node jobs start and stop times |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 148 | start_times = [] # type: List[int] |
| 149 | stop_times = [] # type: List[int] |
| 150 | |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 151 | for ts in results: |
| 152 | self.storage.put_ts(ts) |
| 153 | if len(ts.times) >= 2: # type: ignore |
| 154 | start_times.append(ts.times[0]) |
| 155 | stop_times.append(ts.times[-1]) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 156 | |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 157 | if len(start_times) > 0: |
| 158 | min_start_time = min(start_times) |
| 159 | max_start_time = max(start_times) |
| 160 | min_stop_time = min(stop_times) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 161 | |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 162 | max_allowed_time_diff = int((min_stop_time - max_start_time) * self.max_rel_time_diff) |
| 163 | max_allowed_time_diff = max(max_allowed_time_diff, self.max_time_diff) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 164 | |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 165 | if min_start_time + self.max_time_diff < max_allowed_time_diff: |
| 166 | logger.warning("Too large difference in %s:%s start time - %s. " + |
| 167 | "Max recommended difference is %s", |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 168 | self.name, job.summary, |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 169 | max_start_time - min_start_time, self.max_time_diff) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 170 | |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 171 | if min_stop_time + self.max_time_diff < max_allowed_time_diff: |
| 172 | logger.warning("Too large difference in %s:%s stop time - %s. " + |
| 173 | "Max recommended difference is %s", |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 174 | self.name, job.summary, |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 175 | max_start_time - min_start_time, self.max_time_diff) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 176 | |
kdanylov aka koder | 2e5fce1 | 2017-05-23 01:47:36 +0300 | [diff] [blame^] | 177 | one_s = int(unit_conversion_coef_f('s', results[0].time_units)) |
| 178 | job.reliable_info_range = (int(max_start_time) + one_s, int(min_stop_time) - one_s) |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 179 | |
| 180 | self.storage.put_job(self.suite, job) |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 181 | self.storage.sync() |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 182 | |
| 183 | if self.on_idle is not None: |
| 184 | self.on_idle() |
| 185 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 186 | @abc.abstractmethod |
| 187 | def config_node(self, node: IRPCNode) -> None: |
| 188 | pass |
| 189 | |
| 190 | @abc.abstractmethod |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 191 | def prepare_iteration(self, node: IRPCNode, job: JobConfig) -> None: |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 192 | pass |
| 193 | |
| 194 | @abc.abstractmethod |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 195 | def run_iteration(self, node: IRPCNode, job: JobConfig) -> List[TimeSeries]: |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 196 | pass |
| 197 | |
| 198 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 199 | class TwoScriptTest(ThreadedTest, metaclass=abc.ABCMeta): |
| 200 | def __init__(self, *dt, **mp) -> None: |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 201 | ThreadedTest.__init__(self, *dt, **mp) |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 202 | self.prerun_script = self.suite.params['prerun_script'] |
| 203 | self.run_script = self.suite.params['run_script'] |
| 204 | self.prerun_tout = self.suite.params.get('prerun_tout', 3600) |
| 205 | self.run_tout = self.suite.params.get('run_tout', 3600) |
| 206 | # TODO: fix job_configs field |
| 207 | raise NotImplementedError("Fix job configs") |
Yulia Portnova | 7ddfa73 | 2015-02-24 17:32:58 +0200 | [diff] [blame] | 208 | |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 209 | def get_expected_runtime(self, job: JobConfig) -> Optional[int]: |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 210 | return None |
Yulia Portnova | 7ddfa73 | 2015-02-24 17:32:58 +0200 | [diff] [blame] | 211 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 212 | def config_node(self, node: IRPCNode) -> None: |
| 213 | node.copy_file(self.run_script, self.join_remote(self.run_script)) |
| 214 | node.copy_file(self.prerun_script, self.join_remote(self.prerun_script)) |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 215 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 216 | cmd = self.join_remote(self.prerun_script) |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 217 | cmd += ' ' + self.suite.params.get('prerun_opts', '') |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 218 | node.run(cmd, timeout=self.prerun_tout) |
Yulia Portnova | 7ddfa73 | 2015-02-24 17:32:58 +0200 | [diff] [blame] | 219 | |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 220 | def prepare_iteration(self, node: IRPCNode, job: JobConfig) -> None: |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 221 | pass |
| 222 | |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 223 | def run_iteration(self, node: IRPCNode, job: JobConfig) -> List[TimeSeries]: |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 224 | # TODO: have to store logs |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 225 | cmd = self.join_remote(self.run_script) |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 226 | cmd += ' ' + self.suite.params.get('run_opts', '') |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 227 | return self.parse_results(node.run(cmd, timeout=self.run_tout)) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 228 | |
| 229 | @abc.abstractmethod |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 230 | def parse_results(self, data: str) -> List[TimeSeries]: |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 231 | pass |
| 232 | |