blob: 8b54f8bbb97078aa0b1e48c554b3ce7bbc29d117 [file] [log] [blame]
koder aka kdanilove21d7472015-02-14 19:02:04 -08001import logging
koder aka kdanilov39e449e2016-12-17 15:15:26 +02002from concurrent.futures import Future
3from typing import List, Dict, Tuple, Optional, Union, cast
koder aka kdanilov88407ff2015-05-26 15:35:57 +03004
koder aka kdanilov39e449e2016-12-17 15:15:26 +02005from . import utils, ssh_utils, hw_info
6from .config import ConfigBlock
koder aka kdanilov73084622016-11-16 21:51:08 +02007from .node import setup_rpc, connect
koder aka kdanilov39e449e2016-12-17 15:15:26 +02008from .node_interfaces import NodeInfo, IRPCNode
9from .stage import Stage, StepOrder
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030010from .suits.io.fio import IOPerfTest
koder aka kdanilov39e449e2016-12-17 15:15:26 +020011from .suits.itest import TestInputConfig
12from .suits.mysql import MysqlTest
koder aka kdanilov3b4da8b2016-10-17 00:17:53 +030013from .suits.omgbench import OmgTest
koder aka kdanilov39e449e2016-12-17 15:15:26 +020014from .suits.postgres import PgBenchTest
15from .test_run_class import TestRun
koder aka kdanilovbc2c8982015-06-13 02:50:43 +030016
17
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030018TOOL_TYPE_MAPPER = {
19 "io": IOPerfTest,
20 "pgbench": PgBenchTest,
21 "mysql": MysqlTest,
Yulia Portnovab0c977c2015-12-11 19:23:28 +020022 "omg": OmgTest,
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030023}
koder aka kdanilov63ad2062015-04-27 13:11:40 +030024
koder aka kdanilov57ce4db2015-04-25 21:25:51 +030025
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030026logger = logging.getLogger("wally")
koder aka kdanilovcee43342015-04-14 22:52:53 +030027
koder aka kdanilov7acd6bd2015-02-12 14:28:30 -080028
koder aka kdanilov39e449e2016-12-17 15:15:26 +020029class ConnectStage(Stage):
30 """Connect to nodes stage"""
koder aka kdanilove21d7472015-02-14 19:02:04 -080031
koder aka kdanilov39e449e2016-12-17 15:15:26 +020032 priority = StepOrder.CONNECT
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030033
koder aka kdanilov39e449e2016-12-17 15:15:26 +020034 def run(self, ctx: TestRun) -> None:
koder aka kdanilov73084622016-11-16 21:51:08 +020035 with ctx.get_pool() as pool:
koder aka kdanilov39e449e2016-12-17 15:15:26 +020036 logger.info("Connecting to %s nodes", len(ctx.nodes_info))
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030037
koder aka kdanilov39e449e2016-12-17 15:15:26 +020038 def connect_ext(node_info: NodeInfo) -> Tuple[bool, Union[IRPCNode, NodeInfo]]:
39 try:
40 ssh_node = connect(node_info, conn_timeout=ctx.config.connect_timeout)
koder aka kdanilove7e1a4d2016-12-17 20:29:52 +020041 return True, setup_rpc(ssh_node, ctx.rpc_code, ctx.default_rpc_plugins)
koder aka kdanilov39e449e2016-12-17 15:15:26 +020042 except Exception as exc:
43 logger.error("During connect to {}: {!s}".format(node, exc))
44 return False, node_info
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030045
koder aka kdanilov39e449e2016-12-17 15:15:26 +020046 failed_testnodes = [] # type: List[NodeInfo]
47 failed_nodes = [] # type: List[NodeInfo]
48 ctx.nodes = []
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030049
koder aka kdanilov39e449e2016-12-17 15:15:26 +020050 for ok, node in pool.map(connect_ext, ctx.nodes_info):
51 if not ok:
52 node = cast(NodeInfo, node)
53 if 'testnode' in node.roles:
54 failed_testnodes.append(node)
55 else:
56 failed_nodes.append(node)
57 else:
58 ctx.nodes.append(cast(IRPCNode, node))
koder aka kdanilov22d134e2016-11-08 11:33:19 +020059
koder aka kdanilov39e449e2016-12-17 15:15:26 +020060 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 kdanilov4af1c1d2015-05-18 15:48:58 +030063
koder aka kdanilov39e449e2016-12-17 15:15:26 +020064 if failed_testnodes:
65 msg = "Can't connect to testnode(s) " + \
66 ",".join(map(str, failed_testnodes))
koder aka kdanilovc368eb62015-04-28 18:22:01 +030067 logger.error(msg)
68 raise utils.StopTestError(msg)
69
koder aka kdanilov39e449e2016-12-17 15:15:26 +020070 if not failed_nodes:
71 logger.info("All nodes connected successfully")
koder aka kdanilovcee43342015-04-14 22:52:53 +030072
koder aka kdanilov39e449e2016-12-17 15:15:26 +020073 def cleanup(self, ctx: TestRun) -> None:
74 # TODO(koder): what next line was for?
75 # ssh_utils.close_all_sessions()
koder aka kdanilov73084622016-11-16 21:51:08 +020076
koder aka kdanilov39e449e2016-12-17 15:15:26 +020077 for node in ctx.nodes:
78 node.disconnect()
koder aka kdanilovcee43342015-04-14 22:52:53 +030079
koder aka kdanilov0fdaaee2015-06-30 11:10:48 +030080
koder aka kdanilov39e449e2016-12-17 15:15:26 +020081class CollectInfoStage(Stage):
82 """Collect node info"""
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +020083
koder aka kdanilov39e449e2016-12-17 15:15:26 +020084 priority = StepOrder.START_SENSORS - 1
85 config_block = 'collect_info'
86
87 def run(self, ctx: TestRun) -> None:
88 if not ctx.config.collect_info:
89 return
90
91 futures = {} # type: Dict[str, Future]
92
93 with ctx.get_pool() as pool:
94 for node in ctx.nodes:
95 hw_info_path = "hw_info/{}".format(node.info.node_id())
96 if hw_info_path not in ctx.storage:
97 futures[hw_info_path] = pool.submit(hw_info.get_hw_info, node), node
98
99 sw_info_path = "sw_info/{}".format(node.info.node_id())
100 if sw_info_path not in ctx.storage:
101 futures[sw_info_path] = pool.submit(hw_info.get_sw_info, node)
102
103 for path, future in futures.items():
104 ctx.storage[path] = future.result()
105
106
107class ExplicitNodesStage(Stage):
108 """add explicit nodes"""
109
110 priority = StepOrder.DISCOVER
111 config_block = 'nodes'
112
113 def run(self, ctx: TestRun) -> None:
114 explicit_nodes = []
115 for url, roles in ctx.config.get('explicit_nodes', {}).items():
116 creds = ssh_utils.parse_ssh_uri(url)
117 roles = set(roles.split(","))
118 explicit_nodes.append(NodeInfo(creds, roles))
119
120 ctx.nodes_info.extend(explicit_nodes)
121 ctx.storage['explicit_nodes'] = explicit_nodes # type: ignore
122
123
124class SaveNodesStage(Stage):
125 """Save nodes list to file"""
126
127 priority = StepOrder.CONNECT
128
129 def run(self, ctx: TestRun) -> None:
130 ctx.storage['all_nodes'] = ctx.nodes_info # type: ignore
131
132
133class RunTestsStage(Stage):
134
135 priority = StepOrder.TEST
136 config_block = 'tests'
137
138 def run(self, ctx: TestRun) -> None:
139 for test_group in ctx.config.get('tests', []):
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200140 if not ctx.config.no_tests:
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200141 test_nodes = [node for node in ctx.nodes if 'testnode' in node.info.roles]
koder aka kdanilov3d2bc4f2016-11-12 18:31:18 +0200142
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200143 if not test_nodes:
144 logger.error("No test nodes found")
145 return
koder aka kdanilovda45e882015-04-06 02:24:42 +0300146
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200147 for name, params in test_group.items():
148 vm_count = params.get('node_limit', None) # type: Optional[int]
gstepanov023c1e42015-04-08 15:50:19 +0300149
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200150 # select test nodes
151 if vm_count is None:
152 curr_test_nodes = test_nodes
153 else:
154 curr_test_nodes = test_nodes[:vm_count]
koder aka kdanilov70227062016-11-26 23:23:21 +0200155
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200156 if not curr_test_nodes:
157 logger.error("No nodes found for test, skipping it.")
158 continue
koder aka kdanilov70227062016-11-26 23:23:21 +0200159
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200160 test_cls = TOOL_TYPE_MAPPER[name]
161 remote_dir = ctx.config.default_test_local_folder.format(name=name, uuid=ctx.config.run_uuid)
162 test_cfg = TestInputConfig(test_cls.__name__,
163 params=params,
164 run_uuid=ctx.config.run_uuid,
165 nodes=test_nodes,
166 storage=ctx.storage,
167 remote_dir=remote_dir)
koder aka kdanilov70227062016-11-26 23:23:21 +0200168
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200169 test_cls(test_cfg).run()
gstepanov023c1e42015-04-08 15:50:19 +0300170
koder aka kdanilov39e449e2016-12-17 15:15:26 +0200171 @classmethod
172 def validate_config(cls, cfg: ConfigBlock) -> None:
173 pass