def run(test, params, env): """ Test hot plug and unplug NVMe device. Steps: 1. Install guest with local filesystem. 2. Hot plug NVMe device to guest. 3. Check if the NVMe device exists in qemu side. 4. Check if the NVMe has been successfully added to guest. 5. Run fio in the hot plugged NVMe device in guest. 6. Unplug the NVMe device. 7. Check if the NVMe device still exists. 8. Check if the NVMe has been successfully removed from guest. 9. Reboot guest. :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ unattended_install.run(test, params, env) if params.get('remove_options'): for option in params.get('remove_options').split(): del params[option] params['cdroms'] = params.get('default_cdroms') params['start_vm'] = 'yes' env_process.preprocess_vm(test, params, env, params["main_vm"]) vm = env.get_vm(params["main_vm"]) vm.verify_alive() session = vm.wait_for_login() plug = BlockDevicesPlug(vm) plug.hotplug_devs_serial() target = '/dev/%s' % plug[0] os_type = params['os_type'] data_img_size = params.get('image_size_%s' % params.get('data_img_tag')) if os_type == 'windows': utils_disk.update_windows_disk_attributes(session, plug[0]) drive_letter = utils_disk.configure_empty_disk(session, plug[0], data_img_size, os_type)[0] target = r'%s\:\\%s' % (drive_letter, params.get('fio_filename')) fio = generate_instance(params, vm, 'fio') for option in params['fio_options'].split(';'): fio.run('--filename=%s %s' % (target, option)) plug.unplug_devs_serial() vm.reboot(session)
def hotplug_unplug_block_repeatedly(times): """Hot plug then unplug block devices repeatedly.""" vm_pid = vm.get_pid() plug = BlockDevicesPlug(vm) info = ('The number of AIO file descriptors is %s ' 'after %s block device.') for i in range(times): logging.info('Iteration %d: Hot plug then unplug ' 'block device.', i) plug.hotplug_devs_serial() orig_fds_num = _get_aio_fds_num(vm_pid) logging.info(info, orig_fds_num, 'hot plugging') plug.unplug_devs_serial() new_fds_num = _get_aio_fds_num(vm_pid) logging.info(info, new_fds_num, 'unplugging') if new_fds_num != orig_fds_num: test.fail('The the number of AIO descriptors is ' 'changed, from %s to %s.' % (orig_fds_num, new_fds_num))
def run(test, params, env): """ Test to resize block device then unplug it. Steps: 1) Boot the guest with a data disk. 2) For Windows: Check whether viostor.sys verifier enabled in guest. 3) Resize the data disk, e.g, enlarge to 10GB; shrink to 1GB. 4) Check the data disk in guest whether is enlarge or shrink to the excepted size. 5) Reboot guest. 6) Unplug the data disk. :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ def _change_vm_power(): """ Change the vm power. """ method, command = params['command_opts'].split(',') logging.info('Sending command(%s): %s' % (method, command)) if method == 'shell': power_session = vm.wait_for_login() power_session.sendline(command) else: getattr(vm.monitor, command)() if shutdown_vm: if not utils_misc.wait_for( lambda: vm.monitor.get_event("SHUTDOWN"), 600): raise test.fail("Not received SHUTDOWN QMP event.") def _check_vm_status(timeout=600): """ Check the status of vm. """ action = 'shutdown' if shutdown_vm else 'login' if not getattr(vm, 'wait_for_%s' % action)(timeout=timeout): test.fail('Failed to %s vm.' % action) def _block_resize(dev): """ Resize the block size. """ resize_size = int( float( normalize_data_size( re.search(r'(\d+\.?(\d+)?\w)', params['resize_size']).group(1), "B"))) size = str(data_image_size + resize_size) if resize_op == ENLARGE else str( data_image_size - resize_size) logging.info("Start to %s image '%s' to %sB." % (resize_op, data_image, size)) if vm.check_capability(Flags.BLOCKDEV): args = (None, size, dev) else: args = (dev, size) vm.monitor.block_resize(*args) return size def _check_img_size(size): """ Check the size of image after resize. """ img = qemu_storage.QemuImg(data_image_params, data_dir.get_data_dir(), data_image) if json.loads(img.info(True, 'json'))['virtual-size'] != int(size): test.fail('The virtual size is not equal to %sB after %s.' % (size, resize_op)) shutdown_vm = params.get('shutdown_vm', 'no') == 'yes' reboot = params.get('reboot_vm', 'no') == 'yes' data_image = params.get("images").split()[-1] data_image_params = params.object_params(data_image) data_image_size = int( float(normalize_data_size(data_image_params.get("image_size"), "B"))) data_image_filename = storage.get_image_filename(data_image_params, data_dir.get_data_dir()) resize_op = SHRINK if '-' in params['resize_size'] else ENLARGE is_windows = params['os_type'] == 'windows' vm = env.get_vm(params["main_vm"]) vm.verify_alive() session = vm.wait_for_login() plug = BlockDevicesPlug(vm) if is_windows: utils_test.qemu.windrv_check_running_verifier(session, vm, test, params['driver_name'], 300) _check_img_size(_block_resize(vm.get_block({'file': data_image_filename}))) if reboot: _change_vm_power() _check_vm_status() plug.unplug_devs_serial()
def run(test, params, env): """ Test hotplug of block devices. 1) Boot up guest with virtio-blk or virtio-scsi system disk. 2) Hoplug a virtio-blk or virtio-scsi data disk by qmp. 3) Do read/write data on hotplug block. 4) Unplug block device during serving block io, then verify devices. 5) repeat step2~step4 100 times. :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ def _check_iozone_status(): ck_session = vm.wait_for_login(timeout=360) if not utils_misc.wait_for(lambda: check_cmd[os_type].split( )[-1].lower() in ck_session.cmd_output(check_cmd[os_type]).lower(), 180, step=3.0): test.fail("Iozone is not alive!") ck_session.close() def _run_iozone_background(): logging.info("Start iozone under background.") thread = utils_misc.InterruptedThread( iozone.run, (params['iozone_options'].format(mount_point), float(params['iozone_timeout']))) thread.start() _check_iozone_status() return thread check_cmd = { 'linux': 'pgrep -lx iozone', 'windows': 'TASKLIST /FI "IMAGENAME eq IOZONE.EXE' } os_type = params['os_type'] vm = env.get_vm(params["main_vm"]) vm.verify_alive() session = vm.wait_for_login(timeout=360) iozone = generate_instance(params, vm, 'iozone') plug = BlockDevicesPlug(vm) need_format = True try: for i in range(int(params['repeat_time'])): logging.info('Start to run testing.(iteration: %d).', (i + 1)) plug.hotplug_devs_serial() if need_format: if os_type == 'windows': utils_disk.update_windows_disk_attributes(session, plug[0]) mount_point = utils_disk.configure_empty_disk( session, plug[0], params['image_size_stg0'], os_type)[0] if os_type == 'windows': need_format = False iozone_thread = _run_iozone_background() time.sleep(float(params['sleep_time'])) _check_iozone_status() plug.unplug_devs_serial() iozone_thread.join(suppress_exception=True) finally: iozone.clean(force=True) session.close()
def run(test, params, env): """ Boot vm with virtio device:virtio-blk-pci, virtio-scsi-pci, virtio-net-pci and use aer=on for virtio devices. 1) Boot guest with virtio-blk-pci, virtio-scsi-pci, virtio-net-pci device, and use aer=on,ats=on for virtio devices. 2) check if aer and ats capabilitie in guest os :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ def get_pci_addr_by_devid(dev_id): """ Get pci address by device id. """ def _get_device_by_devid(devices, dev_id): """ Get device info with device id from 'info pci' output. """ device_found = {} for dev in devices: if dev['qdev_id'] == dev_id: device_found = dev break elif dev['class_info'].get('desc') == 'PCI bridge': pci_bridge_devices = dev['pci_bridge'].get('devices') if not pci_bridge_devices: continue device_found = _get_device_by_devid( pci_bridge_devices, dev_id) if device_found: break return device_found dev_addr = '' dev_addr_fmt = '%02d:%02d.%d' pci_info = vm.monitor.info('pci', debug=False) device = _get_device_by_devid(pci_info[0]['devices'], dev_id) if device: dev_addr = dev_addr_fmt % (device['bus'], device['slot'], device['function']) return dev_addr def check_dev_cap_in_guest(dev_id, capbilities): """ Check the specified device's capabilities in guest os :params dev_id: device id in qemu command line :params capbilities: the capabilities list that expected to be found :return True if get all the capabilities, else False """ dev_addr = get_pci_addr_by_devid(dev_id) for cap in capbilities: check_cmd = "lspci -vvv -s %s | grep '%s'" % (dev_addr, cap) if session.cmd_status(check_cmd) != 0: logging.error("Failed to get capability '%s' for device %s", cap, dev_id) return False return True if params.object_params('qmpmonitor1').get('monitor_type') == 'human': test.cancel("Please run test with qmp monitor") vm = env.get_vm(params["main_vm"]) session = vm.wait_for_login() capabilities = params['capabilities'].split(',') images = params.objects('images') dev_ids = [] blk_image = images[1] blk_dev = vm.devices.get_by_qid(blk_image)[0] blk_dev_id = blk_dev.params['id'] dev_ids.append(blk_dev_id) scsi_dev = vm.devices.get_by_params({'driver': 'virtio-scsi-pci'})[0] scsi_dev_id = scsi_dev.params['id'] dev_ids.append(scsi_dev_id) nic_id = vm.virtnet[0].device_id nic_dev = vm.devices.get_by_qid(nic_id)[0] nic_dev_id = nic_dev.params['id'] dev_ids.append(nic_dev_id) try: for dev_id in dev_ids: if not check_dev_cap_in_guest(dev_id, capabilities): test.fail('Check capabilities %s for device %s failed' % (capabilities, dev_id)) plug = BlockDevicesPlug(vm) for img in params.get("hotplug_images", "").split(): plug.unplug_devs_serial(img) plug.hotplug_devs_serial(img) blk_dev = vm.devices.get_by_qid(img)[0] blk_dev_id = blk_dev.params['id'] if not check_dev_cap_in_guest(blk_dev_id, capabilities): test.fail('Check capabilities %s for device %s failed' % (capabilities, blk_dev_id)) finally: session.close()
def utils_test(test, params, env, vm, session): """ :param test: :param params: :param env: :param vm: :param session: :return: """ logging.info(test, params, env, vm, session) tgm = ThrottleGroupManager(vm) logging.info("query_throttle_group group1") tgm.get_throttle_group_props("group1") logging.info("query_throttle_group group4") tgm.get_throttle_group_props("group4") # stg2 nonexist tgm.get_throttle_group_props("stg2") # group5 nonexist logging.info("delete_throttle_group group5") tgm.delete_throttle_group("group5") logging.info("query_throttle_group group3") tgm.get_throttle_group_props("group3") # add group3 failed logging.info("add_throttle_group group3") try: tgm.add_throttle_group("group3", {"iopsx-total": 50}) except Exception as err: logging.error(err) # add group3 succeed tgm.add_throttle_group("group3", {"iops-total": 50}) out = tgm.get_throttle_group_props("group3") logging.info(out) logging.info("get_throttle_group group3") dev = tgm.get_throttle_group("group3") plug = BlockDevicesPlug(vm) # hotplug stg7 logging.info("stg7 hot-plug") plug.hotplug_devs_serial("stg7") logging.info(vm.devices.str_bus_short()) # hotplug stg6 logging.info("stg6 hot-plug") plug.hotplug_devs_serial("stg6") logging.info(vm.devices.str_bus_short()) logging.info("change stg6 from group3 to group1") tgm.change_throttle_group("stg6", "group1") logging.info("change stg3 from group1 to group2") tgm.change_throttle_group("stg3", "group2") logging.info(vm.devices.str_bus_short()) logging.info("change stg3 from group2 to group1") tgm.change_throttle_group("stg3", "group1") logging.info(vm.devices.str_bus_short()) vm.monitor.info("block") logging.info("stg6 hot-unplug") plug.unplug_devs_serial("stg6") logging.info(vm.devices.str_bus_short()) logging.info("update throttle group") tgm.update_throttle_group("group3", {"bps-total": 150}) out = tgm.get_throttle_group_props("group3") logging.info(out) logging.info(dev.raw_limits) logging.info("throttle group hot-unplug") tgm.delete_throttle_group("group3") logging.info(vm.devices.str_bus_short()) tgm.get_throttle_group("group3") logging.info("==================") # image hotplug-unplug logging.info("unplug stg1 ") plug.unplug_devs_serial("stg1") logging.info(vm.devices.str_bus_short()) logging.info("plug stg1") plug.hotplug_devs_serial("stg1") logging.info(vm.devices.str_bus_short()) logging.info("unplug stg1") plug.unplug_devs_serial("stg1") logging.info(vm.devices.str_bus_short()) logging.info("==================") logging.info("plug stg5 belong to no group") plug.hotplug_devs_serial("stg5") logging.info(vm.devices.str_bus_short()) logging.info("unplug stg5") plug.unplug_devs_serial("stg5") logging.info(vm.devices.str_bus_short()) logging.info("sleep 3...") time.sleep(3) logging.info("test simple_hotplug ...") image_name = "stg1" image_params = params.object_params(image_name) # include blockdevs and devices stg_a_devs = vm.devices.images_define_by_params(image_name, image_params, 'disk') for dev in stg_a_devs: vm.devices.simple_hotplug(dev, vm.monitor) image_name = "stg5" image_params = params.object_params(image_name) stg_b_devs = vm.devices.images_define_by_params(image_name, image_params, 'disk') for dev in stg_b_devs: vm.devices.simple_hotplug(dev, vm.monitor) logging.info(vm.devices.str_bus_short()) time.sleep(3) logging.info("test simple_unplug ...") vm.devices.simple_unplug(stg_a_devs[-1], vm.monitor) vm.devices.simple_unplug(stg_b_devs[-1], vm.monitor) logging.info(vm.devices.str_bus_short()) time.sleep(3)
def run(test, params, env): """ Test the virtio scsi block device with virtio-scsi-pci.hotplug=on or off. Steps: 1. Start VM with virtio-scsi-pci(system disk). 2. Check whether vioscsi.sys verifier enabled in windows guest. 3. Hotplug a virtio-scsi disk with virtio-scsi-pci.hotplug=off via qmp. 4. Check the new disk in guest. 5. Rescan the scsi bus in the guest and recheck the disk. 6. Retest the step 3-4 with hotplug=on specified and then hot-unplug it. :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ def list_all_disks(session): """List all disks inside guest.""" if is_linux: return utils_misc.list_linux_guest_disks(session) return set(session.cmd('wmic diskdrive get index').split()[1:]) def _get_scsi_host_id(session): logging.info("Get the scsi host id which is hot plugged.") output = session.cmd("dmesg | grep \"scsi host\" | " "awk 'END{print}' | awk '{print $4}'") return re.search(r'(\d+)', output).group(1) def _rescan_hba_controller_linux(session): session.cmd('echo "- - -" > /sys/class/scsi_host/host%s/scan' % _get_scsi_host_id(session)) def _rescan_hba_controller_windows(session): session.cmd( 'echo rescan > {0} && echo exit >> {0} && diskpart / {0} ' '&& del /f {0}'.format('diskpart_script'), 300) def rescan_hba_controller(session): """Rescan the scsi hba controller.""" error_context.context("Rescan the scsi hba controller.", logging.info) if is_linux: _rescan_hba_controller_linux(session) else: _rescan_hba_controller_windows(session) is_linux = params['os_type'] == 'linux' vm = env.get_vm(params["main_vm"]) vm.verify_alive() session = vm.wait_for_login(timeout=360) if not is_linux: session = qemu.windrv_check_running_verifier(session, vm, test, params['driver_name'], 360) orig_disks = list_all_disks(session) plug = BlockDevicesPlug(vm) plug.hotplug_devs_serial(interval=int(params['hotplug_interval'])) if params['need_rescan_hba'] == 'yes': if utils_misc.wait_for( lambda: bool(list_all_disks(session) - orig_disks), 30, step=3): logging.debug('The all disks: %s.', list_all_disks(session)) test.fail('Found a new disk with virtio-scsi-pci.hotplug=off ' 'before rescan scsi hba controller.') rescan_hba_controller(session) plug.unplug_devs_serial()
def run(test, params, env): """ Test multi disk with multifunction on and off. 1) Boot guest with system disk(multifunction=on) 2) Hotplug 7 disks with addr 0x0.0x1~0x0.0x7 3) hotplug 1 disk with multifunction=on (addr 0x0) 4) Check disks in guest 5) Run dd/iozone test on all data disks 6) Reboot guest, check disks in guest 7) Unplug disk8, and remove disk 1-7 8) Hotplug disk8 with multifunction=off :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ def get_image_device(qdev, img_name): """ Get the image device(virtio-blk-pci/virtio-scsi-pci) :param qdev: DevContainer object :param img_name: The image name """ dev = qdev.get(img_name) devs = [dev] if params['drive_format'].startswith('scsi'): devs.append( qdev.get_by_properties( {'aid': dev.get_param('bus').split('.')[0]})[0]) return devs image = params.objects('images')[0] vm_name = params['main_vm'] set_addr(image, 0, 0, params) # Add multifunction=on option before start vm params['start_vm'] = 'yes' env_process.preprocess_vm(test, params, env, vm_name) vm = env.get_vm(vm_name) qdev = vm.devices windows = params["os_type"] == 'windows' disk_op_cmd = params.get("disk_op_cmd") session = vm.wait_for_login() q35 = params['machine_type'] == 'q35' dev_slot = 0 if q35 else 9 parent_bus = 'pcie_extra_root_port_0' if q35 else 'pci.0' image_size = '1G' # Generate the data disk devices to be plugged for i in range(1, 9): stg = 'stg%s' % i vm.params['images'] += ' %s' % stg vm.params['image_name_%s' % stg] = 'images/%s' % stg vm.params['image_size_%s' % stg] = image_size vm.params['remove_image_%s' % stg] = 'yes' vm.params['force_create_image_%s' % stg] = 'yes' vm.params['boot_drive_%s' % stg] = 'no' # Specify the address of the device, plug them into same slot set_addr(stg, dev_slot, i, vm.params) if params['drive_format'].startswith('scsi'): # Create oen new scsi bus for each block device vm.params['drive_bus_%s' % stg] = i # To create those image files env_process.process_images(env_process.preprocess_image, test, vm.params) plug = BlockDevicesPlug(vm) parent_bus_obj = qdev.get_buses({'aobject': parent_bus})[0] plug.hotplug_devs_serial(bus=parent_bus_obj) # Run io test on all the plugged disks io_test(session, disk_op_cmd, plug, windows, image_size) # Reboot the guest and check if all the disks still exist disks_before_reboot = block_hotplug.find_all_disks(session, windows) session = vm.reboot(session) block_hotplug.wait_plug_disks(session, 'check', disks_before_reboot, 0, windows, test) session.close() # Unplug the disk on function 7 and 0, and check if all the disks been removed images = vm.params.objects('images') unplug_dev = images[-1] unplug_timeout = params['unplug_timeout'] try: plug.unplug_devs_serial(images=unplug_dev, timeout=unplug_timeout) except exceptions.TestError as e: if 'Actual: 8 disks. Expected: ' not in str(e): raise else: test.fail('All the plugged disks should be removed when' ' the device at function 0 is removed.') # replug disk 2-7 rest_dev = images[1:-1] # Remove them from DevContainer first, they are unplugged by qemu # but still in DevContainer for img in rest_dev: devs_rm = get_image_device(qdev, img) list(map(lambda x: qdev.remove(x, recursive=False), devs_rm)) plug._create_devices(rest_dev, {'aobject': parent_bus}) for img, devs in plug._hotplugged_devs.items(): if img not in rest_dev: continue for dev in devs: args = (dev, vm.monitor) if isinstance(dev, QDevice): pci_device = qdev.is_pci_device(dev['driver']) if pci_device: args += (parent_bus_obj, ) elif not dev['driver'].startswith('scsi'): continue elif not isinstance(dev, QDrive): continue try: plug._hotplug_atomic(*args) except NotImplementedError: # Insert might fail for file node 1-7 not been removed # from vm.devices, which can be ignored pass # Replug disk 8 on slot 0 with multifunction='off' set_addr(images[-1], dev_slot, 0, vm.params, multifunction='off') plug._create_devices(unplug_dev.split(), {'aobject': parent_bus}) for img, devs in plug._hotplugged_devs.items(): for dev in devs: if (img == images[-1] and isinstance(dev, QDevice) and qdev.is_pci_device(dev['driver'])): dev['addr'] = hex(dev_slot) # for pci bus addr might be reset try: parent_bus_obj.prepare_hotplug(dev) dev.hotplug(vm.monitor, vm.devices.qemu_version) except QMPCmdError as e: if 'single function' not in str(e): raise else: test.fail( 'It should fail to hotplug a single function device' ' to the address where multifunction already on.') break else: plug._hotplug_atomic(dev, vm.monitor)
def unplug_path_disk(vm): """Unplug passthrough disk.""" error_context.context("Unplug passthrouth device", logging.info) plug = BlockDevicesPlug(vm) plug.unplug_devs_serial()