1import re 2import time 3import os 4import datetime 5from behave import given, when, then 6from crmsh import corosync, parallax 7from utils import check_cluster_state, check_service_state, online, run_command, me, \ 8 run_command_local_or_remote, file_in_archive 9import const 10 11@when('Write multi lines to file "{f}"') 12def step_impl(context, f): 13 with open(f, 'w') as fd: 14 fd.write(context.text) 15 16@given('Cluster service is "{state}" on "{addr}"') 17def step_impl(context, state, addr): 18 assert check_cluster_state(context, state, addr) is True 19 20 21@given('Service "{name}" is "{state}" on "{addr}"') 22def step_impl(context, name, state, addr): 23 assert check_service_state(context, name, state, addr) is True 24 25 26@given('Has disk "{disk}" on "{addr}"') 27def step_impl(context, disk, addr): 28 out = run_command_local_or_remote(context, "fdisk -l", addr) 29 assert re.search(r'{} '.format(disk), out) is not None 30 31 32@given('Online nodes are "{nodelist}"') 33def step_impl(context, nodelist): 34 assert online(context, nodelist) is True 35 36 37@given('IP "{addr}" is belong to "{iface}"') 38def step_impl(context, addr, iface): 39 cmd = 'ip address show dev {}'.format(iface) 40 res = re.search(r' {}/'.format(addr), run_command(context, cmd)[1]) 41 assert bool(res) is True 42 43 44@when('Run "{cmd}" on "{addr}"') 45def step_impl(context, cmd, addr): 46 out = run_command_local_or_remote(context, cmd, addr) 47 context.stdout = out 48 49 50@then('Print stdout') 51def step_impl(context): 52 context.logger.info("\n{}".format(context.stdout)) 53 54 55@then('Print stderr') 56def step_impl(context): 57 context.logger.info("\n{}".format(context.command_error_output)) 58 59 60@when('Try "{cmd}" on "{addr}"') 61def step_impl(context, cmd, addr): 62 run_command_local_or_remote(context, cmd, addr, err_record=True) 63 64 65@when('Try "{cmd}"') 66def step_impl(context, cmd): 67 rc, out = run_command(context, cmd, err_record=True) 68 context.return_code = rc 69 70 71@when('Wait "{second}" seconds') 72def step_impl(context, second): 73 time.sleep(int(second)) 74 75 76@then('Got output "{msg}"') 77def step_impl(context, msg): 78 assert context.stdout == msg 79 context.stdout = None 80 81 82@then('Expected multiple lines') 83def step_impl(context): 84 assert context.stdout == context.text 85 context.stdout = None 86 87 88@then('Expected "{msg}" in stdout') 89def step_impl(context, msg): 90 assert msg in context.stdout 91 context.stdout = None 92 93 94@then('Expected regrex "{reg_str}" in stdout') 95def step_impl(context, reg_str): 96 res = re.search(reg_str, context.stdout) 97 assert res is not None 98 context.stdout = None 99 100 101@then('Expected return code is "{num}"') 102def step_impl(context, num): 103 assert context.return_code == int(num) 104 105 106@then('Expected "{msg}" not in stdout') 107def step_impl(context, msg): 108 assert msg not in context.stdout 109 context.stdout = None 110 111 112@then('Except "{msg}"') 113def step_impl(context, msg): 114 assert msg in context.command_error_output 115 context.command_error_output = None 116 117 118@then('Except multiple lines') 119def step_impl(context): 120 assert context.command_error_output.split('\n') == context.text.split('\n') 121 context.command_error_output = None 122 123 124@then('Expected multiple lines in output') 125def step_impl(context): 126 assert context.text in context.stdout 127 context.stdout = None 128 129 130@then('Except "{msg}" in stderr') 131def step_impl(context, msg): 132 assert msg in context.command_error_output 133 context.command_error_output = None 134 135 136@then('Cluster service is "{state}" on "{addr}"') 137def step_impl(context, state, addr): 138 assert check_cluster_state(context, state, addr) is True 139 140 141@then('Service "{name}" is "{state}" on "{addr}"') 142def step_impl(context, name, state, addr): 143 assert check_service_state(context, name, state, addr) is True 144 145 146@then('Online nodes are "{nodelist}"') 147def step_impl(context, nodelist): 148 assert online(context, nodelist) is True 149 150 151@then('IP "{addr}" is used by corosync on "{node}"') 152def step_impl(context, addr, node): 153 out = run_command_local_or_remote(context, 'corosync-cfgtool -s', node) 154 res = re.search(r' {}\n'.format(addr), out) 155 assert bool(res) is True 156 157 158@then('Cluster name is "{name}"') 159def step_impl(context, name): 160 _, out = run_command(context, 'corosync-cmapctl -b totem.cluster_name') 161 assert out.split()[-1] == name 162 163 164@then('Cluster virtual IP is "{addr}"') 165def step_impl(context, addr): 166 _, out = run_command(context, 'crm configure show|grep -A1 IPaddr2') 167 res = re.search(r' ip={}'.format(addr), out) 168 assert bool(res) is True 169 170 171@then('Cluster is using udpu transport mode') 172def step_impl(context): 173 assert corosync.get_value('totem.transport') == 'udpu' 174 175 176@then('Show cluster status on "{addr}"') 177def step_impl(context, addr): 178 out = run_command_local_or_remote(context, 'crm_mon -1', addr) 179 if out: 180 context.logger.info("\n{}".format(out)) 181 182 183@then('Show corosync ring status') 184def step_impl(context): 185 _, out = run_command(context, 'crm corosync status ring') 186 if out: 187 context.logger.info("\n{}".format(out)) 188 189 190@then('Show crm configure') 191def step_impl(context): 192 _, out = run_command(context, 'crm configure show') 193 if out: 194 context.logger.info("\n{}".format(out)) 195 196 197@then('Show status from qnetd') 198def step_impl(context): 199 _, out = run_command(context, 'crm corosync status qnetd') 200 if out: 201 context.logger.info("\n{}".format(out)) 202 203 204@then('Show corosync qdevice configuration') 205def step_impl(context): 206 _, out = run_command(context, "sed -n -e '/quorum/,/^}/ p' /etc/corosync/corosync.conf") 207 if out: 208 context.logger.info("\n{}".format(out)) 209 210 211@then('Resource "{res}" type "{res_type}" is "{state}"') 212def step_impl(context, res, res_type, state): 213 try_count = 0 214 result = None 215 while try_count < 5: 216 time.sleep(1) 217 _, out = run_command(context, "crm_mon -1rR") 218 if out: 219 result = re.search(r'\s{}\s+.*:+{}\):\s+{} '.format(res, res_type, state), out) 220 if not result: 221 try_count += 1 222 else: 223 break 224 assert result is not None 225 226 227@then('Resource "{res}" failcount on "{node}" is "{number}"') 228def step_impl(context, res, node, number): 229 cmd = "crm resource failcount {} show {}".format(res, node) 230 _, out = run_command(context, cmd) 231 if out: 232 result = re.search(r'name=fail-count-{} value={}'.format(res, number), out) 233 assert result is not None 234 235 236@then('Resource "{res_type}" not configured') 237def step_impl(context, res_type): 238 _, out = run_command(context, "crm configure show") 239 result = re.search(r' {} '.format(res_type), out) 240 assert result is None 241 242 243@then('Output is the same with expected "{cmd}" help output') 244def step_impl(context, cmd): 245 cmd_help = {} 246 cmd_help["crm"] = const.CRM_H_OUTPUT 247 cmd_help["crm_cluster_init"] = const.CRM_CLUSTER_INIT_H_OUTPUT 248 cmd_help["crm_cluster_join"] = const.CRM_CLUSTER_JOIN_H_OUTPUT 249 cmd_help["crm_cluster_add"] = const.CRM_CLUSTER_ADD_H_OUTPUT 250 cmd_help["crm_cluster_remove"] = const.CRM_CLUSTER_REMOVE_H_OUTPUT 251 cmd_help["crm_cluster_geo-init"] = const.CRM_CLUSTER_GEO_INIT_H_OUTPUT 252 cmd_help["crm_cluster_geo-join"] = const.CRM_CLUSTER_GEO_JOIN_H_OUTPUT 253 cmd_help["crm_cluster_geo-init-arbitrator"] = const.CRM_CLUSTER_GEO_INIT_ARBIT_H_OUTPUT 254 key = '_'.join(cmd.split()) 255 assert context.stdout == cmd_help[key] 256 257 258@then('Corosync working on "{transport_type}" mode') 259def step_impl(context, transport_type): 260 if transport_type == "multicast": 261 assert corosync.get_value("totem.transport") != "udpu" 262 if transport_type == "unicast": 263 assert corosync.get_value("totem.transport") == "udpu" 264 265 266@then('Expected votes will be "{votes}"') 267def step_impl(context, votes): 268 assert int(corosync.get_value("quorum.expected_votes")) == int(votes) 269 270 271@then('Default hb_report tar file created') 272def step_impl(context): 273 default_file_name = 'hb_report-{}.tar.bz2'.format(datetime.datetime.now().strftime("%w-%d-%m-%Y")) 274 assert os.path.exists(default_file_name) is True 275 276 277@when('Remove default hb_report tar file') 278def step_impl(context): 279 default_file_name = 'hb_report-{}.tar.bz2'.format(datetime.datetime.now().strftime("%w-%d-%m-%Y")) 280 os.remove(default_file_name) 281 282 283@then('File "{f}" in "{archive}"') 284def step_impl(context, f, archive): 285 assert file_in_archive(f, archive) is True 286 287 288@then('File "{f}" not in "{archive}"') 289def step_impl(context, f, archive): 290 assert file_in_archive(f, archive) is False 291 292 293@then('File "{f}" was synced in cluster') 294def step_impl(context, f): 295 cmd = "crm cluster diff {}".format(f) 296 rc, out = run_command(context, cmd) 297 assert out == "" 298