blob: d8ef685c43366b7dd927ef5b7ddf0b6d7a5db570 [file] [log] [blame]
gstepanov023c1e42015-04-08 15:50:19 +03001import os
koder aka kdanilove21d7472015-02-14 19:02:04 -08002import logging
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +03003import contextlib
koder aka kdanilov73084622016-11-16 21:51:08 +02004from typing import List, Dict, Iterable, Iterator, Tuple, Optional, Union, cast
koder aka kdanilov22d134e2016-11-08 11:33:19 +02005from concurrent.futures import ThreadPoolExecutor, Future
koder aka kdanilov88407ff2015-05-26 15:35:57 +03006
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +02007from .node_interfaces import NodeInfo, IRPCNode
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +03008from .test_run_class import TestRun
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +02009from .discover import discover
koder aka kdanilov22d134e2016-11-08 11:33:19 +020010from . import pretty_yaml, utils, report, ssh_utils, start_vms, hw_info
koder aka kdanilov73084622016-11-16 21:51:08 +020011from .node import setup_rpc, connect
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +020012from .config import ConfigBlock, Config
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030013
14from .suits.mysql import MysqlTest
15from .suits.itest import TestConfig
16from .suits.io.fio import IOPerfTest
17from .suits.postgres import PgBenchTest
18from .suits.omgbench import OmgTest
koder aka kdanilovbc2c8982015-06-13 02:50:43 +030019
20
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030021TOOL_TYPE_MAPPER = {
22 "io": IOPerfTest,
23 "pgbench": PgBenchTest,
24 "mysql": MysqlTest,
Yulia Portnovab0c977c2015-12-11 19:23:28 +020025 "omg": OmgTest,
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030026}
koder aka kdanilov63ad2062015-04-27 13:11:40 +030027
koder aka kdanilov57ce4db2015-04-25 21:25:51 +030028
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030029logger = logging.getLogger("wally")
koder aka kdanilovcee43342015-04-14 22:52:53 +030030
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080031
koder aka kdanilov73084622016-11-16 21:51:08 +020032def connect_all(nodes_info: List[NodeInfo], pool: ThreadPoolExecutor, conn_timeout: int = 30) -> List[IRPCNode]:
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +020033 """Connect to all nodes, log errors"""
koder aka kdanilove21d7472015-02-14 19:02:04 -080034
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +020035 logger.info("Connecting to %s nodes", len(nodes_info))
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030036
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +020037 def connect_ext(node_info: NodeInfo) -> Tuple[bool, Union[IRPCNode, NodeInfo]]:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030038 try:
koder aka kdanilov73084622016-11-16 21:51:08 +020039 ssh_node = connect(node_info, conn_timeout=conn_timeout)
40 # TODO(koder): need to pass all required rpc bytes to this call
41 return True, setup_rpc(ssh_node, b"")
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030042 except Exception as exc:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030043 logger.error("During connect to {}: {!s}".format(node, exc))
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +020044 return False, node_info
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030045
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +020046 failed_testnodes = [] # type: List[NodeInfo]
47 failed_nodes = [] # type: List[NodeInfo]
48 ready = [] # type: List[IRPCNode]
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030049
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +020050 for ok, node in pool.map(connect_ext, nodes_info):
51 if not ok:
52 node = cast(NodeInfo, node)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030053 if 'testnode' in node.roles:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030054 failed_testnodes.append(node)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030055 else:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030056 failed_nodes.append(node)
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +020057 else:
58 ready.append(cast(IRPCNode, node))
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030059
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030060 if failed_nodes:
61 msg = "Node(s) {} would be excluded - can't connect"
62 logger.warning(msg.format(",".join(map(str, failed_nodes))))
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030063
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030064 if failed_testnodes:
65 msg = "Can't connect to testnode(s) " + \
66 ",".join(map(str, failed_testnodes))
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030067 logger.error(msg)
68 raise utils.StopTestError(msg)
69
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030070 if not failed_nodes:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030071 logger.info("All nodes connected successfully")
koder aka kdanilov2c473092015-03-29 17:12:13 +030072
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +020073 return ready
koder aka kdanilov2c473092015-03-29 17:12:13 +030074
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +020075
koder aka kdanilov73084622016-11-16 21:51:08 +020076def collect_info_stage(ctx: TestRun) -> None:
77 futures = {} # type: Dict[str, Future]
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030078
koder aka kdanilov22d134e2016-11-08 11:33:19 +020079 with ctx.get_pool() as pool:
koder aka kdanilov73084622016-11-16 21:51:08 +020080 for node in ctx.nodes:
81 hw_info_path = "hw_info/{}".format(node.info.node_id())
koder aka kdanilov22d134e2016-11-08 11:33:19 +020082 if hw_info_path not in ctx.storage:
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +020083 futures[hw_info_path] = pool.submit(hw_info.get_hw_info, node), node
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030084
koder aka kdanilov73084622016-11-16 21:51:08 +020085 sw_info_path = "sw_info/{}".format(node.info.node_id())
koder aka kdanilov22d134e2016-11-08 11:33:19 +020086 if sw_info_path not in ctx.storage:
87 futures[sw_info_path] = pool.submit(hw_info.get_sw_info, node)
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030088
koder aka kdanilov22d134e2016-11-08 11:33:19 +020089 for path, future in futures.items():
90 ctx.storage[path] = future.result()
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030091
92
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030093@contextlib.contextmanager
koder aka kdanilov73084622016-11-16 21:51:08 +020094def suspend_vm_nodes_ctx(ctx: TestRun, unused_nodes: List[IRPCNode]) -> Iterator[List[int]]:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030095
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +020096 pausable_nodes_ids = [cast(int, node.info.os_vm_id)
97 for node in unused_nodes
98 if node.info.os_vm_id is not None]
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030099
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300100 non_pausable = len(unused_nodes) - len(pausable_nodes_ids)
koder aka kdanilov2c473092015-03-29 17:12:13 +0300101
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200102 if non_pausable:
103 logger.warning("Can't pause {} nodes".format(non_pausable))
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300104
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200105 if pausable_nodes_ids:
106 logger.debug("Try to pause {} unused nodes".format(len(pausable_nodes_ids)))
koder aka kdanilov73084622016-11-16 21:51:08 +0200107 with ctx.get_pool() as pool:
108 start_vms.pause(ctx.os_connection, pausable_nodes_ids, pool)
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300109
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300110 try:
111 yield pausable_nodes_ids
112 finally:
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200113 if pausable_nodes_ids:
114 logger.debug("Unpausing {} nodes".format(len(pausable_nodes_ids)))
koder aka kdanilov73084622016-11-16 21:51:08 +0200115 with ctx.get_pool() as pool:
116 start_vms.unpause(ctx.os_connection, pausable_nodes_ids, pool)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300117
118
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200119def run_tests(ctx: TestRun, test_block: ConfigBlock, nodes: List[IRPCNode]) -> None:
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200120 """Run test from test block"""
121
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200122 test_nodes = [node for node in nodes if 'testnode' in node.info.roles]
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300123
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200124 if not test_nodes:
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300125 logger.error("No test nodes found")
126 return
127
koder aka kdanilovcee43342015-04-14 22:52:53 +0300128 for name, params in test_block.items():
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200129 vm_count = params.get('node_limit', None) # type: Optional[int]
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300130
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200131 # select test nodes
132 if vm_count is None:
133 curr_test_nodes = test_nodes
koder aka kdanilov73084622016-11-16 21:51:08 +0200134 unused_nodes = [] # type: List[IRPCNode]
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300135 else:
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200136 curr_test_nodes = test_nodes[:vm_count]
137 unused_nodes = test_nodes[vm_count:]
koder aka kdanilov652cd802015-04-13 12:21:07 +0300138
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200139 if not curr_test_nodes:
140 logger.error("No nodes found for test, skipping it.")
141 continue
koder aka kdanilove87ae652015-04-20 02:14:35 +0300142
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200143 # results_path = generate_result_dir_name(cfg.results_storage, name, params)
144 # utils.mkdirs_if_unxists(results_path)
koder aka kdanilov652cd802015-04-13 12:21:07 +0300145
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200146 # suspend all unused virtual nodes
147 if ctx.config.get('suspend_unused_vms', True):
koder aka kdanilov73084622016-11-16 21:51:08 +0200148 suspend_ctx = suspend_vm_nodes_ctx(ctx, unused_nodes)
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200149 else:
150 suspend_ctx = utils.empty_ctx()
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300151
koder aka kdanilov73084622016-11-16 21:51:08 +0200152 resumable_nodes_ids = [cast(int, node.info.os_vm_id)
153 for node in curr_test_nodes
154 if node.info.os_vm_id is not None]
155
156 if resumable_nodes_ids:
157 logger.debug("Check and unpause {} nodes".format(len(resumable_nodes_ids)))
158
159 with ctx.get_pool() as pool:
160 start_vms.unpause(ctx.os_connection, resumable_nodes_ids, pool)
161
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200162 with suspend_ctx:
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200163 test_cls = TOOL_TYPE_MAPPER[name]
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200164 remote_dir = ctx.config.default_test_local_folder.format(name=name, uuid=ctx.config.run_uuid)
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200165 test_cfg = TestConfig(test_cls.__name__,
166 params=params,
167 run_uuid=ctx.config.run_uuid,
168 nodes=test_nodes,
169 storage=ctx.storage,
170 remote_dir=remote_dir)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300171
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200172 test_cls(test_cfg).run()
koder aka kdanilov2c473092015-03-29 17:12:13 +0300173
174
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200175def connect_stage(ctx: TestRun) -> None:
koder aka kdanilovda45e882015-04-06 02:24:42 +0300176 ctx.clear_calls_stack.append(disconnect_stage)
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200177
178 with ctx.get_pool() as pool:
koder aka kdanilov73084622016-11-16 21:51:08 +0200179 ctx.nodes = connect_all(ctx.nodes_info, pool)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300180
181
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200182def discover_stage(ctx: TestRun) -> None:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300183 """discover clusters and nodes stage"""
184
koder aka kdanilov73084622016-11-16 21:51:08 +0200185 # TODO(koder): Properly store discovery info and check if it available to skip phase
186
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200187 discover_info = ctx.config.get('discover')
188 if discover_info:
koder aka kdanilov73084622016-11-16 21:51:08 +0200189 if "discovered_nodes" in ctx.storage:
190 nodes = ctx.storage.load_list("discovered_nodes", NodeInfo)
191 ctx.fuel_openstack_creds = ctx.storage.load("fuel_openstack_creds", start_vms.OSCreds)
192 else:
193 discover_objs = [i.strip() for i in discover_info.strip().split(",")]
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300194
koder aka kdanilov73084622016-11-16 21:51:08 +0200195 ctx.fuel_openstack_creds, nodes = discover.discover(discover_objs,
196 ctx.config.clouds,
197 not ctx.config.dont_discover_nodes)
koder aka kdanilov168f6092015-04-19 02:33:38 +0300198
koder aka kdanilov73084622016-11-16 21:51:08 +0200199 ctx.storage["fuel_openstack_creds"] = ctx.fuel_openstack_creds # type: ignore
200 ctx.storage["discovered_nodes"] = nodes # type: ignore
201 ctx.nodes_info.extend(nodes)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300202
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200203 for url, roles in ctx.config.get('explicit_nodes', {}).items():
koder aka kdanilov73084622016-11-16 21:51:08 +0200204 creds = ssh_utils.parse_ssh_uri(url)
205 roles = set(roles.split(","))
206 ctx.nodes_info.append(NodeInfo(creds, roles))
koder aka kdanilovda45e882015-04-06 02:24:42 +0300207
208
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200209def save_nodes_stage(ctx: TestRun) -> None:
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +0300210 """Save nodes list to file"""
koder aka kdanilov73084622016-11-16 21:51:08 +0200211 ctx.storage['nodes'] = ctx.nodes_info # type: ignore
212
213
214def ensure_connected_to_openstack(ctx: TestRun) -> None:
215 if not ctx.os_connection is None:
216 if ctx.os_creds is None:
217 ctx.os_creds = get_OS_credentials(ctx)
218 ctx.os_connection = start_vms.os_connect(ctx.os_creds)
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300219
220
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200221def reuse_vms_stage(ctx: TestRun) -> None:
koder aka kdanilov73084622016-11-16 21:51:08 +0200222 if "reused_nodes" in ctx.storage:
223 ctx.nodes_info.extend(ctx.storage.load_list("reused_nodes", NodeInfo))
224 else:
225 reused_nodes = []
226 vms_patterns = ctx.config.get('clouds/openstack/vms', [])
227 private_key_path = get_vm_keypair_path(ctx.config)[0]
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300228
koder aka kdanilov73084622016-11-16 21:51:08 +0200229 for creds in vms_patterns:
230 user_name, vm_name_pattern = creds.split("@", 1)
231 msg = "Vm like {} lookup failed".format(vm_name_pattern)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300232
koder aka kdanilov73084622016-11-16 21:51:08 +0200233 with utils.LogError(msg):
234 msg = "Looking for vm with name like {0}".format(vm_name_pattern)
235 logger.debug(msg)
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300236
koder aka kdanilov73084622016-11-16 21:51:08 +0200237 ensure_connected_to_openstack(ctx)
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300238
koder aka kdanilov73084622016-11-16 21:51:08 +0200239 for ip, vm_id in start_vms.find_vms(ctx.os_connection, vm_name_pattern):
240 creds = ssh_utils.ConnCreds(host=ip, user=user_name, key_file=private_key_path)
241 node_info = NodeInfo(creds, {'testnode'})
242 node_info.os_vm_id = vm_id
243 reused_nodes.append(node_info)
244 ctx.nodes_info.append(node_info)
245
246 ctx.storage["reused_nodes"] = reused_nodes # type: ignore
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300247
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300248
koder aka kdanilov73084622016-11-16 21:51:08 +0200249def get_OS_credentials(ctx: TestRun) -> start_vms.OSCreds:
250
251 if "openstack_openrc" in ctx.storage:
252 return ctx.storage.load("openstack_openrc", start_vms.OSCreds)
253
koder aka kdanilovcee43342015-04-14 22:52:53 +0300254 creds = None
koder aka kdanilovb7197432015-07-15 00:40:43 +0300255 os_creds = None
koder aka kdanilov8fbb27f2015-07-17 22:23:31 +0300256 force_insecure = False
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200257 cfg = ctx.config
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300258
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300259 if 'openstack' in cfg.clouds:
260 os_cfg = cfg.clouds['openstack']
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300261 if 'OPENRC' in os_cfg:
262 logger.info("Using OS credentials from " + os_cfg['OPENRC'])
koder aka kdanilovb7197432015-07-15 00:40:43 +0300263 creds_tuple = utils.get_creds_openrc(os_cfg['OPENRC'])
264 os_creds = start_vms.OSCreds(*creds_tuple)
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300265 elif 'ENV' in os_cfg:
266 logger.info("Using OS credentials from shell environment")
koder aka kdanilov73084622016-11-16 21:51:08 +0200267 os_creds = start_vms.get_openstack_credentials()
koder aka kdanilovfd2cfa52015-05-20 03:17:42 +0300268 elif 'OS_TENANT_NAME' in os_cfg:
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300269 logger.info("Using predefined credentials")
koder aka kdanilovb7197432015-07-15 00:40:43 +0300270 os_creds = start_vms.OSCreds(os_cfg['OS_USERNAME'].strip(),
271 os_cfg['OS_PASSWORD'].strip(),
272 os_cfg['OS_TENANT_NAME'].strip(),
273 os_cfg['OS_AUTH_URL'].strip(),
274 os_cfg.get('OS_INSECURE', False))
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300275
koder aka kdanilov8fbb27f2015-07-17 22:23:31 +0300276 elif 'OS_INSECURE' in os_cfg:
277 force_insecure = os_cfg.get('OS_INSECURE', False)
278
koder aka kdanilov73084622016-11-16 21:51:08 +0200279 if os_creds is None and 'fuel' in cfg.clouds and 'openstack_env' in cfg.clouds['fuel'] and \
280 ctx.fuel_openstack_creds is not None:
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300281 logger.info("Using fuel creds")
koder aka kdanilov73084622016-11-16 21:51:08 +0200282 creds = ctx.fuel_openstack_creds
koder aka kdanilovb7197432015-07-15 00:40:43 +0300283 elif os_creds is None:
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300284 logger.error("Can't found OS credentials")
285 raise utils.StopTestError("Can't found OS credentials", None)
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300286
koder aka kdanilovcee43342015-04-14 22:52:53 +0300287 if creds is None:
koder aka kdanilovb7197432015-07-15 00:40:43 +0300288 creds = os_creds
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300289
koder aka kdanilov8fbb27f2015-07-17 22:23:31 +0300290 if force_insecure and not creds.insecure:
291 creds = start_vms.OSCreds(creds.name,
292 creds.passwd,
293 creds.tenant,
294 creds.auth_url,
295 True)
296
koder aka kdanilov05e15b92016-02-07 19:32:46 +0200297 logger.debug(("OS_CREDS: user={0.name} tenant={0.tenant} " +
koder aka kdanilovb7197432015-07-15 00:40:43 +0300298 "auth_url={0.auth_url} insecure={0.insecure}").format(creds))
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300299
koder aka kdanilov73084622016-11-16 21:51:08 +0200300 ctx.storage["openstack_openrc"] = creds # type: ignore
koder aka kdanilovcee43342015-04-14 22:52:53 +0300301 return creds
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300302
koder aka kdanilov1c2b5112015-04-10 16:53:51 +0300303
koder aka kdanilov73084622016-11-16 21:51:08 +0200304def get_vm_keypair_path(cfg: Config) -> Tuple[str, str]:
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200305 key_name = cfg.vm_configs['keypair_name']
306 private_path = os.path.join(cfg.settings_dir, key_name + "_private.pem")
307 public_path = os.path.join(cfg.settings_dir, key_name + "_public.pub")
308 return (private_path, public_path)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300309
310
koder aka kdanilov168f6092015-04-19 02:33:38 +0300311@contextlib.contextmanager
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200312def create_vms_ctx(ctx: TestRun, vm_config: ConfigBlock, already_has_count: int = 0) -> Iterator[List[NodeInfo]]:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300313
koder aka kdanilov73084622016-11-16 21:51:08 +0200314 if 'spawned_vm_ids' in ctx.storage:
315 os_nodes_ids = ctx.storage.get('spawned_vm_ids', []) # type: List[int]
316 new_nodes = [] # type: List[NodeInfo]
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300317
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200318 # TODO(koder): reconnect to old VM's
319 raise NotImplementedError("Reconnect to old vms is not implemented")
koder aka kdanilov73084622016-11-16 21:51:08 +0200320 else:
321 os_nodes_ids = []
322 new_nodes = []
323 no_spawn = False
324 if vm_config['count'].startswith('='):
325 count = int(vm_config['count'][1:])
326 if count <= already_has_count:
327 logger.debug("Not need new vms")
328 no_spawn = True
koder aka kdanilov168f6092015-04-19 02:33:38 +0300329
koder aka kdanilov73084622016-11-16 21:51:08 +0200330 if not no_spawn:
331 ensure_connected_to_openstack(ctx)
332 params = ctx.config.vm_configs[vm_config['cfg_name']].copy()
333 params.update(vm_config)
334 params.update(get_vm_keypair_path(ctx.config))
335 params['group_name'] = ctx.config.run_uuid
336 params['keypair_name'] = ctx.config.vm_configs['keypair_name']
koder aka kdanilov168f6092015-04-19 02:33:38 +0300337
koder aka kdanilov73084622016-11-16 21:51:08 +0200338 if not vm_config.get('skip_preparation', False):
339 logger.info("Preparing openstack")
340 start_vms.prepare_os(ctx.os_connection, params)
koder aka kdanilov168f6092015-04-19 02:33:38 +0300341
koder aka kdanilov73084622016-11-16 21:51:08 +0200342 with ctx.get_pool() as pool:
343 for node_info in start_vms.launch_vms(ctx.os_connection, params, pool, already_has_count):
344 node_info.roles.add('testnode')
345 os_nodes_ids.append(node_info.os_vm_id)
346 new_nodes.append(node_info)
koder aka kdanilov168f6092015-04-19 02:33:38 +0300347
koder aka kdanilov73084622016-11-16 21:51:08 +0200348 ctx.storage['spawned_vm_ids'] = os_nodes_ids # type: ignore
349 yield new_nodes
350
351 # keep nodes in case of error for future test restart
352 if not ctx.config.keep_vm:
353 shut_down_vms_stage(ctx, os_nodes_ids)
354
355 del ctx.storage['spawned_vm_ids']
356
357
358@contextlib.contextmanager
359def sensor_monitoring(ctx: TestRun, cfg: ConfigBlock, nodes: List[IRPCNode]) -> Iterator[None]:
360 yield
koder aka kdanilov168f6092015-04-19 02:33:38 +0300361
362
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200363def run_tests_stage(ctx: TestRun) -> None:
364 for group in ctx.config.get('tests', []):
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200365 gitems = list(group.items())
366 if len(gitems) != 1:
koder aka kdanilov170936a2015-06-27 22:51:17 +0300367 msg = "Items in tests section should have len == 1"
368 logger.error(msg)
369 raise utils.StopTestError(msg)
370
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200371 key, config = gitems[0]
koder aka kdanilovcee43342015-04-14 22:52:53 +0300372
373 if 'start_test_nodes' == key:
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300374 if 'openstack' not in config:
375 msg = "No openstack block in config - can't spawn vm's"
376 logger.error(msg)
377 raise utils.StopTestError(msg)
378
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200379 num_test_nodes = len([node for node in ctx.nodes if 'testnode' in node.info.roles])
380 vm_ctx = create_vms_ctx(ctx, config['openstack'], num_test_nodes)
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300381 tests = config.get('tests', [])
382 else:
383 vm_ctx = utils.empty_ctx([])
384 tests = [group]
koder aka kdanilovcee43342015-04-14 22:52:53 +0300385
koder aka kdanilov73084622016-11-16 21:51:08 +0200386 # make mypy happy
387 new_nodes = [] # type: List[NodeInfo]
388
389 with vm_ctx as new_nodes:
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200390 if new_nodes:
391 with ctx.get_pool() as pool:
koder aka kdanilov73084622016-11-16 21:51:08 +0200392 new_rpc_nodes = connect_all(new_nodes, pool)
koder aka kdanilovcee43342015-04-14 22:52:53 +0300393
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200394 test_nodes = ctx.nodes + new_rpc_nodes
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300395
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200396 if ctx.config.get('sensors'):
koder aka kdanilov73084622016-11-16 21:51:08 +0200397 sensor_ctx = sensor_monitoring(ctx, ctx.config.get('sensors'), test_nodes)
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200398 else:
399 sensor_ctx = utils.empty_ctx([])
400
401 if not ctx.config.no_tests:
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +0300402 for test_group in tests:
403 with sensor_ctx:
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200404 run_tests(ctx, test_group, test_nodes)
405
406 for node in new_rpc_nodes:
407 node.disconnect()
koder aka kdanilovda45e882015-04-06 02:24:42 +0300408
gstepanov023c1e42015-04-08 15:50:19 +0300409
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200410def shut_down_vms_stage(ctx: TestRun, nodes_ids: List[int]) -> None:
411 if nodes_ids:
koder aka kdanilov652cd802015-04-13 12:21:07 +0300412 logger.info("Removing nodes")
koder aka kdanilov73084622016-11-16 21:51:08 +0200413 start_vms.clear_nodes(ctx.os_connection, nodes_ids)
koder aka kdanilov652cd802015-04-13 12:21:07 +0300414 logger.info("Nodes has been removed")
gstepanov023c1e42015-04-08 15:50:19 +0300415
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200416
417def clear_enviroment(ctx: TestRun) -> None:
418 shut_down_vms_stage(ctx, ctx.storage.get('spawned_vm_ids', []))
koder aka kdanilov73084622016-11-16 21:51:08 +0200419 ctx.storage['spawned_vm_ids'] = [] # type: ignore
gstepanov023c1e42015-04-08 15:50:19 +0300420
koder aka kdanilov66839a92015-04-11 13:22:31 +0300421
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200422def disconnect_stage(ctx: TestRun) -> None:
423 # TODO(koder): what next line was for?
424 # ssh_utils.close_all_sessions()
koder aka kdanilov652cd802015-04-13 12:21:07 +0300425
koder aka kdanilovda45e882015-04-06 02:24:42 +0300426 for node in ctx.nodes:
koder aka kdanilov22d134e2016-11-08 11:33:19 +0200427 node.disconnect()
koder aka kdanilovda45e882015-04-06 02:24:42 +0300428
429
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200430def console_report_stage(ctx: TestRun) -> None:
431 # TODO(koder): load data from storage
432 raise NotImplementedError("...")
433 # first_report = True
434 # text_rep_fname = ctx.config.text_report_file
435 #
436 # with open(text_rep_fname, "w") as fd:
437 # for tp, data in ctx.results.items():
438 # if 'io' == tp and data is not None:
439 # rep_lst = []
440 # for result in data:
441 # rep_lst.append(
442 # IOPerfTest.format_for_console(list(result)))
443 # rep = "\n\n".join(rep_lst)
444 # elif tp in ['mysql', 'pgbench'] and data is not None:
445 # rep = MysqlTest.format_for_console(data)
446 # elif tp == 'omg':
447 # rep = OmgTest.format_for_console(data)
448 # else:
449 # logger.warning("Can't generate text report for " + tp)
450 # continue
451 #
452 # fd.write(rep)
453 # fd.write("\n")
454 #
455 # if first_report:
456 # logger.info("Text report were stored in " + text_rep_fname)
457 # first_report = False
458 #
459 # print("\n" + rep + "\n")
koder aka kdanilov66839a92015-04-11 13:22:31 +0300460
461
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200462# def test_load_report_stage(cfg: Config, ctx: TestRun) -> None:
463# load_rep_fname = cfg.load_report_file
464# found = False
465# for idx, (tp, data) in enumerate(ctx.results.items()):
466# if 'io' == tp and data is not None:
467# if found:
468# logger.error("Making reports for more than one " +
469# "io block isn't supported! All " +
470# "report, except first are skipped")
471# continue
472# found = True
473# report.make_load_report(idx, cfg['results'], load_rep_fname)
474#
475#
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300476
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200477def html_report_stage(ctx: TestRun) -> None:
478 # TODO(koder): load data from storage
479 raise NotImplementedError("...")
480 # html_rep_fname = cfg.html_report_file
481 # found = False
482 # for tp, data in ctx.results.items():
483 # if 'io' == tp and data is not None:
484 # if found or len(data) > 1:
485 # logger.error("Making reports for more than one " +
486 # "io block isn't supported! All " +
487 # "report, except first are skipped")
488 # continue
489 # found = True
490 # report.make_io_report(list(data[0]),
491 # cfg.get('comment', ''),
492 # html_rep_fname,
493 # lab_info=ctx.nodes)
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300494
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200495#
496# def load_data_from_path(test_res_dir: str) -> Mapping[str, List[Any]]:
497# files = get_test_files(test_res_dir)
498# raw_res = yaml_load(open(files['raw_results']).read())
499# res = collections.defaultdict(list)
500#
501# for tp, test_lists in raw_res:
502# for tests in test_lists:
503# for suite_name, suite_data in tests.items():
504# result_folder = suite_data[0]
505# res[tp].append(TOOL_TYPE_MAPPER[tp].load(suite_name, result_folder))
506#
507# return res
508#
509#
510# def load_data_from_path_stage(var_dir: str, _, ctx: TestRun) -> None:
511# for tp, vals in load_data_from_path(var_dir).items():
512# ctx.results.setdefault(tp, []).extend(vals)
513#
514#
515# def load_data_from(var_dir: str) -> Callable[[TestRun], None]:
516# return functools.partial(load_data_from_path_stage, var_dir)