blob: b96ecf87f428cb1696a93d7f28e9f471e5f894ba [file] [log] [blame]
gstepanov023c1e42015-04-08 15:50:19 +03001import os
koder aka kdanilov57ce4db2015-04-25 21:25:51 +03002import time
koder aka kdanilove21d7472015-02-14 19:02:04 -08003import logging
koder aka kdanilov168f6092015-04-19 02:33:38 +03004import functools
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +03005import contextlib
koder aka kdanilov2c473092015-03-29 17:12:13 +03006import collections
koder aka kdanilov22d134e2016-11-08 11:33:19 +02007from typing import List, Dict, Iterable, Any, Iterator, Mapping, Callable, Tuple, Optional
8from concurrent.futures import ThreadPoolExecutor, Future
koder aka kdanilov88407ff2015-05-26 15:35:57 +03009
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030010from .inode import INode
koder aka kdanilov22d134e2016-11-08 11:33:19 +020011from .discover import discover
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030012from .test_run_class import TestRun
koder aka kdanilov22d134e2016-11-08 11:33:19 +020013from . import pretty_yaml, utils, report, ssh_utils, start_vms, hw_info
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030014
15from .suits.mysql import MysqlTest
16from .suits.itest import TestConfig
17from .suits.io.fio import IOPerfTest
18from .suits.postgres import PgBenchTest
19from .suits.omgbench import OmgTest
koder aka kdanilovbc2c8982015-06-13 02:50:43 +030020
21
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030022TOOL_TYPE_MAPPER = {
23 "io": IOPerfTest,
24 "pgbench": PgBenchTest,
25 "mysql": MysqlTest,
Yulia Portnovab0c977c2015-12-11 19:23:28 +020026 "omg": OmgTest,
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030027}
koder aka kdanilov63ad2062015-04-27 13:11:40 +030028
koder aka kdanilov57ce4db2015-04-25 21:25:51 +030029
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030030logger = logging.getLogger("wally")
koder aka kdanilovcee43342015-04-14 22:52:53 +030031
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080032
koder aka kdanilov22d134e2016-11-08 11:33:19 +020033
34def connect_all(nodes: Iterable[INode],
35 pool: ThreadPoolExecutor,
36 conn_timeout: int = 30,
37 rpc_conn_callback: ssh_utils.RPCBeforeConnCallback = None) -> None:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030038 """Connect to all nodes, log errors
koder aka kdanilov22d134e2016-11-08 11:33:19 +020039 nodes - list of nodes
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030040 """
koder aka kdanilove21d7472015-02-14 19:02:04 -080041
koder aka kdanilov22d134e2016-11-08 11:33:19 +020042 logger.info("Connecting to %s nodes", len(nodes))
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030043
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030044 def connect_ext(node: INode) -> bool:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030045 try:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030046 node.connect_ssh(conn_timeout)
koder aka kdanilov22d134e2016-11-08 11:33:19 +020047 node.rpc, node.rpc_params = ssh_utils.setup_rpc(node, rpc_conn_callback=rpc_conn_callback)
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030048 return True
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030049 except Exception as exc:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030050 logger.error("During connect to {}: {!s}".format(node, exc))
51 return False
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030052
koder aka kdanilov22d134e2016-11-08 11:33:19 +020053 list(pool.map(connect_ext, nodes))
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030054
55 failed_testnodes = []
56 failed_nodes = []
57
58 for node in nodes:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030059 if not node.is_connected():
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030060 if 'testnode' in node.roles:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030061 failed_testnodes.append(node)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030062 else:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030063 failed_nodes.append(node)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030064
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030065 if failed_nodes:
66 msg = "Node(s) {} would be excluded - can't connect"
67 logger.warning(msg.format(",".join(map(str, failed_nodes))))
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030068
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030069 if failed_testnodes:
70 msg = "Can't connect to testnode(s) " + \
71 ",".join(map(str, failed_testnodes))
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030072 logger.error(msg)
73 raise utils.StopTestError(msg)
74
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030075 if not failed_nodes:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030076 logger.info("All nodes connected successfully")
koder aka kdanilov2c473092015-03-29 17:12:13 +030077
78
koder aka kdanilov22d134e2016-11-08 11:33:19 +020079def collect_info_stage(ctx: TestRun, nodes: Iterable[INode]) -> None:
80 futures = {} # type: Dict[str, Future]
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030081
koder aka kdanilov22d134e2016-11-08 11:33:19 +020082 with ctx.get_pool() as pool:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030083 for node in nodes:
koder aka kdanilov22d134e2016-11-08 11:33:19 +020084 hw_info_path = "hw_info/{}".format(node.node_id())
85 if hw_info_path not in ctx.storage:
86 futures[hw_info_path] = pool.submit(hw_info.get_hw_info, node)
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030087
koder aka kdanilov22d134e2016-11-08 11:33:19 +020088 sw_info_path = "sw_info/{}".format(node.node_id())
89 if sw_info_path not in ctx.storage:
90 futures[sw_info_path] = pool.submit(hw_info.get_sw_info, node)
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030091
koder aka kdanilov22d134e2016-11-08 11:33:19 +020092 for path, future in futures.items():
93 ctx.storage[path] = future.result()
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030094
95
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030096@contextlib.contextmanager
koder aka kdanilov22d134e2016-11-08 11:33:19 +020097def suspend_vm_nodes_ctx(unused_nodes: List[INode]) -> Iterator[List[int]]:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030098
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030099 pausable_nodes_ids = [node.os_vm_id for node in unused_nodes
100 if node.os_vm_id is not None]
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300101
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300102 non_pausable = len(unused_nodes) - len(pausable_nodes_ids)
koder aka kdanilov2c473092015-03-29 17:12:13 +0300103
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300104 if 0 != non_pausable:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300105 logger.warning("Can't pause {} nodes".format(
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300106 non_pausable))
107
108 if len(pausable_nodes_ids) != 0:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300109 logger.debug("Try to pause {} unused nodes".format(
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300110 len(pausable_nodes_ids)))
111 start_vms.pause(pausable_nodes_ids)
112
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300113 try:
114 yield pausable_nodes_ids
115 finally:
116 if len(pausable_nodes_ids) != 0:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300117 logger.debug("Unpausing {} nodes".format(
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300118 len(pausable_nodes_ids)))
119 start_vms.unpause(pausable_nodes_ids)
120
121
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300122def generate_result_dir_name(results: str, name: str, params: Dict[str, Any]) -> str:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300123 # make a directory for results
124 all_tests_dirs = os.listdir(results)
125
126 if 'name' in params:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300127 dir_name = "{}_{}".format(name, params['name'])
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300128 else:
129 for idx in range(len(all_tests_dirs) + 1):
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300130 dir_name = "{}_{}".format(name, idx)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300131 if dir_name not in all_tests_dirs:
132 break
133 else:
134 raise utils.StopTestError("Can't select directory for test results")
135
136 return os.path.join(results, dir_name)
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300137
138
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300139@contextlib.contextmanager
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200140def sensor_monitoring(sensor_cfg: Any, nodes: Iterable[INode]) -> Iterator[None]:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300141 # TODO(koder): write this function
142 pass
143
144
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200145def run_tests(cfg: Config,
146 test_block: Dict[str, Dict[str, Any]],
147 nodes: Iterable[INode]) -> Iterator[Tuple[str, List[Any]]]:
148 """Run test from test block"""
149
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300150 test_nodes = [node for node in nodes if 'testnode' in node.roles]
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300151
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300152 if len(test_nodes) == 0:
153 logger.error("No test nodes found")
154 return
155
koder aka kdanilovcee43342015-04-14 22:52:53 +0300156 for name, params in test_block.items():
koder aka kdanilovcee43342015-04-14 22:52:53 +0300157 results = []
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300158
159 # iterate over all node counts
160 limit = params.get('node_limit', len(test_nodes))
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300161 if isinstance(limit, int):
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200162 vm_limits = [limit] # type: List[int]
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300163 else:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300164 list_or_tpl = isinstance(limit, (tuple, list))
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300165 all_ints = list_or_tpl and all(isinstance(climit, int)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300166 for climit in limit)
167 if not all_ints:
168 msg = "'node_limit' parameter ion config should" + \
169 "be either int or list if integers, not {0!r}".format(limit)
170 raise ValueError(msg)
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200171 vm_limits = limit # type: List[int]
koder aka kdanilov652cd802015-04-13 12:21:07 +0300172
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300173 for vm_count in vm_limits:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300174 # select test nodes
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300175 if vm_count == 'all':
176 curr_test_nodes = test_nodes
177 unused_nodes = []
178 else:
179 curr_test_nodes = test_nodes[:vm_count]
180 unused_nodes = test_nodes[vm_count:]
koder aka kdanilove87ae652015-04-20 02:14:35 +0300181
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300182 if 0 == len(curr_test_nodes):
183 continue
koder aka kdanilov652cd802015-04-13 12:21:07 +0300184
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300185 results_path = generate_result_dir_name(cfg.results_storage, name, params)
186 utils.mkdirs_if_unxists(results_path)
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300187
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300188 # suspend all unused virtual nodes
189 if cfg.settings.get('suspend_unused_vms', True):
190 suspend_ctx = suspend_vm_nodes_ctx(unused_nodes)
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300191 else:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300192 suspend_ctx = utils.empty_ctx()
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300193
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300194 with suspend_ctx:
195 resumable_nodes_ids = [node.os_vm_id for node in curr_test_nodes
196 if node.os_vm_id is not None]
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300197
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300198 if len(resumable_nodes_ids) != 0:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300199 logger.debug("Check and unpause {} nodes".format(
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300200 len(resumable_nodes_ids)))
201 start_vms.unpause(resumable_nodes_ids)
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300202
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300203 test_cls = TOOL_TYPE_MAPPER[name]
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300204
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300205 remote_dir = cfg.default_test_local_folder.format(name=name)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300206
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300207 test_cfg = TestConfig(test_cls.__name__,
208 params=params,
209 test_uuid=cfg.run_uuid,
210 nodes=test_nodes,
211 log_directory=results_path,
212 remote_dir=remote_dir)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300213
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300214 t_start = time.time()
215 res = test_cls(test_cfg).run()
216 t_end = time.time()
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300217
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300218 results.append(res)
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300219
220 yield name, results
koder aka kdanilov2c473092015-03-29 17:12:13 +0300221
222
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300223def connect_stage(cfg: Config, ctx: TestRun) -> None:
koder aka kdanilovda45e882015-04-06 02:24:42 +0300224 ctx.clear_calls_stack.append(disconnect_stage)
225 connect_all(ctx.nodes)
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200226 ctx.nodes = [node for node in ctx.nodes if node.is_connected()]
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300227
228
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300229def discover_stage(cfg: Config, ctx: TestRun) -> None:
230 """discover clusters and nodes stage"""
231
koder aka kdanilov652cd802015-04-13 12:21:07 +0300232 if cfg.get('discover') is not None:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300233 discover_objs = [i.strip() for i in cfg.discover.strip().split(",")]
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300234
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300235 nodes = discover(ctx,
236 discover_objs,
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300237 cfg.clouds,
238 cfg.results_storage,
239 not cfg.dont_discover_nodes)
koder aka kdanilov168f6092015-04-19 02:33:38 +0300240
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300241 ctx.nodes.extend(nodes)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300242
243 for url, roles in cfg.get('explicit_nodes', {}).items():
244 ctx.nodes.append(Node(url, roles.split(",")))
245
246
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300247def save_nodes_stage(cfg: Config, ctx: TestRun) -> None:
248 """Save nodes list to file"""
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300249 cluster = {}
250 for node in ctx.nodes:
251 roles = node.roles[:]
252 if 'testnode' in roles:
253 roles.remove('testnode')
254
255 if len(roles) != 0:
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200256 cluster[node.ssh_conn_url] = roles
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300257
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300258 with open(cfg.nodes_report_file, "w") as fd:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300259 fd.write(pretty_yaml.dumps(cluster))
260
261
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300262def reuse_vms_stage(cfg: Config, ctx: TestRun) -> None:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300263 vms_patterns = cfg.get('clouds', {}).get('openstack', {}).get('vms', [])
264 private_key_path = get_vm_keypair(cfg)['keypair_file_private']
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300265
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300266 for creds in vms_patterns:
267 user_name, vm_name_pattern = creds.split("@", 1)
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300268 msg = "Vm like {} lookup failed".format(vm_name_pattern)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300269
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300270 with utils.LogError(msg):
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300271 msg = "Looking for vm with name like {0}".format(vm_name_pattern)
272 logger.debug(msg)
273
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300274 if not start_vms.is_connected():
275 os_creds = get_OS_credentials(cfg, ctx)
276 else:
koder aka kdanilovb7197432015-07-15 00:40:43 +0300277 os_creds = None
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300278
koder aka kdanilovb7197432015-07-15 00:40:43 +0300279 conn = start_vms.nova_connect(os_creds)
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300280 for ip, vm_id in start_vms.find_vms(conn, vm_name_pattern):
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300281 conn_url = "ssh://{user}@{ip}::{key}".format(user=user_name,
282 ip=ip,
283 key=private_key_path)
284 node = Node(conn_url, ['testnode'])
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300285 node.os_vm_id = vm_id
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300286 ctx.nodes.append(node)
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300287
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300288
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300289def get_OS_credentials(cfg: Config, ctx: TestRun) -> None:
koder aka kdanilovcee43342015-04-14 22:52:53 +0300290 creds = None
koder aka kdanilovb7197432015-07-15 00:40:43 +0300291 os_creds = None
koder aka kdanilov8fbb27f2015-07-17 22:23:31 +0300292 force_insecure = False
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300293
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300294 if 'openstack' in cfg.clouds:
295 os_cfg = cfg.clouds['openstack']
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300296 if 'OPENRC' in os_cfg:
297 logger.info("Using OS credentials from " + os_cfg['OPENRC'])
koder aka kdanilovb7197432015-07-15 00:40:43 +0300298 creds_tuple = utils.get_creds_openrc(os_cfg['OPENRC'])
299 os_creds = start_vms.OSCreds(*creds_tuple)
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300300 elif 'ENV' in os_cfg:
301 logger.info("Using OS credentials from shell environment")
koder aka kdanilovb7197432015-07-15 00:40:43 +0300302 os_creds = start_vms.ostack_get_creds()
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300303 elif 'OS_TENANT_NAME' in os_cfg:
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300304 logger.info("Using predefined credentials")
koder aka kdanilovb7197432015-07-15 00:40:43 +0300305 os_creds = start_vms.OSCreds(os_cfg['OS_USERNAME'].strip(),
306 os_cfg['OS_PASSWORD'].strip(),
307 os_cfg['OS_TENANT_NAME'].strip(),
308 os_cfg['OS_AUTH_URL'].strip(),
309 os_cfg.get('OS_INSECURE', False))
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300310
koder aka kdanilov8fbb27f2015-07-17 22:23:31 +0300311 elif 'OS_INSECURE' in os_cfg:
312 force_insecure = os_cfg.get('OS_INSECURE', False)
313
koder aka kdanilovb7197432015-07-15 00:40:43 +0300314 if os_creds is None and 'fuel' in cfg.clouds and \
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300315 'openstack_env' in cfg.clouds['fuel'] and \
koder aka kdanilov88407ff2015-05-26 15:35:57 +0300316 ctx.fuel_openstack_creds is not None:
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300317 logger.info("Using fuel creds")
koder aka kdanilovb7197432015-07-15 00:40:43 +0300318 creds = start_vms.OSCreds(**ctx.fuel_openstack_creds)
319 elif os_creds is None:
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300320 logger.error("Can't found OS credentials")
321 raise utils.StopTestError("Can't found OS credentials", None)
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300322
koder aka kdanilovcee43342015-04-14 22:52:53 +0300323 if creds is None:
koder aka kdanilovb7197432015-07-15 00:40:43 +0300324 creds = os_creds
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300325
koder aka kdanilov8fbb27f2015-07-17 22:23:31 +0300326 if force_insecure and not creds.insecure:
327 creds = start_vms.OSCreds(creds.name,
328 creds.passwd,
329 creds.tenant,
330 creds.auth_url,
331 True)
332
koder aka kdanilov05e15b92016-02-07 19:32:46 +0200333 logger.debug(("OS_CREDS: user={0.name} tenant={0.tenant} " +
koder aka kdanilovb7197432015-07-15 00:40:43 +0300334 "auth_url={0.auth_url} insecure={0.insecure}").format(creds))
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300335
koder aka kdanilovcee43342015-04-14 22:52:53 +0300336 return creds
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300337
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300338
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300339def get_vm_keypair(cfg: Config) -> Dict[str, str]:
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200340 res = {} # type: Dict[str, str]
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300341 for field, ext in (('keypair_file_private', 'pem'),
342 ('keypair_file_public', 'pub')):
343 fpath = cfg.vm_configs.get(field)
344
345 if fpath is None:
346 fpath = cfg.vm_configs['keypair_name'] + "." + ext
347
348 if os.path.isabs(fpath):
349 res[field] = fpath
350 else:
351 res[field] = os.path.join(cfg.config_folder, fpath)
352 return res
353
354
koder aka kdanilov168f6092015-04-19 02:33:38 +0300355@contextlib.contextmanager
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200356def create_vms_ctx(ctx: TestRun, cfg: Config, config, already_has_count: int=0) -> Iterator[List[INode]]:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300357 if config['count'].startswith('='):
358 count = int(config['count'][1:])
359 if count <= already_has_count:
360 logger.debug("Not need new vms")
361 yield []
362 return
363
364 params = cfg.vm_configs[config['cfg_name']].copy()
koder aka kdanilov168f6092015-04-19 02:33:38 +0300365 os_nodes_ids = []
366
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300367 if not start_vms.is_connected():
368 os_creds = get_OS_credentials(cfg, ctx)
369 else:
koder aka kdanilovb7197432015-07-15 00:40:43 +0300370 os_creds = None
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300371
koder aka kdanilovb7197432015-07-15 00:40:43 +0300372 nova = start_vms.nova_connect(os_creds)
koder aka kdanilov168f6092015-04-19 02:33:38 +0300373
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300374 params.update(config)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300375 params.update(get_vm_keypair(cfg))
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300376
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300377 params['group_name'] = cfg.run_uuid
378 params['keypair_name'] = cfg.vm_configs['keypair_name']
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300379
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300380 if not config.get('skip_preparation', False):
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300381 logger.info("Preparing openstack")
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200382 start_vms.prepare_os(nova, params, os_creds)
koder aka kdanilov168f6092015-04-19 02:33:38 +0300383
384 new_nodes = []
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300385 old_nodes = ctx.nodes[:]
koder aka kdanilov168f6092015-04-19 02:33:38 +0300386 try:
koder aka kdanilov10266f42015-09-10 19:26:08 +0300387 for new_node, node_id in start_vms.launch_vms(nova, params, already_has_count):
koder aka kdanilov168f6092015-04-19 02:33:38 +0300388 new_node.roles.append('testnode')
389 ctx.nodes.append(new_node)
390 os_nodes_ids.append(node_id)
391 new_nodes.append(new_node)
392
393 store_nodes_in_log(cfg, os_nodes_ids)
394 ctx.openstack_nodes_ids = os_nodes_ids
395
396 yield new_nodes
397
398 finally:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300399 if not cfg.keep_vm:
koder aka kdanilov168f6092015-04-19 02:33:38 +0300400 shut_down_vms_stage(cfg, ctx)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300401 ctx.nodes = old_nodes
koder aka kdanilov168f6092015-04-19 02:33:38 +0300402
403
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300404def run_tests_stage(cfg: Config, ctx: TestRun) -> None:
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300405 ctx.results = collections.defaultdict(lambda: [])
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300406
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300407 for group in cfg.get('tests', []):
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200408 gitems = list(group.items())
409 if len(gitems) != 1:
koder aka kdanilov170936a2015-06-27 22:51:17 +0300410 msg = "Items in tests section should have len == 1"
411 logger.error(msg)
412 raise utils.StopTestError(msg)
413
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200414 key, config = gitems[0]
koder aka kdanilovcee43342015-04-14 22:52:53 +0300415
416 if 'start_test_nodes' == key:
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300417 if 'openstack' not in config:
418 msg = "No openstack block in config - can't spawn vm's"
419 logger.error(msg)
420 raise utils.StopTestError(msg)
421
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300422 num_test_nodes = 0
423 for node in ctx.nodes:
424 if 'testnode' in node.roles:
425 num_test_nodes += 1
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300426
427 vm_ctx = create_vms_ctx(ctx, cfg, config['openstack'],
428 num_test_nodes)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300429 tests = config.get('tests', [])
430 else:
431 vm_ctx = utils.empty_ctx([])
432 tests = [group]
koder aka kdanilovcee43342015-04-14 22:52:53 +0300433
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300434 if cfg.get('sensors') is None:
435 sensor_ctx = utils.empty_ctx()
436 else:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300437 sensor_ctx = sensor_monitoring(cfg.get('sensors'), ctx.nodes)
koder aka kdanilovcee43342015-04-14 22:52:53 +0300438
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300439 with vm_ctx as new_nodes:
440 if len(new_nodes) != 0:
441 connect_all(new_nodes, True)
442
443 if not cfg.no_tests:
444 for test_group in tests:
445 with sensor_ctx:
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200446 it = run_tests(cfg, test_group, ctx.nodes)
447 for tp, res in it:
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300448 ctx.results[tp].extend(res)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300449
gstepanov023c1e42015-04-08 15:50:19 +0300450
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300451def shut_down_vms_stage(cfg: Config, ctx: TestRun) -> None:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300452 vm_ids_fname = cfg.vm_ids_fname
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300453 if ctx.openstack_nodes_ids is None:
koder aka kdanilov66839a92015-04-11 13:22:31 +0300454 nodes_ids = open(vm_ids_fname).read().split()
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300455 else:
456 nodes_ids = ctx.openstack_nodes_ids
457
koder aka kdanilov652cd802015-04-13 12:21:07 +0300458 if len(nodes_ids) != 0:
459 logger.info("Removing nodes")
460 start_vms.clear_nodes(nodes_ids)
461 logger.info("Nodes has been removed")
gstepanov023c1e42015-04-08 15:50:19 +0300462
koder aka kdanilov66839a92015-04-11 13:22:31 +0300463 if os.path.exists(vm_ids_fname):
464 os.remove(vm_ids_fname)
gstepanov023c1e42015-04-08 15:50:19 +0300465
koder aka kdanilov66839a92015-04-11 13:22:31 +0300466
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200467def store_nodes_in_log(cfg: Config, nodes_ids: Iterable[str]) -> None:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300468 with open(cfg.vm_ids_fname, 'w') as fd:
koder aka kdanilov66839a92015-04-11 13:22:31 +0300469 fd.write("\n".join(nodes_ids))
gstepanov023c1e42015-04-08 15:50:19 +0300470
471
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300472def clear_enviroment(cfg: Config, ctx: TestRun) -> None:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300473 if os.path.exists(cfg.vm_ids_fname):
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300474 shut_down_vms_stage(cfg, ctx)
gstepanov023c1e42015-04-08 15:50:19 +0300475
476
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300477def disconnect_stage(cfg: Config, ctx: TestRun) -> None:
koder aka kdanilov652cd802015-04-13 12:21:07 +0300478 ssh_utils.close_all_sessions()
479
koder aka kdanilovda45e882015-04-06 02:24:42 +0300480 for node in ctx.nodes:
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200481 node.disconnect()
koder aka kdanilovda45e882015-04-06 02:24:42 +0300482
483
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300484def store_raw_results_stage(cfg: Config, ctx: TestRun) -> None:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300485 if os.path.exists(cfg.raw_results):
486 cont = yaml_load(open(cfg.raw_results).read())
koder aka kdanilov66839a92015-04-11 13:22:31 +0300487 else:
488 cont = []
489
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300490 cont.extend(utils.yamable(ctx.results).items())
koder aka kdanilov66839a92015-04-11 13:22:31 +0300491 raw_data = pretty_yaml.dumps(cont)
492
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300493 with open(cfg.raw_results, "w") as fd:
koder aka kdanilov66839a92015-04-11 13:22:31 +0300494 fd.write(raw_data)
495
496
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300497def console_report_stage(cfg: Config, ctx: TestRun) -> None:
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300498 first_report = True
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300499 text_rep_fname = cfg.text_report_file
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300500 with open(text_rep_fname, "w") as fd:
501 for tp, data in ctx.results.items():
502 if 'io' == tp and data is not None:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300503 rep_lst = []
504 for result in data:
505 rep_lst.append(
506 IOPerfTest.format_for_console(list(result)))
507 rep = "\n\n".join(rep_lst)
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300508 elif tp in ['mysql', 'pgbench'] and data is not None:
509 rep = MysqlTest.format_for_console(data)
Yulia Portnovab0c977c2015-12-11 19:23:28 +0200510 elif tp == 'omg':
511 rep = OmgTest.format_for_console(data)
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300512 else:
513 logger.warning("Can't generate text report for " + tp)
514 continue
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300515
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300516 fd.write(rep)
517 fd.write("\n")
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300518
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300519 if first_report:
520 logger.info("Text report were stored in " + text_rep_fname)
521 first_report = False
522
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300523 print("\n" + rep + "\n")
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300524
koder aka kdanilov66839a92015-04-11 13:22:31 +0300525
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300526def test_load_report_stage(cfg: Config, ctx: TestRun) -> None:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300527 load_rep_fname = cfg.load_report_file
koder aka kdanilov88407ff2015-05-26 15:35:57 +0300528 found = False
529 for idx, (tp, data) in enumerate(ctx.results.items()):
530 if 'io' == tp and data is not None:
531 if found:
532 logger.error("Making reports for more than one " +
533 "io block isn't supported! All " +
534 "report, except first are skipped")
535 continue
536 found = True
537 report.make_load_report(idx, cfg['results'], load_rep_fname)
538
539
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300540def html_report_stage(cfg: Config, ctx: TestRun) -> None:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300541 html_rep_fname = cfg.html_report_file
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300542 found = False
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300543 for tp, data in ctx.results.items():
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300544 if 'io' == tp and data is not None:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300545 if found or len(data) > 1:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300546 logger.error("Making reports for more than one " +
547 "io block isn't supported! All " +
548 "report, except first are skipped")
549 continue
550 found = True
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300551 report.make_io_report(list(data[0]),
koder aka kdanilov88407ff2015-05-26 15:35:57 +0300552 cfg.get('comment', ''),
553 html_rep_fname,
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200554 lab_info=ctx.nodes)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300555
koder aka kdanilovda45e882015-04-06 02:24:42 +0300556
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300557def load_data_from_path(test_res_dir: str) -> Mapping[str, List[Any]]:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300558 files = get_test_files(test_res_dir)
559 raw_res = yaml_load(open(files['raw_results']).read())
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300560 res = collections.defaultdict(list)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300561
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300562 for tp, test_lists in raw_res:
563 for tests in test_lists:
564 for suite_name, suite_data in tests.items():
565 result_folder = suite_data[0]
566 res[tp].append(TOOL_TYPE_MAPPER[tp].load(suite_name, result_folder))
koder aka kdanilovda45e882015-04-06 02:24:42 +0300567
koder aka kdanilov6b872662015-06-23 01:58:36 +0300568 return res
569
570
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300571def load_data_from_path_stage(var_dir: str, _, ctx: TestRun) -> None:
koder aka kdanilov6b872662015-06-23 01:58:36 +0300572 for tp, vals in load_data_from_path(var_dir).items():
573 ctx.results.setdefault(tp, []).extend(vals)
koder aka kdanilovbc2c8982015-06-13 02:50:43 +0300574
575
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200576def load_data_from(var_dir: str) -> Callable[[TestRun], None]:
koder aka kdanilov6b872662015-06-23 01:58:36 +0300577 return functools.partial(load_data_from_path_stage, var_dir)