def check_data_disks(test, params, env, vm, session): """ Check guest data disks (except image1) :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. :param vm: VM object :param session: VM session """ image_list = params.objects("images") del image_list[0] image_num = len(image_list) error_context.context("Check data disks in monitor!", logging.info) monitor_info_block = vm.monitor.info_block(False) blocks = ','.join(monitor_info_block.keys()) for image in image_list: if image not in blocks: test.fail("drive_%s is missed: %s!" % (image, blocks)) error_context.context("Read and write on data disks!", logging.info) os_type = params["os_type"] if os_type == "linux": sub_test_type = params.get("sub_test_type", "dd_test") for image in image_list: params["dd_if"] = "ZERO" params["dd_of"] = image utils_test.run_virt_sub_test(test, params, env, sub_test_type) params["dd_if"] = image params["dd_of"] = "NULL" utils_test.run_virt_sub_test(test, params, env, sub_test_type) elif os_type == "windows": iozone_cmd = params["iozone_cmd"] iozone_cmd = utils_misc.set_winutils_letter(session, iozone_cmd) data_image_size = params["data_image_size"] disks = utils_disk.get_windows_disks_index(session, data_image_size) disk_num = len(disks) if disk_num < image_num: err_msg = "set disk num: %d" % image_num err_msg += ", get in guest: %d" % disk_num test.fail("Fail to list all the volumes, %s" % err_msg) if not utils_disk.update_windows_disk_attributes(session, disks): test.fail("Failed to update windows disk attributes.") for disk in disks: drive_letter = utils_disk.configure_empty_disk( session, disk, data_image_size, os_type) if not drive_letter: test.fail("Fail to format disks.") iozone_cmd_disk = iozone_cmd % drive_letter[0] status, output = session.cmd_status_output(iozone_cmd_disk, timeout=3600) if status: test.fail("Check block device '%s' failed! Output: %s" % (drive_letter[0], output)) utils_disk.clean_partition(session, disk, os_type) else: test.cancel("Unsupported OS type '%s'" % os_type)
def run(test, params, env): """ Test multi disk suport of guest, this case will: 1) Create disks image in configuration file. 2) Start the guest with those disks. 3) Checks qtree vs. test params. (Optional) 4) Create partition on those disks. 5) Get disk dev filenames in guest. 6) Format those disks in guest. 7) Copy file into / out of those disks. 8) Compare the original file and the copied file using md5 or fc comand. 9) Repeat steps 3-5 if needed. :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ def _add_param(name, value): """ Converts name+value to stg_params string """ if value: value = re.sub(' ', '\\ ', value) return " %s:%s " % (name, value) else: return '' def _do_post_cmd(session): cmd = params.get("post_cmd") if cmd: session.cmd_status_output(cmd) session.close() error_context.context("Parsing test configuration", logging.info) stg_image_num = 0 stg_params = params.get("stg_params", "") # Compatibility stg_params += _add_param("image_size", params.get("stg_image_size")) stg_params += _add_param("image_format", params.get("stg_image_format")) stg_params += _add_param("image_boot", params.get("stg_image_boot", "no")) stg_params += _add_param("drive_format", params.get("stg_drive_format")) stg_params += _add_param("drive_cache", params.get("stg_drive_cache")) if params.get("stg_assign_index") != "no": # Assume 0 and 1 are already occupied (hd0 and cdrom) stg_params += _add_param("drive_index", 'range(2,n)') param_matrix = {} stg_params = stg_params.split(' ') i = 0 while i < len(stg_params) - 1: if not stg_params[i].strip(): i += 1 continue if stg_params[i][-1] == '\\': stg_params[i] = '%s %s' % (stg_params[i][:-1], stg_params.pop(i + 1)) i += 1 rerange = [] has_name = False for i in range(len(stg_params)): if not stg_params[i].strip(): continue (cmd, parm) = stg_params[i].split(':', 1) if cmd == "image_name": has_name = True if _RE_RANGE1.match(parm): parm = _range(parm) if parm is False: test.error("Incorrect cfg: stg_params %s looks " "like range(..) but doesn't contain " "numbers." % cmd) param_matrix[cmd] = parm if type(parm) is str: # When we know the stg_image_num, substitute it. rerange.append(cmd) continue else: # ',' separated list of values parm = parm.split(',') j = 0 while j < len(parm) - 1: if parm[j][-1] == '\\': parm[j] = '%s,%s' % (parm[j][:-1], parm.pop(j + 1)) j += 1 param_matrix[cmd] = parm stg_image_num = max(stg_image_num, len(parm)) stg_image_num = int(params.get('stg_image_num', stg_image_num)) for cmd in rerange: param_matrix[cmd] = _range(param_matrix[cmd], stg_image_num) # param_table* are for pretty print of param_matrix param_table = [] param_table_header = ['name'] if not has_name: param_table_header.append('image_name') for _ in param_matrix: param_table_header.append(_) stg_image_name = params.get('stg_image_name', 'images/%s') for i in range(stg_image_num): name = "stg%d" % i params['images'] += " %s" % name param_table.append([]) param_table[-1].append(name) if not has_name: params["image_name_%s" % name] = stg_image_name % name param_table[-1].append(params.get("image_name_%s" % name)) for parm in param_matrix.items(): params['%s_%s' % (parm[0], name)] = str(parm[1][i % len(parm[1])]) param_table[-1].append(params.get('%s_%s' % (parm[0], name))) if params.get("multi_disk_params_only") == 'yes': # Only print the test param_matrix and finish logging.info('Newly added disks:\n%s', astring.tabular_output(param_table, param_table_header)) return # Always recreate VMs and disks error_context.context("Start the guest with new disks", logging.info) for vm_name in params.objects("vms"): vm_params = params.object_params(vm_name) env_process.process_images(env_process.preprocess_image, test, vm_params) error_context.context("Start the guest with those disks", logging.info) vm = env.get_vm(params["main_vm"]) vm.create(timeout=max(10, stg_image_num), params=params) login_timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=login_timeout) n_repeat = int(params.get("n_repeat", "1")) file_system = [_.strip() for _ in params["file_system"].split()] cmd_timeout = float(params.get("cmd_timeout", 360)) black_list = params["black_list"].split() drive_letters = int(params.get("drive_letters", "26")) stg_image_size = params["stg_image_size"] dd_test = params.get("dd_test", "no") labeltype = params.get("labeltype", "gpt") have_qtree = True out = vm.monitor.human_monitor_cmd("info qtree", debug=False) if "unknown command" in str(out): have_qtree = False if (params.get("check_guest_proc_scsi") == "yes") and have_qtree: error_context.context("Verifying qtree vs. test params") err = 0 qtree = qemu_qtree.QtreeContainer() qtree.parse_info_qtree(vm.monitor.info('qtree')) disks = qemu_qtree.QtreeDisksContainer(qtree.get_nodes()) (tmp1, tmp2) = disks.parse_info_block(vm.monitor.info_block()) err += tmp1 + tmp2 err += disks.generate_params() err += disks.check_disk_params(params) (tmp1, tmp2, _, _) = disks.check_guests_proc_scsi( session.cmd_output('cat /proc/scsi/scsi')) err += tmp1 + tmp2 if err: test.fail("%s errors occurred while verifying qtree vs." " params" % err) if params.get('multi_disk_only_qtree') == 'yes': return try: err_msg = "Set disks num: %d" % stg_image_num err_msg += ", Get disks num in guest: %d" ostype = params["os_type"] if ostype == "windows": error_context.context("Get windows disk index that to " "be formatted", logging.info) disks = utils_disk.get_windows_disks_index(session, stg_image_size) if len(disks) < stg_image_num: test.fail("Fail to list all the volumes" ", %s" % err_msg % len(disks)) if len(disks) > drive_letters: black_list.extend(utils_misc.get_winutils_vol(session)) disks = random.sample(disks, drive_letters - len(black_list)) error_context.context("Clear readonly for all disks and online " "them in windows guest.", logging.info) if not utils_disk.update_windows_disk_attributes(session, disks): test.fail("Failed to update windows disk attributes.") dd_test = "no" else: error_context.context("Get linux disk that to be " "formatted", logging.info) disks = sorted(utils_disk.get_linux_disks(session).keys()) if len(disks) < stg_image_num: test.fail("Fail to list all the volumes" ", %s" % err_msg % len(disks)) except Exception: _do_post_cmd(session) raise try: for i in range(n_repeat): logging.info("iterations: %s", (i + 1)) for disk in disks: error_context.context("Format disk in guest: '%s'" % disk, logging.info) # Random select one file system from file_system index = random.randint(0, (len(file_system) - 1)) fstype = file_system[index].strip() partitions = utils_disk.configure_empty_disk( session, disk, stg_image_size, ostype, fstype=fstype, labeltype=labeltype) if not partitions: test.fail("Fail to format disks.") cmd_list = params["cmd_list"] for partition in partitions: if "/" not in partition: partition += ":" else: partition = partition.split("/")[-1] error_context.context("Copy file into / out of partition:" " %s..." % partition, logging.info) for cmd_l in cmd_list.split(): cmd = params.get(cmd_l) if cmd: session.cmd(cmd % partition, timeout=cmd_timeout) cmd = params["compare_command"] key_word = params["check_result_key_word"] output = session.cmd_output(cmd) if key_word not in output: test.fail("Files on guest os root fs and disk differ") if dd_test != "no": error_context.context("dd test on partition: %s..." % partition, logging.info) status, output = session.cmd_status_output( dd_test % (partition, partition), timeout=cmd_timeout) if status != 0: test.fail("dd test fail: %s" % output) need_reboot = params.get("need_reboot", "no") need_shutdown = params.get("need_shutdown", "no") if need_reboot == "yes": error_context.context("Rebooting guest ...", logging.info) session = vm.reboot(session=session, timeout=login_timeout) if need_shutdown == "yes": error_context.context("Shutting down guest ...", logging.info) vm.graceful_shutdown(timeout=login_timeout) if vm.is_alive(): test.fail("Fail to shut down guest.") error_context.context("Start the guest again.", logging.info) vm = env.get_vm(params["main_vm"]) vm.create(params=params) session = vm.wait_for_login(timeout=login_timeout) error_context.context("Delete partitions in guest.", logging.info) for disk in disks: utils_disk.clean_partition(session, disk, ostype) finally: _do_post_cmd(session)
def run(test, params, env): """ Test multi disk suport of guest, this case will: 1) Create disks image in configuration file. 2) Start the guest with those disks. 3) Checks qtree vs. test params. (Optional) 4) Create partition on those disks. 5) Get disk dev filenames in guest. 6) Format those disks in guest. 7) Copy file into / out of those disks. 8) Compare the original file and the copied file using md5 or fc comand. 9) Repeat steps 3-5 if needed. :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ def _add_param(name, value): """ Converts name+value to stg_params string """ if value: value = re.sub(' ', '\\ ', value) return " %s:%s " % (name, value) else: return '' def _do_post_cmd(session): cmd = params.get("post_cmd") if cmd: session.cmd_status_output(cmd) session.close() error_context.context("Parsing test configuration", logging.info) stg_image_num = 0 stg_params = params.get("stg_params", "") # Compatibility stg_params += _add_param("image_size", params.get("stg_image_size")) stg_params += _add_param("image_format", params.get("stg_image_format")) stg_params += _add_param("image_boot", params.get("stg_image_boot", "no")) stg_params += _add_param("drive_format", params.get("stg_drive_format")) stg_params += _add_param("drive_cache", params.get("stg_drive_cache")) if params.get("stg_assign_index") != "no": # Assume 0 and 1 are already occupied (hd0 and cdrom) stg_params += _add_param("drive_index", 'range(2,n)') param_matrix = {} stg_params = stg_params.split(' ') i = 0 while i < len(stg_params) - 1: if not stg_params[i].strip(): i += 1 continue if stg_params[i][-1] == '\\': stg_params[i] = '%s %s' % (stg_params[i][:-1], stg_params.pop(i + 1)) i += 1 rerange = [] has_name = False for i in range(len(stg_params)): if not stg_params[i].strip(): continue (cmd, parm) = stg_params[i].split(':', 1) if cmd == "image_name": has_name = True if _RE_RANGE1.match(parm): parm = _range(parm) if parm is False: test.error("Incorrect cfg: stg_params %s looks " "like range(..) but doesn't contain " "numbers." % cmd) param_matrix[cmd] = parm if type(parm) is str: # When we know the stg_image_num, substitute it. rerange.append(cmd) continue else: # ',' separated list of values parm = parm.split(',') j = 0 while j < len(parm) - 1: if parm[j][-1] == '\\': parm[j] = '%s,%s' % (parm[j][:-1], parm.pop(j + 1)) j += 1 param_matrix[cmd] = parm stg_image_num = max(stg_image_num, len(parm)) stg_image_num = int(params.get('stg_image_num', stg_image_num)) for cmd in rerange: param_matrix[cmd] = _range(param_matrix[cmd], stg_image_num) # param_table* are for pretty print of param_matrix param_table = [] param_table_header = ['name'] if not has_name: param_table_header.append('image_name') for _ in param_matrix: param_table_header.append(_) stg_image_name = params.get('stg_image_name', 'images/%s') for i in range(stg_image_num): name = "stg%d" % i params['images'] += " %s" % name param_table.append([]) param_table[-1].append(name) if not has_name: params["image_name_%s" % name] = stg_image_name % name param_table[-1].append(params.get("image_name_%s" % name)) for parm in param_matrix.items(): params['%s_%s' % (parm[0], name)] = str(parm[1][i % len(parm[1])]) param_table[-1].append(params.get('%s_%s' % (parm[0], name))) if params.get("multi_disk_params_only") == 'yes': # Only print the test param_matrix and finish logging.info('Newly added disks:\n%s', astring.tabular_output(param_table, param_table_header)) return # Always recreate VMs and disks error_context.context("Start the guest with new disks", logging.info) for vm_name in params.objects("vms"): vm_params = params.object_params(vm_name) env_process.process_images(env_process.preprocess_image, test, vm_params) error_context.context("Start the guest with those disks", logging.info) vm = env.get_vm(params["main_vm"]) vm.create(timeout=max(10, stg_image_num), params=params) login_timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=login_timeout) n_repeat = int(params.get("n_repeat", "1")) file_system = [_.strip() for _ in params["file_system"].split()] cmd_timeout = float(params.get("cmd_timeout", 360)) black_list = params["black_list"].split() drive_letters = int(params.get("drive_letters", "26")) stg_image_size = params["stg_image_size"] dd_test = params.get("dd_test", "no") pre_command = params.get("pre_command", "") labeltype = params.get("labeltype", "gpt") iozone_target_num = int(params.get('iozone_target_num', '5')) iozone_options = params.get('iozone_options') iozone_timeout = float(params.get('iozone_timeout', '7200')) have_qtree = True out = vm.monitor.human_monitor_cmd("info qtree", debug=False) if "unknown command" in str(out): have_qtree = False if (params.get("check_guest_proc_scsi") == "yes") and have_qtree: error_context.context("Verifying qtree vs. test params") err = 0 qtree = qemu_qtree.QtreeContainer() qtree.parse_info_qtree(vm.monitor.info('qtree')) disks = qemu_qtree.QtreeDisksContainer(qtree.get_nodes()) (tmp1, tmp2) = disks.parse_info_block(vm.monitor.info_block()) err += tmp1 + tmp2 err += disks.generate_params() err += disks.check_disk_params(params) (tmp1, tmp2, _, _) = disks.check_guests_proc_scsi( session.cmd_output('cat /proc/scsi/scsi')) err += tmp1 + tmp2 if err: test.fail("%s errors occurred while verifying qtree vs." " params" % err) if params.get('multi_disk_only_qtree') == 'yes': return try: err_msg = "Set disks num: %d" % stg_image_num err_msg += ", Get disks num in guest: %d" ostype = params["os_type"] if ostype == "windows": error_context.context( "Get windows disk index that to " "be formatted", logging.info) disks = utils_disk.get_windows_disks_index(session, stg_image_size) if len(disks) < stg_image_num: test.fail("Fail to list all the volumes" ", %s" % err_msg % len(disks)) if len(disks) > drive_letters: black_list.extend(utils_misc.get_winutils_vol(session)) disks = random.sample(disks, drive_letters - len(black_list)) error_context.context( "Clear readonly for all disks and online " "them in windows guest.", logging.info) if not utils_disk.update_windows_disk_attributes(session, disks): test.fail("Failed to update windows disk attributes.") dd_test = "no" else: error_context.context("Get linux disk that to be " "formatted", logging.info) disks = sorted(utils_disk.get_linux_disks(session).keys()) if len(disks) < stg_image_num: test.fail("Fail to list all the volumes" ", %s" % err_msg % len(disks)) except Exception: _do_post_cmd(session) raise try: if iozone_options: iozone = generate_instance(params, session, 'iozone') random.shuffle(disks) for i in range(n_repeat): logging.info("iterations: %s", (i + 1)) for n, disk in enumerate(disks): error_context.context("Format disk in guest: '%s'" % disk, logging.info) # Random select one file system from file_system index = random.randint(0, (len(file_system) - 1)) fstype = file_system[index].strip() partitions = utils_disk.configure_empty_disk( session, disk, stg_image_size, ostype, fstype=fstype, labeltype=labeltype) if not partitions: test.fail("Fail to format disks.") cmd_list = params["cmd_list"] for partition in partitions: orig_partition = partition if "/" not in partition: partition += ":" else: partition = partition.split("/")[-1] error_context.context( "Copy file into / out of partition:" " %s..." % partition, logging.info) for cmd_l in cmd_list.split(): cmd = params.get(cmd_l) if cmd: session.cmd(cmd % partition, timeout=cmd_timeout) cmd = params["compare_command"] key_word = params["check_result_key_word"] output = session.cmd_output(cmd) if iozone_options and n < iozone_target_num: iozone.run(iozone_options.format(orig_partition), iozone_timeout) if key_word not in output: test.fail("Files on guest os root fs and disk differ") if dd_test != "no": error_context.context( "dd test on partition: %s..." % partition, logging.info) status, output = session.cmd_status_output( dd_test % (partition, partition), timeout=cmd_timeout) if status != 0: test.fail("dd test fail: %s" % output) # When multiple SCSI disks are simulated by scsi_debug, # they could be viewed as multiple paths to the same # storage device. So need umount partition before operate # next disk, in order to avoid corrupting the filesystem # (xfs integrity checks error). if ostype == "linux" and "scsi_debug add_host" in pre_command: status, output = session.cmd_status_output( "umount /dev/%s" % partition, timeout=cmd_timeout) if status != 0: test.fail("Failed to umount partition '%s': %s" % (partition, output)) need_reboot = params.get("need_reboot", "no") need_shutdown = params.get("need_shutdown", "no") if need_reboot == "yes": error_context.context("Rebooting guest ...", logging.info) session = vm.reboot(session=session, timeout=login_timeout) if need_shutdown == "yes": error_context.context("Shutting down guest ...", logging.info) vm.graceful_shutdown(timeout=login_timeout) if vm.is_alive(): test.fail("Fail to shut down guest.") error_context.context("Start the guest again.", logging.info) vm = env.get_vm(params["main_vm"]) vm.create(params=params) session = vm.wait_for_login(timeout=login_timeout) error_context.context("Delete partitions in guest.", logging.info) for disk in disks: utils_disk.clean_partition(session, disk, ostype) finally: if iozone_options: iozone.clean() _do_post_cmd(session)
def run(test, params, env): """ Special hardware test case. FC host: ibm-x3650m4-05.lab.eng.pek2.redhat.com Disk serial name: scsi-360050763008084e6e0000000000001a4 # multipath -ll mpathb (360050763008084e6e0000000000001a8) dm-4 IBM,2145 size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw |-+- policy='service-time 0' prio=50 status=active | `- 2:0:1:0 sde 8:64 active ready running `-+- policy='service-time 0' prio=10 status=enabled `- 2:0:0:0 sdd 8:48 active ready running mpatha (360050763008084e6e0000000000001a4) dm-3 IBM,2145 size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw |-+- policy='service-time 0' prio=50 status=active | `- 1:0:1:0 sdc 8:32 active ready running `-+- policy='service-time 0' prio=10 status=enabled `- 1:0:0:0 sdb 8:16 active ready running Customer Bug ID: 1720047 1753992 format passthrough disk and do iozone test on it. 1) pass-through /dev/sdb 2) format it and do iozone test 3) pass-through /dev/sg1 4) format it and do iozone test 5) pass-through /dev/mapper/mpatha 6) format it and do iozone test :param test: kvm test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ def get_multipath_disks(mpath_name="mpatha"): """ Get all disks of multiple paths. multipath like below: mpatha (360050763008084e6e0000000000001a4) dm-3 IBM,2145 size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw |-+- policy='service-time 0' prio=50 status=active | `- 1:0:1:0 sdc 8:32 active ready running `-+- policy='service-time 0' prio=10 status=enabled `- 1:0:0:0 sdb 8:16 active ready running :param mpath_name: multi-path name. :return: a list. if get disks successfully or raise a error """ disks = [] disk_str = [] outputs = process.run("multipath -ll", shell=True).stdout.decode() outputs = outputs.split(mpath_name)[-1] disk_str.append("active ready running") disk_str.append("active faulty offline") disk_str.append("failed faulty offline") for line in outputs.splitlines(): if disk_str[0] in line or disk_str[1] in line or disk_str[2] in line: disks.append(line.split()[-5]) if not disks: test.fail("Failed to get disks by 'multipath -ll'") else: return disks def get_multipath_disks_status(mpath_name="mpatha"): """ Get status of multiple paths. multipath like below: mpatha (360050763008084e6e0000000000001a4) dm-3 IBM,2145 size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw |-+- policy='service-time 0' prio=50 status=active | `- 1:0:1:0 sdc 8:32 active ready running `-+- policy='service-time 0' prio=10 status=enabled `- 1:0:0:0 sdb 8:16 active ready running :param mpath_name: multi-path name. :return: a list. if get status successfully or raise a error """ disks = get_multipath_disks(mpath_name) disks_status = [] outputs = process.run("multipath -ll", shell=True).stdout.decode() outputs = outputs.split(mpath_name)[-1] for line in outputs.splitlines(): for i in range(len(disks)): if disks[i] in line: disks_status.append(line.strip().split()[-1]) break if not disks_status or len(disks_status) != len(disks): test.fail("Failed to get disks status by 'multipath -ll'") else: return disks_status def compare_multipath_status(status, mpath_name="mpatha"): """ Compare status whether equal to the given status. This function just focus on all paths are running or all are offline. :param status: the state of disks. :param mpath_name: multi-path name. :return: True, if equal to the given status or False """ status_list = get_multipath_disks_status(mpath_name) if len(set(status_list)) == 1 and status_list[0] == status: return True else: return False def set_disk_status_to_online_offline(disk, status): """ set disk state to online/offline. multipath like below: mpatha (360050763008084e6e0000000000001a4) dm-3 IBM,2145 size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw |-+- policy='service-time 0' prio=50 status=active | `- 1:0:1:0 sdc 8:32 active ready running `-+- policy='service-time 0' prio=10 status=enabled `- 1:0:0:0 sdb 8:16 failed faulty offline :param disk: disk name. :param status: the state of disk. :return: by default """ error_context.context("Set disk '%s' to status '%s'." % (disk, status), logging.info) process.run("echo %s > /sys/block/%s/device/state" % (status, disk), shell=True) def set_multipath_disks_status(disks, status): """ set multiple paths to same status. all disks online or offline. multipath like below: mpatha (360050763008084e6e0000000000001a4) dm-3 IBM,2145 size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw |-+- policy='service-time 0' prio=50 status=active | `- 1:0:1:0 sdc 8:32 active ready running `-+- policy='service-time 0' prio=10 status=enabled `- 1:0:0:0 sdb 8:16 failed faulty offline :param disks: disk list. :param status: the state of disk. online/offline :return: by default """ for disk in disks: set_disk_status_to_online_offline(disk, status) wait.wait_for(lambda: compare_multipath_status(status), first=2, step=1.5, timeout=60) def _do_post_cmd(session): """ do post command after test. :param session: A shell session object. :return: by default """ cmd = params.get("post_cmd") if cmd: session.cmd_status_output(cmd) session.close() def get_disk_by_sg_map(image_name_stg): """ get disk name by sg_map. :param image_name_stg: linux sg. e.g. /dev/sg1 :return: disk name. e.g. sdb """ outputs = process.run("sg_map", shell=True).stdout.decode().splitlines() for output in outputs: if image_name_stg in output: return output.strip().split()[-1].split("/")[-1] def _get_windows_disks_index(session, image_size): """ Get all disks index which show in 'diskpart list disk'. except for system disk. in diskpart: if disk size < 8GB: it displays as MB else: it displays as GB :param session: session object to guest. :param image_size: image size. e.g. 40M :return: a list with all disks index except for system disk. """ disk = "disk_" + ''.join(random.sample(string.ascii_letters + string.digits, 4)) disk_indexs = [] list_disk_cmd = "echo list disk > " + disk list_disk_cmd += " && echo exit >> " + disk list_disk_cmd += " && diskpart /s " + disk list_disk_cmd += " && del /f " + disk disks = session.cmd_output(list_disk_cmd) size_type = image_size[-1] + "B" if size_type == "MB": disk_size = image_size[:-1] + " MB" elif size_type == "GB" and int(image_size[:-1]) < 8: disk_size = str(int(image_size[:-1]) * 1024) + " MB" else: disk_size = image_size[:-1] + " GB" regex_str = 'Disk (\d+).*?%s' % disk_size for disk in disks.splitlines(): if disk.startswith(" Disk"): o = re.findall(regex_str, disk, re.I | re.M) if o: disk_indexs.append(o[0]) return disk_indexs def delete_partition_on_host(did): """ Delete partitions on the given disk. :param did: disk ID. disk kname. e.g. 'sdb', 'nvme0n1' :return: by default. """ # process.run("partprobe /dev/%s" % did, shell=True) list_disk_cmd = "lsblk -o KNAME,MOUNTPOINT" output = process.run(list_disk_cmd, shell=True).stdout.decode() regex_str = did + "\w*(\d+)" rm_cmd = 'parted -s "/dev/%s" rm %s' for line in output.splitlines(): partition = re.findall(regex_str, line, re.I | re.M) if partition: if "/" in line.split()[-1]: process.run("umount %s" % line.split()[-1], shell=True) list_partition_number = "parted -s /dev/%s print|awk '/^ / {print $1}'" partition_numbers = process.run(list_partition_number % did, shell=True).stdout.decode() ignore_err_msg = "unrecognised disk label" if ignore_err_msg in partition_numbers: logging.info("no partition to delete on %s" % did) else: partition_numbers = partition_numbers.splitlines() for number in partition_numbers: logging.info("remove partition %s on %s" % (number, did)) process.run(rm_cmd % (did, number), shell=True) process.run("partprobe /dev/%s" % did, shell=True) def delete_multipath_partition_on_host(mpath_name="mpatha"): """ Delete partitions on the given multipath. :param mpath_name: multi-path name. :return: by default. """ # process.run("partprobe /dev/mapper/%s" % mpath_name, shell=True) output = process.run("lsblk", shell=True).stdout.decode() mpath_dict = {} pattern = r'%s(\d+)' % mpath_name rm_cmd = 'parted -s "/dev/mapper/%s" rm %s' for line in output.splitlines(): for part_num in re.findall(pattern, line, re.I | re.M): if part_num not in mpath_dict.keys(): mpath_dict[part_num] = line.split()[-1] for key, value in mpath_dict.items(): if "/" in value: process.run("umount %s" % value, shell=True) logging.info("remove partition %s on %s" % (key, mpath_name)) process.run(rm_cmd % (mpath_name, key), shell=True) output = process.run("dmsetup ls", shell=True).stdout.decode() for line in output.splitlines(): for key in mpath_dict.keys(): if (mpath_name + key) in line: process.run("dmsetup remove %s%s" % (mpath_name, key), shell=True) process.run("partprobe /dev/mapper/%s" % mpath_name, shell=True) def clean_partition_on_host(mpath_name="mpatha"): """ Delete partitions on multi-path disks. :param mpath_name: multi-path name. :return: by default """ delete_multipath_partition_on_host(mpath_name) disks = get_multipath_disks(mpath_name) for disk in disks: delete_partition_on_host(disk) error_context.context("Get FC host name:", logging.info) hostname = process.run("hostname", shell=True).stdout.decode().strip() if hostname != params["special_host"]: test.cancel("The special host is not '%s', cancel the test." % params["special_host"]) error_context.context("Get FC disk serial name:", logging.info) stg_serial_name = params["stg_serial_name"] image_name_stg = params["image_name_stg"].split("/")[-1] if "mpath" not in image_name_stg: if "sg" in image_name_stg: image_name_stg = get_disk_by_sg_map(image_name_stg) if not image_name_stg: test.cancel("Failed to get disk by sg_map," " output is '%s'" % image_name_stg) query_cmd = "udevadm info -q property -p /sys/block/%s" % image_name_stg outputs = process.run(query_cmd, shell=True).stdout.decode().splitlines() for output in outputs: # ID_SERIAL=360050763008084e6e0000000000001a4 if stg_serial_name in output and output.startswith("ID_SERIAL="): break else: test.cancel("The special disk is not '%s', cancel the test." % stg_serial_name) else: outputs = process.run("multipath -ll", shell=True).stdout.decode().splitlines() for output in outputs: if stg_serial_name in output and image_name_stg in output: break else: test.cancel("The special disk is not '%s', cancel the test." % stg_serial_name) mpath_name = image_name_stg multi_disks = get_multipath_disks(mpath_name) error_context.context("Get all disks for '%s': %s" % (mpath_name, multi_disks), logging.info) error_context.context("Verify all paths are running for %s before " "start vm." % mpath_name, logging.info) if compare_multipath_status("running", mpath_name): logging.info("All paths are running for %s." % mpath_name) else: logging.info("Not all paths are running for %s, set " "them to running." % mpath_name) set_multipath_disks_status(multi_disks, "running") error_context.context("Delete partitions on host before testing.", logging.info) clean_partition_on_host(params["mpath_name"]) vm = env.get_vm(params["main_vm"]) try: vm.create(params=params) except Exception as e: test.error("failed to create VM: %s" % six.text_type(e)) session = vm.wait_for_login(timeout=int(params.get("timeout", 240))) file_system = [_.strip() for _ in params["file_system"].split()] labeltype = params.get("labeltype", "gpt") iozone_target_num = int(params.get('iozone_target_num', '5')) iozone_options = params.get('iozone_options') iozone_timeout = float(params.get('iozone_timeout', '7200')) image_num_stg = int(params["image_num_stg"]) image_size_stg = params["image_size_stg"] ostype = params["os_type"] try: if ostype == "windows": error_context.context("Get windows disk index that to " "be formatted", logging.info) # disks = utils_disk.get_windows_disks_index(session, image_size_stg) disks = _get_windows_disks_index(session, image_size_stg) if len(disks) != image_num_stg: test.fail("Failed to list all disks by image size. The expected " "is %s, actual is %s" % (image_num_stg, len(disks))) error_context.context("Clear readonly for all disks and online " "them in windows guest.", logging.info) if not utils_disk.update_windows_disk_attributes(session, disks): test.fail("Failed to update windows disk attributes.") else: error_context.context("Get linux disk that to be " "formatted", logging.info) disks = sorted(utils_disk.get_linux_disks(session).keys()) if len(disks) != image_num_stg: test.fail("Failed to list all disks by image size. The expected " "is %s, actual is %s" % (image_num_stg, len(disks))) # logging.info("Get data disk by serial name: '%s'" % stg_serial_name) # drive_path = utils_misc.get_linux_drive_path(session, stg_serial_name) # if not drive_path: # test.fail("Failed to get data disk by serial name: %s" # % stg_serial_name) except Exception: _do_post_cmd(session) raise if iozone_options: iozone = generate_instance(params, vm, 'iozone') try: error_context.context("Make sure guest is running before test", logging.info) vm.resume() vm.verify_status("running") for n, disk in enumerate(disks): error_context.context("Format disk in guest: '%s'" % disk, logging.info) # Random select one file system from file_system index = random.randint(0, (len(file_system) - 1)) fstype = file_system[index].strip() partitions = utils_disk.configure_empty_disk( session, disk, image_size_stg, ostype, fstype=fstype, labeltype=labeltype) if not partitions: test.fail("Fail to format disks.") for partition in partitions: if iozone_options and n < iozone_target_num: iozone.run(iozone_options.format(partition), iozone_timeout) error_context.context("Reboot guest after format disk " "and iozone test.", logging.info) session = vm.reboot(session=session, timeout=int(params.get("timeout", 240))) error_context.context("Shutting down guest after reboot it.", logging.info) vm.graceful_shutdown(timeout=int(params.get("timeout", 240))) if vm.is_alive(): test.fail("Fail to shut down guest.") error_context.context("Start the guest again.", logging.info) vm = env.get_vm(params["main_vm"]) vm.create(params=params) session = vm.wait_for_login(timeout=int(params.get("timeout", 240))) error_context.context("Delete partitions in guest.", logging.info) for disk in disks: utils_disk.clean_partition(session, disk, ostype) error_context.context("Inform the OS of partition table changes " "after testing.", logging.info) if "sg1" in params["image_name_stg"]: image_name_stg = get_disk_by_sg_map(params["image_name_stg"]) process.run("partprobe /dev/%s" % image_name_stg, shell=True) else: process.run("partprobe %s" % params["image_name_stg"], shell=True) finally: if iozone_options: iozone.clean() _do_post_cmd(session)