def run(test, params, env): """ Test nbd disk option. 1.Prepare backend storage 2.Use nbd to export the backend storage with or without TLS 3.Prepare a disk xml indicating to the backend storage 4.Start VM with disk hotplug/coldplug 5.Start snapshot or save/restore operations on ndb disk 6.Check some behaviours on VM 7.Recover test environment """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) virsh_dargs = {'debug': True, 'ignore_status': False} def check_disk_save_restore(save_file): """ Check domain save and restore operation. :param save_file: the path to saved file """ # Save the domain. ret = virsh.save(vm_name, save_file, **virsh_dargs) libvirt.check_exit_status(ret) # Restore the domain. ret = virsh.restore(save_file, **virsh_dargs) libvirt.check_exit_status(ret) def check_snapshot(): """ Check domain snapshot operations. """ # Cleaup dirty data if exists if os.path.exists(snapshot_name1_file): os.remove(snapshot_name1_file) if os.path.exists(snapshot_name2_mem_file): os.remove(snapshot_name2_mem_file) if os.path.exists(snapshot_name2_disk_file): os.remove(snapshot_name2_disk_file) device_target = 'vda' snapshot_name1_option = "--diskspec %s,file=%s,snapshot=external --disk-only --atomic" % ( device_target, snapshot_name1_file) ret = virsh.snapshot_create_as(vm_name, "%s %s" % (snapshot_name1, snapshot_name1_option), debug=True) libvirt.check_exit_status(ret) snap_lists = virsh.snapshot_list(vm_name, debug=True) if snapshot_name1 not in snap_lists: test.fail("Snapshot %s doesn't exist" % snapshot_name1) # Check file can be created after snapshot def _check_file_create(filename): """ Check whether file with specified filename exists or not. :param filename: finename """ try: session = vm.wait_for_login() if platform.platform().count('ppc64'): time.sleep(10) cmd = ("echo" " teststring > /tmp/{0}".format(filename)) status, output = session.cmd_status_output(cmd) if status != 0: test.fail("Failed to touch one file on VM internal") except (remote.LoginError, virt_vm.VMError, aexpect.ShellError) as e: logging.error(str(e)) raise finally: if session: session.close() _check_file_create("disk.txt") # Create memory snapshot. snapshot_name2_mem_option = "--memspec file=%s,snapshot=external" % ( snapshot_name2_mem_file) snapshot_name2_disk_option = "--diskspec %s,file=%s,snapshot=external --atomic" % ( device_target, snapshot_name2_disk_file) snapshot_name2_option = "%s %s" % (snapshot_name2_mem_option, snapshot_name2_disk_option) ret = virsh.snapshot_create_as(vm_name, "%s %s" % (snapshot_name2, snapshot_name2_option), debug=True) libvirt.check_exit_status(ret) snap_lists = virsh.snapshot_list(vm_name, debug=True) if snapshot_name2 not in snap_lists: test.fail("Snapshot: %s doesn't exist" % snapshot_name2) _check_file_create("mem.txt") def check_in_vm(target, old_parts): """ Check mount/read/write disk in VM. :param target: Disk dev in VM. :param old_parts: Original disk partitions in VM. :return: True if check successfully. """ try: session = vm.wait_for_login() if platform.platform().count('ppc64'): time.sleep(10) new_parts = utils_disk.get_parts_list(session) added_parts = list(set(new_parts).difference(set(old_parts))) logging.info("Added parts:%s", added_parts) if len(added_parts) != 1: logging.error("The number of new partitions is invalid in VM") return False else: added_part = added_parts[0] cmd = ("fdisk -l /dev/{0} && mkfs.ext4 -F /dev/{0} && " "mkdir -p test && mount /dev/{0} test && echo" " teststring > test/testfile && umount test".format( added_part)) status, output = session.cmd_status_output(cmd) logging.debug("Disk operation in VM:\nexit code:\n%s\noutput:\n%s", status, output) return status == 0 except (remote.LoginError, virt_vm.VMError, aexpect.ShellError) as e: logging.error(str(e)) return False # Disk specific attributes. device = params.get("virt_disk_device", "disk") device_target = params.get("virt_disk_device_target", "vdb") device_format = params.get("virt_disk_device_format", "raw") device_type = params.get("virt_disk_device_type", "file") device_bus = params.get("virt_disk_device_bus", "virtio") backend_storage_type = params.get("backend_storage_type", "iscsi") image_path = params.get("emulated_image") # Get config parameters status_error = "yes" == params.get("status_error") define_error = "yes" == params.get("define_error") check_partitions = "yes" == params.get("virt_disk_check_partitions", "yes") hotplug_disk = "yes" == params.get("hotplug_disk", "no") tls_enabled = "yes" == params.get("enable_tls", "no") domain_operation = params.get("domain_operation") # Get snapshot attributes. snapshot_name1 = params.get("snapshot_name1") snapshot_name1_file = params.get("snapshot_name1_file") snapshot_name2 = params.get("snapshot_name2") snapshot_name2_mem_file = params.get("snapshot_name2_mem_file") snapshot_name2_disk_file = params.get("snapshot_name2_disk_file") # Initialize one NbdExport object nbd = None # Start VM and get all partions in VM. if vm.is_dead(): vm.start() session = vm.wait_for_login() old_parts = utils_disk.get_parts_list(session) session.close() vm.destroy(gracefully=False) # Back up xml file. vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) try: vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) # Get server hostname. hostname = process.run('hostname', ignore_status=False, shell=True, verbose=True).stdout_text.strip() # Setup backend storage nbd_server_host = hostname nbd_server_port = params.get("nbd_server_port") image_path = params.get("emulated_image", "/var/lib/libvirt/images/nbdtest.img") export_name = params.get("export_name", None) deleteExisted = "yes" == params.get("deleteExisted", "yes") tls_bit = "no" if tls_enabled: tls_bit = "yes" # Initialize special test environment config for snapshot operations. if domain_operation == "snap_shot": first_disk = vm.get_first_disk_devices() image_path = first_disk['source'] device_target = 'vda' # Remove previous xml disks = vmxml.get_devices(device_type="disk") for disk_ in disks: if disk_.target['dev'] == device_target: vmxml.del_device(disk_) break # Create NbdExport object nbd = NbdExport(image_path, image_format=device_format, port=nbd_server_port, export_name=export_name, tls=tls_enabled, deleteExisted=deleteExisted) nbd.start_nbd_server() # Prepare disk source xml source_attrs_dict = {"protocol": "nbd", "tls": "%s" % tls_bit} if export_name: source_attrs_dict.update({"name": "%s" % export_name}) disk_src_dict = {} disk_src_dict.update({"attrs": source_attrs_dict}) disk_src_dict.update( {"hosts": [{ "name": nbd_server_host, "port": nbd_server_port }]}) # Add disk xml. disk_xml = Disk(type_name=device_type) disk_xml.device = device disk_xml.target = {"dev": device_target, "bus": device_bus} driver_dict = {"name": "qemu", "type": 'raw'} disk_xml.driver = driver_dict disk_source = disk_xml.new_disk_source(**disk_src_dict) disk_xml.source = disk_source logging.debug("new disk xml is: %s", disk_xml) # Sync VM xml if not hotplug_disk: vmxml.add_device(disk_xml) try: vmxml.sync() vm.start() vm.wait_for_login() except xcepts.LibvirtXMLError as xml_error: if not define_error: test.fail("Failed to define VM:\n%s" % str(xml_error)) except virt_vm.VMStartError as details: # When use wrong password in disk xml for cold plug cases, # VM cannot be started if status_error and not hotplug_disk: logging.info("VM failed to start as expected: %s" % str(details)) else: test.fail("VM should start but failed: %s" % str(details)) # Hotplug disk. if hotplug_disk: result = virsh.attach_device(vm_name, disk_xml.xml, ignore_status=True, debug=True) libvirt.check_exit_status(result, status_error) # Check save and restore operation and its result if domain_operation == 'save_restore': save_file = "/tmp/%s.save" % vm_name check_disk_save_restore(save_file) # Check attached nbd disk if check_partitions and not status_error: logging.debug("wait seconds for starting in checking vm part") time.sleep(2) if not check_in_vm(device_target, old_parts): test.fail("Check disk partitions in VM failed") # Check snapshot operation and its result if domain_operation == 'snap_shot': check_snapshot() # Unplug disk. if hotplug_disk: result = virsh.detach_device(vm_name, disk_xml.xml, ignore_status=True, debug=True) libvirt.check_exit_status(result, status_error) finally: # Clean up backend storage and TLS try: if nbd: nbd.cleanup() # Clean up snapshots if exist if domain_operation == 'snap_shot': snap_lists = virsh.snapshot_list(vm_name, debug=True) for snap_name in snap_lists: virsh.snapshot_delete(vm_name, snap_name, "--metadata", debug=True, ignore_status=True) # Cleaup dirty data if exists if os.path.exists(snapshot_name1_file): os.remove(snapshot_name1_file) if os.path.exists(snapshot_name2_mem_file): os.remove(snapshot_name2_mem_file) if os.path.exists(snapshot_name2_disk_file): os.remove(snapshot_name2_disk_file) except Exception as ndbEx: logging.info("Clean Up nbd failed: %s" % str(ndbEx)) # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) vmxml_backup.sync("--snapshots-metadata")
def run(test, params, env): """ Test usb virtual disk plug/unplug. 1.Prepare a vm with usb controllers 2.Prepare a local image 3.Prepare a virtual disk xml 4.Attach the virtual disk to the vm 5.Check the disk in vm 6.Unplug the disk from vm """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) def get_new_disks(old_partitions): """ Get new virtual disks in vm after disk plug. :param old_partitions: Already existing partitions in vm. :return: New disks/partitions in vm. """ session = None try: session = vm.wait_for_login() if platform.platform().count('ppc64'): time.sleep(10) new_partitions = utils_disk.get_parts_list(session) added_partitions = list( set(new_partitions).difference(set(old_partitions))) if not added_partitions: logging.debug("No new partitions found in vm.") else: logging.debug("Newly added partition(s) is: %s", added_partitions) return added_partitions except (remote.LoginError, virt_vm.VMError, aexpect.ShellError) as err: test.fail("Error happens when get new disk: %s", str(err)) finally: if session: session.close() def check_disk_type(partition): """ Check if a disk partition is a usb disk in vm. :param partition: The disk partition in vm to be checked. :return: If the disk is a usb device, return True. """ session = None try: session = vm.wait_for_login() if platform.platform().count('ppc64'): time.sleep(10) cmd = "ls -l /dev/disk/by-id/ | grep %s | grep -i usb" % partition status = session.cmd_status(cmd) return status == 0 except (remote.LoginError, virt_vm.VMError, aexpect.ShellError) as err: logging.debug( "Error happens when check if new disk is usb device: %s", str(err)) return False finally: if session: session.close() def check_disk_io(partition): """ Check if the disk partition in vm can be normally used. :param partition: The disk partition in vm to be checked. :return: If the disk can be used, return True. """ session = None try: session = vm.wait_for_login() cmd = ( "fdisk -l /dev/{0} && mkfs.ext4 -F /dev/{0} && " "mkdir -p test && mount /dev/{0} test && echo" " teststring > test/testfile && umount test".format(partition)) status, output = session.cmd_status_output(cmd) logging.debug("Disk operation in VM:\nexit code:\n%s\noutput:\n%s", status, output) return status == 0 except (remote.LoginError, virt_vm.VMError, aexpect.ShellError) as err: logging.debug("Error happens when check disk io in vm: %s", str(err)) return False finally: if session: session.close() def remove_usbs(vmxml): """ Remove all USB devices and controllers from a vm's xml. :param vmxml: The vm's xml. """ try: for xml in vmxml.xmltreefile.findall('/devices/*'): if (xml.get('bus') == 'usb') or (xml.get('type') == 'usb'): vmxml.xmltreefile.remove(xml) except (AttributeError, TypeError): pass # Element doesn't exist at first vmxml.xmltreefile.write() def prepare_usb_controller(vmxml, usb_models): """ Add usb controllers into vm's xml. :param vmxml: The vm's xml. :param usb_models: The usb models will be used in usb controller(s). """ if not usb_models: test.error("No usb model provided.") # Add disk usb controller(s) for usb_model in usb_models: usb_controller = Controller("controller") usb_controller.type = "usb" usb_controller.index = "0" usb_controller.model = usb_model vmxml.add_device(usb_controller) # Redefine domain vmxml.sync() def prepare_local_image(): """ Prepare a local image. :return: The path to the image file. """ image_filename = params.get("image_filename", "raw.img") image_format = params.get("image_format", "raw") image_size = params.get("image_size", "1G") image_path = os.path.join(data_dir.get_data_dir(), image_filename) try: if image_format in ["raw", "qcow2"]: image_path = libvirt.create_local_disk( "file", image_path, image_size, disk_format=image_format) else: test.cancel("We only test raw & qcow2 format for now.") except Exception as err: test.error("Error happens when prepare local image: %s", err) return image_path def prepare_virt_disk_xml(image_path): """ Prepare the virtual disk xml to be attached/detached. :param image_path: The path to the local image. :return: The virtual disk xml. """ virt_disk_device = params.get("virt_disk_device", "disk") virt_disk_device_type = params.get("virt_disk_device_type", "file") virt_disk_device_format = params.get("virt_disk_device_format", "raw") virt_disk_device_target = params.get("virt_disk_device_target", "sdb") virt_disk_device_bus = params.get("virt_disk_device_bus", "usb") disk_xml = Disk(type_name=virt_disk_device_type) disk_xml.device = virt_disk_device disk_src_dict = {'attrs': {'file': image_path, 'type_name': 'file'}} disk_xml.source = disk_xml.new_disk_source(**disk_src_dict) driver_dict = {"name": "qemu", "type": virt_disk_device_format} disk_xml.driver = driver_dict disk_xml.target = { "dev": virt_disk_device_target, "bus": virt_disk_device_bus } return disk_xml usb_models = params.get("usb_model").split() coldplug = "yes" == params.get("coldplug") status_error = "yes" == params.get("status_error") new_disks = [] new_disk = "" attach_options = "" # Get disk partitions info before hot/cold plug virtual disk if vm.is_dead(): vm.start() session = vm.wait_for_login() old_partitions = utils_disk.get_parts_list(session) session.close() vm.destroy(gracefully=False) # Backup vm xml vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) vmxml = vmxml_backup.copy() try: if 'vt82c686b-uhci' in usb_models and libvirt_version.version_compare( 7, 4, 0): test.cancel("vt82c686b-usb-uhci not supported in this QEMU") remove_usbs(vmxml) prepare_usb_controller(vmxml, usb_models) vm.start() session = vm.wait_for_login() disk_xml = prepare_virt_disk_xml(prepare_local_image()) session.close() if coldplug: attach_options = "--config" # Attach virtual disk to vm result = virsh.attach_device(vm_name, disk_xml.xml, flagstr=attach_options, ignore_status=True, debug=True) libvirt.check_exit_status(result, status_error) # Check the attached disk in vm if coldplug: vm.destroy(gracefully=False) vm.start() vm.wait_for_login().close() utils_misc.wait_for(lambda: get_new_disks(old_partitions), 20) new_disks = get_new_disks(old_partitions) if len(new_disks) != 1: test.fail("Attached 1 virtual disk but got %s." % len(new_disk)) new_disk = new_disks[0] if not check_disk_type(new_disk): test.fail("The newly attached disk is not a usb one.") if not check_disk_io(new_disk): test.fail("Cannot operate the newly added disk in vm.") # Detach the disk from vm result = virsh.detach_device(vm_name, disk_xml.xml, flagstr=attach_options, ignore_status=True, debug=True, wait_remove_event=True) libvirt.check_exit_status(result, status_error) # Check the detached disk in vm if coldplug: vm.destroy(gracefully=False) vm.start() vm.wait_for_login().close() utils_misc.wait_for(lambda: not get_new_disks(old_partitions), 20) new_disks = get_new_disks(old_partitions) if len(new_disks) != 0: test.fail("Unplug virtual disk failed.") finally: if vm.is_alive(): vm.destroy(gracefully=False) # Restoring vm vmxml_backup.sync()
def run(test, params, env): """ Test disk encryption option. 1.Prepare backend storage (blkdev/iscsi/gluster/ceph) 2.Use luks format to encrypt the backend storage 3.Prepare a disk xml indicating to the backend storage with valid/invalid luks password 4.Start VM with disk hot/cold plugged 5.Check some disk operations in VM 6.Check backend storage is still in luks format 7.Recover test environment """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) virsh_dargs = {'debug': True, 'ignore_status': True} def encrypt_dev(device, params): """ Encrypt device with luks format :param device: Storage deivce to be encrypted. :param params: From the dict to get encryption password. """ password = params.get("luks_encrypt_passwd", "password") size = params.get("luks_size", "500M") cmd = ( "qemu-img create -f luks " "--object secret,id=sec0,data=`printf '%s' | base64`,format=base64 " "-o key-secret=sec0 %s %s" % (password, device, size)) if process.system(cmd, shell=True): test.fail("Can't create a luks encrypted img by qemu-img") def check_dev_format(device, fmt="luks"): """ Check if device is in luks format :param device: Storage deivce to be checked. :param fmt: Expected disk format. :return: If device's format equals to fmt, return True, else return False. """ cmd_result = process.run("qemu-img" + ' -h', ignore_status=True, shell=True, verbose=False) if b'-U' in cmd_result.stdout: cmd = ("qemu-img info -U %s| grep -i 'file format' " "| grep -i %s" % (device, fmt)) else: cmd = ("qemu-img info %s| grep -i 'file format' " "| grep -i %s" % (device, fmt)) cmd_result = process.run(cmd, ignore_status=True, shell=True) if cmd_result.exit_status: test.fail("device %s is not in %s format. err is: %s" % (device, fmt, cmd_result.stderr)) def check_in_vm(target, old_parts): """ Check mount/read/write disk in VM. :param target: Disk dev in VM. :param old_parts: Original disk partitions in VM. :return: True if check successfully. """ try: session = vm.wait_for_login() if platform.platform().count('ppc64'): time.sleep(10) new_parts = utils_disk.get_parts_list(session) added_parts = list(set(new_parts).difference(set(old_parts))) logging.info("Added parts:%s", added_parts) if len(added_parts) != 1: logging.error("The number of new partitions is invalid in VM") return False else: added_part = added_parts[0] cmd = ("fdisk -l /dev/{0} && mkfs.ext4 -F /dev/{0} && " "mkdir -p test && mount /dev/{0} test && echo" " teststring > test/testfile && umount test".format( added_part)) status, output = session.cmd_status_output(cmd) logging.debug("Disk operation in VM:\nexit code:\n%s\noutput:\n%s", status, output) return status == 0 except (remote.LoginError, virt_vm.VMError, aexpect.ShellError) as e: logging.error(str(e)) return False # Disk specific attributes. device = params.get("virt_disk_device", "disk") device_target = params.get("virt_disk_device_target", "vdd") device_format = params.get("virt_disk_device_format", "raw") device_type = params.get("virt_disk_device_type", "file") device_bus = params.get("virt_disk_device_bus", "virtio") backend_storage_type = params.get("backend_storage_type", "iscsi") # Backend storage options. storage_size = params.get("storage_size", "1G") enable_auth = "yes" == params.get("enable_auth") # Luks encryption info, luks_encrypt_passwd is the password used to encrypt # luks image, and luks_secret_passwd is the password set to luks secret, you # can set a wrong password to luks_secret_passwd for negative tests luks_encrypt_passwd = params.get("luks_encrypt_passwd", "password") luks_secret_passwd = params.get("luks_secret_passwd", "password") # Backend storage auth info use_auth_usage = "yes" == params.get("use_auth_usage") if use_auth_usage: use_auth_uuid = False else: use_auth_uuid = "yes" == params.get("use_auth_uuid", "yes") auth_sec_usage_type = params.get("auth_sec_usage_type", "iscsi") auth_sec_usage_target = params.get("auth_sec_usage_target", "libvirtiscsi") status_error = "yes" == params.get("status_error") check_partitions = "yes" == params.get("virt_disk_check_partitions", "yes") hotplug_disk = "yes" == params.get("hotplug_disk", "no") encryption_in_source = "yes" == params.get("encryption_in_source", "no") auth_in_source = "yes" == params.get("auth_in_source", "no") auth_sec_uuid = "" luks_sec_uuid = "" disk_auth_dict = {} disk_encryption_dict = {} pvt = None if ((encryption_in_source or auth_in_source) and not libvirt_version.version_compare(3, 9, 0)): test.cancel("Cannot put <encryption> or <auth> inside disk <source> " "in this libvirt version.") # Start VM and get all partions in VM. if vm.is_dead(): vm.start() session = vm.wait_for_login() old_parts = utils_disk.get_parts_list(session) session.close() vm.destroy(gracefully=False) # Back up xml file. vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) try: # Setup backend storage if backend_storage_type == "iscsi": iscsi_host = params.get("iscsi_host") iscsi_port = params.get("iscsi_port") if device_type == "block": device_source = libvirt.setup_or_cleanup_iscsi(is_setup=True) disk_src_dict = {'attrs': {'dev': device_source}} elif device_type == "network": if enable_auth: chap_user = params.get("chap_user", "redhat") chap_passwd = params.get("chap_passwd", "password") auth_sec_usage = params.get("auth_sec_usage", "libvirtiscsi") auth_sec_dict = { "sec_usage": "iscsi", "sec_target": auth_sec_usage } auth_sec_uuid = libvirt.create_secret(auth_sec_dict) # Set password of auth secret (not luks encryption secret) virsh.secret_set_value(auth_sec_uuid, chap_passwd, encode=True, debug=True) iscsi_target, lun_num = libvirt.setup_or_cleanup_iscsi( is_setup=True, is_login=False, image_size=storage_size, chap_user=chap_user, chap_passwd=chap_passwd, portal_ip=iscsi_host) # ISCSI auth attributes for disk xml if use_auth_uuid: disk_auth_dict = { "auth_user": chap_user, "secret_type": auth_sec_usage_type, "secret_uuid": auth_sec_uuid } elif use_auth_usage: disk_auth_dict = { "auth_user": chap_user, "secret_type": auth_sec_usage_type, "secret_usage": auth_sec_usage_target } else: iscsi_target, lun_num = libvirt.setup_or_cleanup_iscsi( is_setup=True, is_login=False, image_size=storage_size, portal_ip=iscsi_host) device_source = "iscsi://%s:%s/%s/%s" % ( iscsi_host, iscsi_port, iscsi_target, lun_num) disk_src_dict = { "attrs": { "protocol": "iscsi", "name": "%s/%s" % (iscsi_target, lun_num) }, "hosts": [{ "name": iscsi_host, "port": iscsi_port }] } elif backend_storage_type == "gluster": gluster_vol_name = params.get("gluster_vol_name", "gluster_vol1") gluster_pool_name = params.get("gluster_pool_name", "gluster_pool1") gluster_img_name = params.get("gluster_img_name", "gluster1.img") gluster_host_ip = libvirt.setup_or_cleanup_gluster( is_setup=True, vol_name=gluster_vol_name, pool_name=gluster_pool_name, **params) device_source = "gluster://%s/%s/%s" % ( gluster_host_ip, gluster_vol_name, gluster_img_name) disk_src_dict = { "attrs": { "protocol": "gluster", "name": "%s/%s" % (gluster_vol_name, gluster_img_name) }, "hosts": [{ "name": gluster_host_ip, "port": "24007" }] } elif backend_storage_type == "ceph": ceph_host_ip = params.get("ceph_host_ip", "EXAMPLE_HOSTS") ceph_mon_ip = params.get("ceph_mon_ip", "EXAMPLE_MON_HOST") ceph_host_port = params.get("ceph_host_port", "EXAMPLE_PORTS") ceph_disk_name = params.get("ceph_disk_name", "EXAMPLE_SOURCE_NAME") ceph_client_name = params.get("ceph_client_name") ceph_client_key = params.get("ceph_client_key") ceph_auth_user = params.get("ceph_auth_user") ceph_auth_key = params.get("ceph_auth_key") enable_auth = "yes" == params.get("enable_auth") key_file = os.path.join(data_dir.get_tmp_dir(), "ceph.key") key_opt = "" # Prepare a blank params to confirm if delete the configure at the end of the test ceph_cfg = "" if not utils_package.package_install(["ceph-common"]): test.error("Failed to install ceph-common") # Create config file if it doesn't exist ceph_cfg = ceph.create_config_file(ceph_mon_ip) if enable_auth: # If enable auth, prepare a local file to save key if ceph_client_name and ceph_client_key: with open(key_file, 'w') as f: f.write("[%s]\n\tkey = %s\n" % (ceph_client_name, ceph_client_key)) key_opt = "--keyring %s" % key_file auth_sec_dict = { "sec_usage": auth_sec_usage_type, "sec_name": "ceph_auth_secret" } auth_sec_uuid = libvirt.create_secret(auth_sec_dict) virsh.secret_set_value(auth_sec_uuid, ceph_auth_key, debug=True) disk_auth_dict = { "auth_user": ceph_auth_user, "secret_type": auth_sec_usage_type, "secret_uuid": auth_sec_uuid } cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} rm " "{2}".format(ceph_mon_ip, key_opt, ceph_disk_name)) else: test.error("No ceph client name/key provided.") device_source = "rbd:%s:mon_host=%s:keyring=%s" % ( ceph_disk_name, ceph_mon_ip, key_file) else: device_source = "rbd:%s:mon_host=%s" % (ceph_disk_name, ceph_mon_ip) disk_src_dict = { "attrs": { "protocol": "rbd", "name": ceph_disk_name }, "hosts": [{ "name": ceph_host_ip, "port": ceph_host_port }] } elif backend_storage_type == "nfs": pool_name = params.get("pool_name", "nfs_pool") pool_target = params.get("pool_target", "nfs_mount") pool_type = params.get("pool_type", "netfs") nfs_server_dir = params.get("nfs_server_dir", "nfs_server") emulated_image = params.get("emulated_image") image_name = params.get("nfs_image_name", "nfs.img") tmp_dir = data_dir.get_tmp_dir() pvt = libvirt.PoolVolumeTest(test, params) pvt.pre_pool(pool_name, pool_type, pool_target, emulated_image) nfs_mount_dir = os.path.join(tmp_dir, pool_target) device_source = nfs_mount_dir + image_name disk_src_dict = { 'attrs': { 'file': device_source, 'type_name': 'file' } } else: test.cancel("Only iscsi/gluster/rbd/nfs can be tested for now.") logging.debug("device source is: %s", device_source) luks_sec_uuid = libvirt.create_secret(params) logging.debug("A secret created with uuid = '%s'", luks_sec_uuid) ret = virsh.secret_set_value(luks_sec_uuid, luks_secret_passwd, encode=True, debug=True) encrypt_dev(device_source, params) libvirt.check_exit_status(ret) # Add disk xml. vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) disk_xml = Disk(type_name=device_type) disk_xml.device = device disk_xml.target = {"dev": device_target, "bus": device_bus} driver_dict = {"name": "qemu", "type": device_format} disk_xml.driver = driver_dict disk_source = disk_xml.new_disk_source(**disk_src_dict) if disk_auth_dict: logging.debug("disk auth dict is: %s" % disk_auth_dict) if auth_in_source: disk_source.auth = disk_xml.new_auth(**disk_auth_dict) else: disk_xml.auth = disk_xml.new_auth(**disk_auth_dict) disk_encryption_dict = { "encryption": "luks", "secret": { "type": "passphrase", "uuid": luks_sec_uuid } } disk_encryption = disk_xml.new_encryption(**disk_encryption_dict) if encryption_in_source: disk_source.encryption = disk_encryption else: disk_xml.encryption = disk_encryption disk_xml.source = disk_source logging.debug("new disk xml is: %s", disk_xml) # Sync VM xml if not hotplug_disk: vmxml.add_device(disk_xml) vmxml.sync() try: vm.start() vm.wait_for_login() except virt_vm.VMStartError as details: # When use wrong password in disk xml for cold plug cases, # VM cannot be started if status_error and not hotplug_disk: logging.info("VM failed to start as expected: %s" % str(details)) else: test.fail("VM should start but failed: %s" % str(details)) if hotplug_disk: result = virsh.attach_device(vm_name, disk_xml.xml, ignore_status=True, debug=True) libvirt.check_exit_status(result, status_error) if check_partitions and not status_error: if not check_in_vm(device_target, old_parts): test.fail("Check disk partitions in VM failed") check_dev_format(device_source) finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) vmxml_backup.sync("--snapshots-metadata") # Clean up backend storage if backend_storage_type == "iscsi": gluster.setup_or_cleanup_iscsi(is_setup=False) elif backend_storage_type == "gluster": gluster.setup_or_cleanup_gluster(is_setup=False, vol_name=gluster_vol_name, pool_name=gluster_pool_name, **params) elif backend_storage_type == "ceph": # Remove ceph configure file if created. if ceph_cfg: os.remove(ceph_cfg) cmd = ("rbd -m {0} {1} info {2} && rbd -m {0} {1} rm " "{2}".format(ceph_mon_ip, key_opt, ceph_disk_name)) cmd_result = process.run(cmd, ignore_status=True, shell=True) logging.debug("result of rbd removal: %s", cmd_result) if os.path.exists(key_file): os.remove(key_file) # Clean up secrets if auth_sec_uuid: virsh.secret_undefine(auth_sec_uuid) if luks_sec_uuid: virsh.secret_undefine(luks_sec_uuid) # Clean up pools if pvt: pvt.cleanup_pool(pool_name, pool_type, pool_target, emulated_image)
def run(test, params, env): """ Test command: domfsinfo [--domain] The command gets information of domain's mounted filesystems. """ start_vm = ("yes" == params.get("start_vm", "yes")) start_ga = ("yes" == params.get("start_ga", "yes")) prepare_channel = ("yes" == params.get("prepare_channel", "yes")) status_error = ("yes" == params.get("status_error", "no")) vm_name = params.get("main_vm") vm = env.get_vm(vm_name) mount_dir = params.get("mount_dir", None) quiet_mode = ("yes" == params.get("quiet_mode", False)) readonly_mode = ("yes" == params.get("readonly_mode", False)) nfs_mount = ("yes" == params.get("nfs_mount", False)) domfsfreeze = ("yes" == params.get("domfsfreeze", False)) # Hotplug and Unplug options hotplug_unplug = ("yes" == params.get("hotplug_unplug", False)) disk_name = params.get("disk_name", "test") disk_path = os.path.join(data_dir.get_tmp_dir(), disk_name) disk_target = params.get("disk_target", "vdb") fs_type = params.get("fs_type", "ext3") new_part = "" fail_pat = [] check_point_msg = params.get("check_point_msg", "") if check_point_msg: for msg in check_point_msg.split(";"): fail_pat.append(msg) def hotplug_domain_disk(domain, target, source=None, hotplug=True): """ Hot-plug/Hot-unplug disk for domain :param domain: Guest name :param source: Source of disk device, can leave None if hotplug=False :param target: Target of disk device :param hotplug: True means hotplug, False means hot-unplug :return: Virsh command object """ if hotplug: result = virsh.attach_disk(domain, source, target, "--live", ignore_status=False, debug=True) else: session = vm.wait_for_login() try: session.cmd("umount %s" % mount_dir) session.close() except: test.error( "fail to unmount the disk before unpluging the disk") result = virsh.detach_disk(domain, target, "--live", ignore_status=False, debug=True) # It need more time for attachment to take effect time.sleep(5) vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) cleanup_nfs = False try: reset_kwargs = { "start_vm": start_vm, "start_ga": start_ga, "prepare_channel": prepare_channel } reset_domain(vm, **reset_kwargs) if domfsfreeze: result = virsh.domfsfreeze(vm_name, debug=True) if result.exit_status: test.fail("Failed to execute virsh.domfsfreeze:\n%s" % result.stderr) if nfs_mount: nfs_device = libvirt.setup_or_cleanup_nfs(True, mount_dir=mount_dir, is_mount=True) if nfs_device: cleanup_nfs = True if hotplug_unplug: session = vm.wait_for_login() new_device = libvirt.create_local_disk("file", path=disk_path, size="1") parts_list_before_attach = utils_disk.get_parts_list(session) hotplug_domain_disk(vm_name, disk_target, new_device) parts_list_after_attach = utils_disk.get_parts_list(session) new_part = list( set(parts_list_after_attach).difference( set(parts_list_before_attach)))[0] logging.debug("The new partition is %s", new_part) libvirt.mkfs("/dev/%s" % new_part, fs_type, session=session) session.cmd_status( "mkdir -p {0} ; mount /dev/{1} {0}; ls {0}".format( mount_dir, new_part)) session.close() # Run test case command_dargs = { "readonly": readonly_mode, "quiet": quiet_mode, "debug": True } result = virsh.domfsinfo(vm_name, **command_dargs) if not result.exit_status: if fail_pat: test.fail("Expected fail with %s, but run succeed:\n%s" % (fail_pat, result)) else: if not fail_pat: test.fail("Expected success, but run failed:\n%s" % result) else: # If not any pattern matches(fail_pat, result.stderr) if not any(p in result.stderr for p in fail_pat): test.fail( "Expected fail with one of %s, but failed with:\n%s" % (fail_pat, result)) # Check virsh.domfsinfo output cmd_output = result.stdout.strip() if quiet_mode: head_pat = "Mountpoint\s+Name\s+Type\s+Target" check_output(cmd_output, head_pat, test, expected=False) elif nfs_mount: check_output(cmd_output, mount_dir, test, expected=False) elif hotplug_unplug: blk_target = re.findall(r'[a-z]+', new_part)[0] disk_pat = "%s\s+%s\s+%s\s+%s" % (mount_dir, new_part, fs_type, blk_target) check_output(cmd_output, disk_pat, test, expected=True) # Unplug domain disk hotplug_domain_disk(vm_name, target=new_part, hotplug=False) result = virsh.domfsinfo(vm_name, **command_dargs) if result.exit_status: test.fail( "Failed to run virsh.domfsinfo after disk unplug:\n%s" % result.stderr) check_output(result.stdout.strip(), disk_pat, test, expected=False) else: # Verify virsh.domfsinfo consistency if not status_error: session = vm.wait_for_login(timeout=120) domfsinfo = vm.domfsinfo() expected_result = get_mount_fs(session) if domfsinfo and expected_result: check_domfsinfo(domfsinfo, expected_result, test) else: logging.debug("Virsh.domfsinfo output:\n%s", domfsinfo) logging.debug("Expected_result is:\n%s", expected_result) test.error("Command output inconsistent with expected") session.close() finally: if cleanup_nfs: libvirt.setup_or_cleanup_nfs(False, mount_dir=mount_dir) if vm.is_alive(): vm.destroy() if hotplug_unplug: if disk_path: cmd = "rm -rf %s" % disk_path process.run(cmd) vmxml_backup.sync()
def run(test, params, env): """ Test virsh {at|de}tach-disk command. The command can attach new disk/detach disk. 1.Prepare test environment,destroy or suspend a VM. 2.Perform virsh attach/detach-disk operation. 3.Recover test environment. 4.Confirm the test result. """ def check_info_in_audit_log_file(test_cmd, device_source): """ Check if information can be found in audit.log. :params test_cmd: test command :params device_source: device source """ grep_audit = ('grep "%s" /var/log/audit/audit.log' % test_cmd.split("-")[0]) cmd = (grep_audit + ' | ' + 'grep "%s" | tail -n1 | grep "res=success"' % device_source) return process.run(cmd, ignore_status=True, shell=True).exit_status == 0 def check_vm_partition(vm, device, os_type, target_name, old_parts): """ Check VM disk's partition. :param vm. VM guest. :param os_type. VM's operation system type. :param target_name. Device target type. :return: True if check successfully. """ logging.info("Checking VM partittion...") if vm.is_dead(): vm.start() try: attached = False if os_type == "linux": session = vm.wait_for_login() new_parts = utils_disk.get_parts_list(session) added_parts = list(set(new_parts).difference(set(old_parts))) logging.debug("Added parts: %s" % added_parts) for i in range(len(added_parts)): if device == "disk": if target_name.startswith("vd"): if added_parts[i].startswith("vd"): attached = True elif target_name.startswith( "hd") or target_name.startswith("sd"): if added_parts[i].startswith("sd"): attached = True elif device == "cdrom": if added_parts[i].startswith("sr"): attached = True session.close() return attached except (remote.LoginError, virt_vm.VMError, aexpect.ShellError) as e: logging.error(str(e)) return False def acpiphp_module_modprobe(vm, os_type): """ Add acpiphp module if VM's os type is rhle5.* :param vm. VM guest. :param os_type. VM's operation system type. :return: True if operate successfully. """ if vm.is_dead(): vm.start() try: if os_type == "linux": session = vm.wait_for_login() s_rpm, _ = session.cmd_status_output("rpm --version") # If status is different from 0, this # guest OS doesn't support the rpm package # manager if s_rpm: session.close() return True _, o_vd = session.cmd_status_output( "rpm -qa | grep redhat-release") if o_vd.find("5Server") != -1: s_mod, o_mod = session.cmd_status_output( "modprobe acpiphp") del o_mod if s_mod != 0: session.close() return False session.close() return True except (remote.LoginError, virt_vm.VMError, aexpect.ShellError) as e: logging.error(str(e)) return False def check_shareable(at_with_shareable, test_twice): """ check if current libvirt version support shareable option at_with_shareable: True or False. Whether attach disk with shareable option test_twice: True or False. Whether perform operations twice return: True or cancel the test """ if at_with_shareable or test_twice: if libvirt_version.version_compare(3, 9, 0): return True else: test.cancel( "Current libvirt version doesn't support shareable feature" ) # Get test command. test_cmd = params.get("at_dt_disk_test_cmd", "attach-disk") vm_ref = params.get("at_dt_disk_vm_ref", "name") at_options = params.get("at_dt_disk_at_options", "") dt_options = params.get("at_dt_disk_dt_options", "") at_with_shareable = "yes" == params.get("at_with_shareable", 'no') pre_vm_state = params.get("at_dt_disk_pre_vm_state", "running") status_error = "yes" == params.get("status_error", 'no') no_attach = params.get("at_dt_disk_no_attach", 'no') os_type = params.get("os_type", "linux") qemu_file_lock = params.get("qemu_file_lock", "") if qemu_file_lock: if utils_misc.compare_qemu_version(2, 9, 0): logging.info('From qemu-kvm-rhev 2.9.0:' 'QEMU image locking, which should prevent multiple ' 'runs of QEMU or qemu-img when a VM is running.') if test_cmd == "detach-disk" or pre_vm_state == "shut off": test.cancel('This case is not supported.') else: logging.info( 'The expect result is failure as opposed with succeed') status_error = True # Disk specific attributes. device = params.get("at_dt_disk_device", "disk") device_source_name = params.get("at_dt_disk_device_source", "attach.img") device_source_format = params.get("at_dt_disk_device_source_format", "raw") device_target = params.get("at_dt_disk_device_target", "vdd") device_disk_bus = params.get("at_dt_disk_bus_type", "virtio") source_path = "yes" == params.get("at_dt_disk_device_source_path", "yes") create_img = "yes" == params.get("at_dt_disk_create_image", "yes") test_twice = "yes" == params.get("at_dt_disk_test_twice", "no") test_systemlink_twice = "yes" == params.get( "at_dt_disk_twice_with_systemlink", "no") test_type = "yes" == params.get("at_dt_disk_check_type", "no") test_audit = "yes" == params.get("at_dt_disk_check_audit", "no") test_block_dev = "yes" == params.get("at_dt_disk_iscsi_device", "no") test_logcial_dev = "yes" == params.get("at_dt_disk_logical_device", "no") restart_libvirtd = "yes" == params.get("at_dt_disk_restart_libvirtd", "no") detach_disk_with_print_xml = "yes" == params.get( "detach_disk_with_print_xml", "no") vg_name = params.get("at_dt_disk_vg", "vg_test_0") lv_name = params.get("at_dt_disk_lv", "lv_test_0") # Get additional lvm item names. additional_lv_names = params.get("at_dt_disk_additional_lvs", "").split() serial = params.get("at_dt_disk_serial", "") address = params.get("at_dt_disk_address", "") address2 = params.get("at_dt_disk_address2", "") cache_options = params.get("cache_options", "") time_sleep = params.get("time_sleep", 3) # Define one empty list to locate those lvm. total_lvm_names = [] if check_shareable(at_with_shareable, test_twice): at_options += " --mode shareable" if serial: at_options += (" --serial %s" % serial) if address2: at_options_twice = at_options + (" --address %s" % address2) if address: at_options += (" --address %s" % address) if cache_options: if cache_options.count("directsync"): if not libvirt_version.version_compare(1, 0, 0): test.cancel("'directsync' cache option doesn't " "support in current libvirt version.") at_options += (" --cache %s" % cache_options) machine_type = params.get('machine_type') vm_name = params.get("main_vm") vm = env.get_vm(vm_name) # Start vm and get all partitions in vm. if vm.is_dead(): vm.start() session = vm.wait_for_login() old_parts = utils_disk.get_parts_list(session) session.close() vm.destroy(gracefully=False) # Back up xml file. backup_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) vm_dump_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Create virtual device file. device_source_path = os.path.join(data_dir.get_data_dir(), device_source_name) if test_block_dev: device_source = libvirt.setup_or_cleanup_iscsi(True) if not device_source: # We should skip this case test.cancel("Can not get iscsi device name in host") if test_logcial_dev: if lv_utils.vg_check(vg_name): lv_utils.vg_remove(vg_name) lv_utils.vg_create(vg_name, device_source) device_source = libvirt.create_local_disk("lvm", size="10M", vgname=vg_name, lvname=lv_name) logging.debug("New created volume: %s", lv_name) total_lvm_names.append(device_source) if test_systemlink_twice: for lvm__item_name in additional_lv_names: additional_device_source = libvirt.create_local_disk( "lvm", size="10M", vgname=vg_name, lvname=lvm__item_name) logging.debug("New created volume: %s", additional_device_source) total_lvm_names.append(additional_device_source) else: if source_path and create_img: device_source = libvirt.create_local_disk( "file", path=device_source_path, size="1G", disk_format=device_source_format) else: device_source = device_source_name if machine_type == 'q35': # Add more pci controllers to avoid error: No more available PCI slots if test_twice and params.get("add_more_pci_controllers", "yes") == "yes": vm_dump_xml.remove_all_device_by_type('controller') machine_list = vm_dump_xml.os.machine.split("-") vm_dump_xml.set_os_attrs( **{"machine": machine_list[0] + "-q35-" + machine_list[2]}) q35_pcie_dict0 = { 'controller_model': 'pcie-root', 'controller_type': 'pci', 'controller_index': 0 } q35_pcie_dict1 = { 'controller_model': 'pcie-root-port', 'controller_type': 'pci' } vm_dump_xml.add_device( libvirt.create_controller_xml(q35_pcie_dict0)) # Add enough controllers to match multiple times disk attaching requirements for i in list(range(1, 15)): q35_pcie_dict1.update({'controller_index': "%d" % i}) vm_dump_xml.add_device( libvirt.create_controller_xml(q35_pcie_dict1)) vm_dump_xml.sync() if params.get("reset_pci_controllers_nums", "no") == "yes" \ and 'attach-disk' in test_cmd: libvirt_pcicontr.reset_pci_num(vm_name, 15) # if we are testing audit, we need to start audit servcie first. if test_audit: auditd_service = Factory.create_service("auditd") if not auditd_service.status(): auditd_service.start() logging.info("Auditd service status: %s" % auditd_service.status()) # If we are testing cdrom device, we need to detach hdc in VM first. if device == "cdrom": if vm.is_alive(): vm.destroy(gracefully=False) s_detach = virsh.detach_disk(vm_name, device_target, "--config") if not s_detach: logging.error("Detach hdc failed before test.") # If we are testing detach-disk, we need to attach certain device first. if test_cmd == "detach-disk" and no_attach != "yes": s_at_options = "--driver qemu --config" #Since lock feature is introduced in libvirt 3.9.0 afterwards, disk shareable options #need be set if disk needs be attached multitimes if check_shareable(at_with_shareable, test_twice): s_at_options += " --mode shareable" s_attach = virsh.attach_disk(vm_name, device_source, device_target, s_at_options, debug=True).exit_status if s_attach != 0: logging.error("Attaching device failed before testing detach-disk") else: logging.debug( "Attaching device succeeded before testing detach-disk") if test_twice: device_target2 = params.get("at_dt_disk_device_target2", device_target) device_source = libvirt.create_local_disk( "file", path=device_source_path, size="1", disk_format=device_source_format) s_attach = virsh.attach_disk(vm_name, device_source, device_target2, s_at_options).exit_status if s_attach != 0: logging.error("Attaching device failed before testing " "detach-disk test_twice") vm.start() vm.wait_for_login() # Add acpiphp module before testing if VM's os type is rhle5.* if not acpiphp_module_modprobe(vm, os_type): test.error("Add acpiphp module failed before test.") # Turn VM into certain state. if pre_vm_state == "paused": logging.info("Suspending %s..." % vm_name) if vm.is_alive(): vm.pause() elif pre_vm_state == "shut off": logging.info("Shutting down %s..." % vm_name) if vm.is_alive(): vm.destroy(gracefully=False) # Get disk count before test. disk_count_before_cmd = vm_xml.VMXML.get_disk_count(vm_name) # Test. domid = vm.get_id() domuuid = vm.get_uuid() # Confirm how to reference a VM. if vm_ref == "name": vm_ref = vm_name elif vm_ref.find("invalid") != -1: vm_ref = params.get(vm_ref) elif vm_ref == "id": vm_ref = domid elif vm_ref == "hex_id": vm_ref = hex(int(domid)) elif vm_ref == "uuid": vm_ref = domuuid else: vm_ref = "" if test_cmd == "attach-disk": status = virsh.attach_disk(vm_ref, device_source, device_target, at_options, debug=True).exit_status elif test_cmd == "detach-disk": # For detach disk with print-xml option, it only print information,and not actual disk detachment. if detach_disk_with_print_xml and libvirt_version.version_compare( 4, 5, 0): ret = virsh.detach_disk(vm_ref, device_target, at_options) libvirt.check_exit_status(ret) cmd = ("echo \"%s\" | grep -A 16 %s" % (ret.stdout.strip(), device_source_name)) if process.system(cmd, ignore_status=True, shell=True): test.error("Check disk with source image name failed") status = virsh.detach_disk(vm_ref, device_target, dt_options, debug=True).exit_status if restart_libvirtd: libvirtd_serv = utils_libvirtd.Libvirtd() libvirtd_serv.restart() if test_twice: device_target2 = params.get("at_dt_disk_device_target2", device_target) device_source = libvirt.create_local_disk( "file", path=device_source_path, size="1G", disk_format=device_source_format) if test_cmd == "attach-disk": if address2: at_options = at_options_twice status = virsh.attach_disk(vm_ref, device_source, device_target2, at_options, debug=True).exit_status elif test_cmd == "detach-disk": status = virsh.detach_disk(vm_ref, device_target2, dt_options, debug=True).exit_status if test_systemlink_twice: # Detach lvm previously attached. result = virsh.detach_disk(vm_ref, device_target, dt_options, debug=True) libvirt.check_exit_status(result) # Remove systemlink for lv01,lv02,and lv03 for lvm_item in total_lvm_names: remove_systemlink_cmd = ('lvchange -a n %s' % lvm_item) if process.run(remove_systemlink_cmd, shell=True).exit_status: logging.error("Remove systemlink failed") # Add new systemlink for lv01,lv02,and lv03 by shifting one position for index in range(0, len(total_lvm_names)): add_systemlink_cmd = ( 'lvchange -a y %s' % total_lvm_names[(index + 1) % len(total_lvm_names)]) if process.run(add_systemlink_cmd, shell=True).exit_status: logging.error("Add systemlink failed") # Attach lvm lv01 again. result = virsh.attach_disk(vm_ref, device_source, device_target, at_options, debug=True) libvirt.check_exit_status(result) # Detach lvm 01 again. result = virsh.detach_disk(vm_ref, device_target, dt_options, debug=True) libvirt.check_exit_status(result) # Resume guest after command. On newer libvirt this is fixed as it has # been a bug. The change in xml file is done after the guest is resumed. if pre_vm_state == "paused": vm.resume() time.sleep(5) # Check audit log check_audit_after_cmd = True if test_audit: result = utils_misc.wait_for( lambda: check_info_in_audit_log_file(test_cmd, device_source), timeout=20) if not result: logging.error("Audit check failed") check_audit_after_cmd = False # Need wait a while for xml to sync time.sleep(float(time_sleep)) # Check disk count after command. check_count_after_cmd = True disk_count_after_cmd = vm_xml.VMXML.get_disk_count(vm_name) if test_cmd == "attach-disk": if disk_count_after_cmd == disk_count_before_cmd: check_count_after_cmd = False elif test_cmd == "detach-disk": if disk_count_after_cmd < disk_count_before_cmd: check_count_after_cmd = False # Recover VM state. if pre_vm_state == "shut off": vm.start() # Check in VM after command. check_vm_after_cmd = True check_vm_after_cmd = check_vm_partition(vm, device, os_type, device_target, old_parts) # Check disk type after attach. check_disk_type = True if test_type: if test_block_dev: check_disk_type = vm_xml.VMXML.check_disk_type( vm_name, device_source, "block") else: check_disk_type = vm_xml.VMXML.check_disk_type( vm_name, device_source, "file") # Check disk serial after attach. check_disk_serial = True if serial: disk_serial = vm_xml.VMXML.get_disk_serial(vm_name, device_target) if serial != disk_serial: check_disk_serial = False # Check disk address after attach. check_disk_address = True if address: disk_address = vm_xml.VMXML.get_disk_address(vm_name, device_target) if address != disk_address: check_disk_address = False # Check multifunction address after attach. check_disk_address2 = True if address2: disk_address2 = vm_xml.VMXML.get_disk_address(vm_name, device_target2) if address2 != disk_address2: check_disk_address2 = False # Check disk cache option after attach. check_cache_after_cmd = True if cache_options: disk_cache = vm_xml.VMXML.get_disk_attr(vm_name, device_target, "driver", "cache") if cache_options == "default": if disk_cache is not None: check_cache_after_cmd = False elif disk_cache != cache_options: check_cache_after_cmd = False # Eject cdrom test eject_cdrom = "yes" == params.get("at_dt_disk_eject_cdrom", "no") save_vm = "yes" == params.get("at_dt_disk_save_vm", "no") save_file = os.path.join(data_dir.get_data_dir(), "vm.save") try: if eject_cdrom: eject_params = { 'type_name': "file", 'device_type': "cdrom", 'target_dev': device_target, 'target_bus': device_disk_bus } eject_xml = libvirt.create_disk_xml(eject_params) with open(eject_xml) as eject_file: logging.debug("Eject CDROM by XML: %s", eject_file.read()) # Run command twice to make sure cdrom tray open first #BZ892289 # Open tray virsh.attach_device(domainarg=vm_name, filearg=eject_xml, debug=True) # Add time sleep between two attach commands. if time_sleep: time.sleep(float(time_sleep)) # Eject cdrom result = virsh.attach_device(domainarg=vm_name, filearg=eject_xml, debug=True) if result.exit_status != 0: test.fail("Eject CDROM failed") if vm_xml.VMXML.check_disk_exist(vm_name, device_source): test.fail("Find %s after do eject" % device_source) # Save and restore VM if save_vm: result = virsh.save(vm_name, save_file, debug=True) libvirt.check_exit_status(result) result = virsh.restore(save_file, debug=True) libvirt.check_exit_status(result) if vm_xml.VMXML.check_disk_exist(vm_name, device_source): test.fail("Find %s after do restore" % device_source) # Destroy VM. vm.destroy(gracefully=False) # Check disk count after VM shutdown (with --config). check_count_after_shutdown = True inactive_vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) disk_count_after_shutdown = len(inactive_vmxml.get_disk_all()) if test_cmd == "attach-disk": if disk_count_after_shutdown == disk_count_before_cmd: check_count_after_shutdown = False elif test_cmd == "detach-disk": if disk_count_after_shutdown < disk_count_before_cmd: check_count_after_shutdown = False finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) logging.debug("Restore the VM XML") backup_xml.sync() if os.path.exists(save_file): os.remove(save_file) if test_block_dev: if test_logcial_dev: libvirt.delete_local_disk("lvm", vgname=vg_name, lvname=lv_name) if test_systemlink_twice: for lv_item_name in additional_lv_names: libvirt.delete_local_disk("lvm", vgname=vg_name, lvname=lv_item_name) lv_utils.vg_remove(vg_name) process.run("pvremove %s" % device_source, shell=True, ignore_status=True) libvirt.setup_or_cleanup_iscsi(False) else: libvirt.delete_local_disk("file", device_source) # Check results. if status_error: if not status: test.fail("virsh %s exit with unexpected value." % test_cmd) else: if test_systemlink_twice: return if status: test.fail("virsh %s failed." % test_cmd) if test_cmd == "attach-disk": if at_options.count("config"): if not check_count_after_shutdown: test.fail("Cannot see config attached device " "in xml file after VM shutdown.") if not check_disk_serial: test.fail("Serial set failed after attach") if not check_disk_address: test.fail("Address set failed after attach") if not check_disk_address2: test.fail("Address(multifunction) set failed" " after attach") else: if not check_count_after_cmd: test.fail("Cannot see device in xml file" " after attach.") if not check_vm_after_cmd: test.fail("Cannot see device in VM after" " attach.") if not check_disk_type: test.fail("Check disk type failed after" " attach.") if not check_audit_after_cmd: test.fail("Audit hotplug failure after attach") if not check_cache_after_cmd: test.fail("Check cache failure after attach") if at_options.count("persistent"): if not check_count_after_shutdown: test.fail("Cannot see device attached " "with persistent after " "VM shutdown.") else: if check_count_after_shutdown: test.fail("See non-config attached device " "in xml file after VM shutdown.") elif test_cmd == "detach-disk": if dt_options.count("config"): if check_count_after_shutdown: test.fail("See config detached device in " "xml file after VM shutdown.") else: if check_count_after_cmd: test.fail("See device in xml file " "after detach.") if check_vm_after_cmd: test.fail("See device in VM after detach.") if not check_audit_after_cmd: test.fail("Audit hotunplug failure " "after detach") if dt_options.count("persistent"): if check_count_after_shutdown: test.fail("See device deattached " "with persistent after " "VM shutdown.") else: if not check_count_after_shutdown: test.fail("See non-config detached " "device in xml file after " "VM shutdown.") else: test.error("Unknown command %s." % test_cmd)
def run(test, params, env): """ Test SCSI3 Persistent Reservation functions. 1.Prepare iscsi backend storage. 2.Prepare disk xml. 3.Hot/cold plug the disk to vm. 4.Check if SCSI3 Persistent Reservation commands can be issued to that disk. 5.Recover test environment. 6.Confirm the test result. """ def get_delta_parts(vm, old_parts): """ Get the newly added partitions/blockdevs in vm. :param vm: The vm to be operated. :param old_parts: The original partitions/blockdevs in vm. :return: Newly added partitions/blockdevs. """ session = vm.wait_for_login() new_parts = utils_disk.get_parts_list(session) new_parts = list(set(new_parts).difference(set(old_parts))) session.close() return new_parts def check_pr_cmds(vm, blk_dev): """ Check if SCSI3 Persistent Reservation commands can be used in vm. :param vm: The vm to be checked. :param blk_dev: The block device in vm to be checked. """ session = vm.wait_for_login() cmd = ( "sg_persist --no-inquiry -v --out --register-ignore --param-sark 123aaa /dev/{0} &&" "sg_persist --no-inquiry --in -k /dev/{0} &&" "sg_persist --no-inquiry -v --out --reserve --param-rk 123aaa --prout-type 5 /dev/{0} &&" "sg_persist --no-inquiry --in -r /dev/{0} &&" "sg_persist --no-inquiry -v --out --release --param-rk 123aaa --prout-type 5 /dev/{0} &&" "sg_persist --no-inquiry --in -r /dev/{0} &&" "sg_persist --no-inquiry -v --out --register --param-rk 123aaa --prout-type 5 /dev/{0} &&" "sg_persist --no-inquiry --in -k /dev/{0}".format(blk_dev)) cmd_status, cmd_output = session.cmd_status_output(cmd) session.close() if cmd_status == 127: test.error("sg3_utils not installed in test image") elif cmd_status != 0: test.fail("persistent reservation failed for /dev/%s" % blk_dev) else: logging.info("persistent reservation successful for /dev/%s" % blk_dev) def start_or_stop_qemu_pr_helper( is_start=True, path_to_sock="/var/run/qemu-pr-helper.sock"): """ Start or stop qemu-pr-helper daemon :param is_start: Set True to start, False to stop. """ service_mgr = service.ServiceManager() if is_start: service_mgr.start('qemu-pr-helper') time.sleep(2) shutil.chown(path_to_sock, "qemu", "qemu") else: service_mgr.stop('qemu-pr-helper') def ppc_controller_update(): """ Update controller of ppc vm to 'virtio-scsi' to support 'scsi' type :return: """ if params.get('machine_type') == 'pseries' and device_bus == 'scsi': if not vmxml.get_controllers(device_bus, 'virtio-scsi'): vmxml.del_controller(device_bus) ppc_controller = Controller('controller') ppc_controller.type = device_bus ppc_controller.index = '0' ppc_controller.model = 'virtio-scsi' vmxml.add_device(ppc_controller) vmxml.sync() # Check if SCSI3 Persistent Reservations supported by # current libvirt versions. if not libvirt_version.version_compare(4, 4, 0): test.cancel("The <reservations> tag supported by libvirt from version " "4.4.0") vm_name = params.get("main_vm") vm = env.get_vm(vm_name) virsh_dargs = {'debug': True, 'ignore_status': True} # Disk specific attributes device = params.get("virt_disk_device", "lun") device_target = params.get("virt_disk_device_target", "sdb") device_format = params.get("virt_disk_device_format", "raw") device_type = params.get("virt_disk_device_type", "block") device_bus = params.get("virt_disk_device_bus", "scsi") # Iscsi options iscsi_host = params.get("iscsi_host") iscsi_port = params.get("iscsi_port") emulated_size = params.get("iscsi_image_size", "1G") auth_uuid = "yes" == params.get("auth_uuid") auth_usage = "yes" == params.get("auth_usage") # SCSI3 PR options reservations_managed = "yes" == params.get("reservations_managed", "yes") reservations_source_type = params.get("reservations_source_type", "unix") reservations_source_path = params.get("reservations_source_path", "/var/run/qemu-pr-helper.sock") reservations_source_mode = params.get("reservations_source_mode", "client") secret_uuid = "" # Case step options hotplug_disk = "yes" == params.get("hotplug_disk", "no") # Start vm and get all partitions in vm if vm.is_dead(): vm.start() session = vm.wait_for_login() old_parts = utils_disk.get_parts_list(session) session.close() vm.destroy(gracefully=False) # Back up xml file vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) try: chap_user = "" chap_passwd = "" if auth_uuid or auth_usage: auth_in_source = "yes" == params.get("auth_in_source", "no") if auth_in_source and not libvirt_version.version_compare(3, 9, 0): test.cancel("place auth in source is not supported in " "current libvirt version.") auth_type = params.get("auth_type", "chap") secret_usage_target = params.get("secret_usage_target", "libvirtiscsi") secret_usage_type = params.get("secret_usage_type", "iscsi") chap_user = params.get("iscsi_user", "redhat") chap_passwd = params.get("iscsi_password", "redhat") sec_xml = secret_xml.SecretXML("no", "yes") sec_xml.description = "iSCSI secret" sec_xml.auth_type = auth_type sec_xml.auth_username = chap_user sec_xml.usage = secret_usage_type sec_xml.target = secret_usage_target sec_xml.xmltreefile.write() ret = virsh.secret_define(sec_xml.xml) libvirt.check_exit_status(ret) secret_uuid = re.findall(r".+\S+(\ +\S+)\ +.+\S+", ret.stdout.strip())[0].lstrip() logging.debug("Secret uuid %s", secret_uuid) if secret_uuid == "": test.error("Failed to get secret uuid") # Set secret value encoding = locale.getpreferredencoding() secret_string = base64.b64encode( str(chap_passwd).encode(encoding)).decode(encoding) ret = virsh.secret_set_value(secret_uuid, secret_string, **virsh_dargs) libvirt.check_exit_status(ret) # Setup iscsi target blk_dev = libvirt.setup_or_cleanup_iscsi(is_setup=True, is_login=True, image_size=emulated_size, chap_user=chap_user, chap_passwd=chap_passwd, portal_ip=iscsi_host) # Add disk xml vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) disk_xml = Disk(type_name=device_type) disk_xml.device = device disk_xml.target = {"dev": device_target, "bus": device_bus} driver_dict = {"name": "qemu", "type": device_format} disk_xml.driver = driver_dict auth_dict = {} if auth_uuid: auth_dict = { "auth_user": chap_user, "secret_type": secret_usage_type, "secret_uuid": secret_uuid } elif auth_usage: auth_dict = { "auth_user": chap_user, "secret_type": secret_usage_type, "secret_usage": secret_usage_target } disk_source = disk_xml.new_disk_source(**{"attrs": {"dev": blk_dev}}) if auth_dict: disk_auth = disk_xml.new_auth(**auth_dict) if auth_in_source: disk_source.auth = disk_auth else: disk_xml.auth = disk_auth if reservations_managed: reservations_dict = {"reservations_managed": "yes"} else: start_or_stop_qemu_pr_helper(path_to_sock=reservations_source_path) reservations_dict = { "reservations_managed": "no", "reservations_source_type": reservations_source_type, "reservations_source_path": reservations_source_path, "reservations_source_mode": reservations_source_mode } disk_source.reservations = disk_xml.new_reservations( **reservations_dict) disk_xml.source = disk_source # Update controller of ppc vms ppc_controller_update() if not hotplug_disk: vmxml.add_device(disk_xml) try: # Start the VM and check status vmxml.sync() vm.start() vm.wait_for_login().close() time.sleep(5) if hotplug_disk: result = virsh.attach_device(vm_name, disk_xml.xml, ignore_status=True, debug=True) libvirt.check_exit_status(result) new_parts = get_delta_parts(vm, old_parts) if len(new_parts) != 1: logging.error("Expected 1 dev added but has %s" % len(new_parts)) new_part = new_parts[0] check_pr_cmds(vm, new_part) result = virsh.detach_device(vm_name, disk_xml.xml, ignore_status=True, debug=True, wait_for_event=True) libvirt.check_exit_status(result) except virt_vm.VMStartError as e: test.fail("VM failed to start." "Error: %s" % str(e)) except xcepts.LibvirtXMLError as xml_error: test.fail("Failed to define VM:\n%s" % xml_error) finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) vmxml_backup.sync("--snapshots-metadata") # Delete the tmp files. libvirt.setup_or_cleanup_iscsi(is_setup=False) # Clean up secret if secret_uuid: virsh.secret_undefine(secret_uuid) # Stop qemu-pr-helper daemon start_or_stop_qemu_pr_helper(is_start=False)
def run(test, params, env): """ Test scenarios: virsh blockcommit with relative path 1) Prepare test environment. 2) Create relative path backing chain 3) Do virsh blockcommit 4) Check result. 5) Recover the environments """ def check_chain_backing_files(disk_src_file, expect_backing_list): """ Check backing chain files of relative path after blockcommit. :param disk_src_file: first disk src file. :param expect_backing_list: backing chain lists. """ # Validate source image doesn't have backing files after active blockcommit qemu_img_info_backing_chain = libvirt_disk.get_chain_backing_files( disk_src_file) logging.debug("The actual qemu-img qemu_img_info_backing_chain:%s\n", qemu_img_info_backing_chain) logging.debug("The actual qemu-img expect_backing_list:%s\n", expect_backing_list) if qemu_img_info_backing_chain != expect_backing_list: test.fail( "The backing files by qemu-img is not identical in expected backing list" ) def check_top_image_in_xml(expected_top_image): """ check top image in src file :param expected_top_image: expect top image """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) disks = vmxml.devices.by_device_tag('disk') disk_xml = None for disk in disks: if disk.target['dev'] == disk_target: disk_xml = disk.xmltreefile break logging.debug("disk xml in top: %s\n", disk_xml) for attr in ['file', 'name', 'dev']: src_file = disk_xml.find('source').get(attr) if src_file: break if src_file not in expected_top_image: test.fail("Current top img %s is not the same with expected: %s" % (src_file, expected_top_image)) def check_blockcommit_with_bandwidth(chain_list): """ Check blockcommit with bandwidth param chain_list: list, expected backing chain list """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) disks = vmxml.devices.by_device_tag('disk') disk_xml = None for disk in disks: if disk.target['dev'] == disk_target: disk_xml = disk break logging.debug("disk xml in check_blockcommit_with_bandwidth: %s\n", disk_xml.xmltreefile) backingstore_list = disk_xml.get_backingstore_list() parse_source_file_list = [ elem.find('source').get('file') or elem.find('source').get('name') for elem in backingstore_list ] logging.debug("expected backing chain list is %s", chain_list) logging.debug("parse source list is %s", parse_source_file_list) # Check whether relative path has been kept for i in range(0, len(chain_list) - 1): if chain_list[i] not in parse_source_file_list[i]: test.fail( "The relative path parsed from disk xml is different with pre-expected ones" ) def check_file_not_exists(root_dir, file_name, reverse=False): """ Check whether file exists in certain folder :param root_dir: preset root directory :param file_name: input file name :param reverse: whether reverse the condition """ files_path = [ os.path.join(root_dir, f) for f in os.listdir(root_dir) if os.path.isfile(os.path.join(root_dir, f)) ] logging.debug("all files in folder: %s \n", files_path) if not files_path: test.fail("Failed to get snapshot files in preset folder") elif reverse: if file_name not in files_path: test.fail("snapshot file:%s can not be found" % file_name) else: if file_name in files_path: test.fail("snapshot file:%s can not be deleted" % file_name) def check_backing_chain_file_not_exists(disk_src_file, file_name, reverse=False): """ Check whether file exists in source file's backing chain :param disk_src_file: disk source with backing chain files :param file_name: input file name :param reverse: whether reverse this condition """ qemu_img_info_backing_chain = libvirt_disk.get_chain_backing_files( disk_src_file) if reverse: if file_name not in qemu_img_info_backing_chain: test.fail("%s can not be found in backing chain file" % file_name) else: if file_name in qemu_img_info_backing_chain: test.fail("%s should not be in backing chain file" % file_name) def fill_vm_with_contents(): """ Fill contents in VM """ logging.info("Filling VM contents...") try: session = vm.wait_for_login() status, output = session.cmd_status_output( "dd if=/dev/urandom of=/tmp/bigfile bs=1M count=200") logging.info("Fill contents in VM:\n%s", output) session.close() except Exception as e: logging.error(str(e)) def create_lvm_pool(): """ create lvm pool""" pvt.cleanup_pool(pool_name, pool_type, pool_target, emulated_image) pvt.pre_pool(**params) capacity = "5G" for i in range(1, 5): vol_name = 'vol%s' % i path = "%s/%s" % (pool_target, vol_name) virsh.vol_create_as(vol_name, pool_name, capacity, capacity, "qcow2", debug=True) cmd = "qemu-img create -f %s %s %s" % ("qcow2", path, capacity) process.run(cmd, ignore_status=False, shell=True) volume_path_list.append(path) capacity = "2G" def setup_iscsi_env(): """ Setup iscsi environment""" libvirt.setup_or_cleanup_iscsi(is_setup=False) emulated_size = params.get("image_size", "10G") iscsi_target, lun_num = libvirt.setup_or_cleanup_iscsi( is_setup=True, is_login=False, image_size=emulated_size, portal_ip="127.0.0.1") cmd = ("qemu-img create -f qcow2 iscsi://%s:%s/%s/%s %s" % ("127.0.0.1", "3260", iscsi_target, lun_num, emulated_size)) process.run(cmd, shell=True) blk_source_image_after_converted = "iscsi://%s:%s/%s/%s" % ( "127.0.0.1", "3260", iscsi_target, lun_num) # Convert the image from qcow2 to raw convert_disk_cmd = ( "qemu-img convert" " -O %s %s %s" % (disk_format, first_src_file, blk_source_image_after_converted)) process.run(convert_disk_cmd, ignore_status=False, shell=True) replace_disk_image, backing_chain_list = libvirt_disk.make_relative_path_backing_files( vm, pre_set_root_dir, blk_source_image_after_converted, disk_format) params.update({ 'disk_source_name': replace_disk_image, 'disk_type': 'file', 'disk_source_protocol': 'file' }) return replace_disk_image, blk_source_image_after_converted, backing_chain_list def setup_rbd_env(): """ Set up rbd environment""" params.update({ "virt_disk_device_target": disk_target, "ceph_image_file": first_src_file }) libvirt_ceph_utils.create_or_cleanup_ceph_backend_vm_disk( vm, params, is_setup=True) ceph_mon_ip = params.get("ceph_mon_ip", "EXAMPLE_MON_HOST") ceph_disk_name = params.get("ceph_disk_name", "EXAMPLE_SOURCE_NAME") blk_source_image_after_converted = ("rbd:%s:mon_host=%s" % (ceph_disk_name, ceph_mon_ip)) replace_disk_image, backing_chain_list = libvirt_disk.make_relative_path_backing_files( vm, pre_set_root_dir, blk_source_image_after_converted, disk_format) params.update({ 'disk_source_name': replace_disk_image, 'disk_type': 'file', 'disk_format': 'qcow2', 'disk_source_protocol': 'file' }) return replace_disk_image, blk_source_image_after_converted, backing_chain_list def setup_volume_pool_env(): """Setup volume pool environment""" params.update({"virt_disk_device_target": disk_target}) create_lvm_pool() blk_source_image_after_converted = ("%s" % volume_path_list[0]) # Convert the image from qcow2 to volume convert_disk_cmd = ( "qemu-img convert" " -O %s %s %s" % (disk_format, first_src_file, blk_source_image_after_converted)) process.run(convert_disk_cmd, ignore_status=False, shell=True) params.update({ 'disk_source_name': blk_source_image_after_converted, 'disk_type': 'block', 'disk_format': 'qcow2', 'disk_source_protocol': 'file' }) libvirt.set_vm_disk(vm, params, tmp_dir) vm.wait_for_login().close() vm.destroy(gracefully=False) replace_disk_image, backing_chain_list = libvirt_disk.make_syslink_path_backing_files( pre_set_root_dir, volume_path_list, disk_format) params.update({ 'disk_source_name': replace_disk_image, 'disk_type': 'file', 'disk_format': 'qcow2', 'disk_source_protocol': 'file' }) blk_source_image_after_converted = os.path.join( pre_set_root_dir, syslink_top_img) skip_first_one = True return replace_disk_image, blk_source_image_after_converted, skip_first_one, backing_chain_list def validate_blockcommit_after_libvirtd_restart(): """Validate blockcommit after libvirtd restart""" logging.debug("phase three blockcommit .....") counts = 1 phase_three_blockcommit_options = " --active" libvirt_disk.do_blockcommit_repeatedly( vm, 'vda', phase_three_blockcommit_options, counts) time.sleep(3) # Before restart libvirtd mirror_content_before_restart = libvirt_disk.get_mirror_part_in_xml( vm, disk_target) logging.debug(mirror_content_before_restart) utils_libvirtd.libvirtd_restart() # After restart libvirtd mirror_content_after_restart = libvirt_disk.get_mirror_part_in_xml( vm, disk_target) logging.debug(mirror_content_after_restart) # Check whether mirror content is identical with previous one if mirror_content_before_restart != mirror_content_after_restart: test.fail( "The mirror part content changed after libvirtd restarted") virsh.blockjob(vm_name, disk_target, '--abort', ignore_status=True) def prepare_case_scenarios(snap_del_disks, base_file): """ Prepare case scenarios :param snap_del_disks: snapshot list :param base_file: base file for snapshot """ index = len(snap_del_disks) - 1 option = "--top %s --base %s --delete --verbose --wait" scenarios = {} scenarios.update({ "middle-to-middle": { 'blkcomopt': option % (snap_del_disks[index - 1], snap_del_disks[index - 2]), 'top': snap_del_disks[index - 1], 'base': snap_del_disks[index - 2] } }) scenarios.update({ "middle-to-base": { 'blkcomopt': option % (snap_del_disks[index - 1], base_file), 'top': snap_del_disks[index - 1], 'base': base_file } }) scenarios.update({ "top-to-middle": { 'blkcomopt': option % (snap_del_disks[index], snap_del_disks[index - 2]) + " --active", 'top': snap_del_disks[index], 'base': snap_del_disks[index - 2] } }) scenarios.update({ "top-to-base": { 'blkcomopt': "--top %s --delete --verbose --wait --active --pivot" % (snap_del_disks[index]), "top": snap_del_disks[index], "base": snap_del_disks[index] } }) scenarios.update({ "abort-top-job": { 'blkcomopt': "--top %s --delete --verbose --wait --active --pivot --bandwidth 1" % (snap_del_disks[index]), "top": snap_del_disks[index], "base": snap_del_disks[index] } }) return scenarios def loop_case_in_scenarios(scenarios): """ Loop case scenarios :param scenarios: scenario list """ # loop each scenario for case, opt in list(scenarios.items()): logging.debug("Begin scenario: %s testing....................", case) reverse = False if vm.is_alive(): vm.destroy(gracefully=False) # Reset VM to initial state vmxml_backup.sync("--snapshots-metadata") vm.start() snap_del_disks = libvirt_disk.make_external_disk_snapshots( vm, disk_target, snapshot_prefix, snapshot_take) tmp_option = opt.get('blkcomopt') top_file = opt.get('top') base_file = opt.get('base') if 'abort' in case: fill_vm_with_contents() ignite_blockcommit_thread = threading.Thread( target=virsh.blockcommit, args=( vm_name, disk_target, tmp_option, ), kwargs={ 'ignore_status': True, 'debug': True }) ignite_blockcommit_thread.start() ignite_blockcommit_thread.join(2) virsh.blockjob(vm_name, disk_target, " --abort", ignore_status=False) reverse = True else: libvirt_disk.do_blockcommit_repeatedly(vm, 'vda', tmp_option, 1) # Need pivot to make effect if "--active" in tmp_option and "--pivot" not in tmp_option: virsh.blockjob(vm_name, disk_target, '--pivot', ignore_status=True) check_file_not_exists(pre_set_root_dir, top_file, reverse=reverse) if 'top' not in case: check_backing_chain_file_not_exists( snap_del_disks[len(snap_del_disks) - 1], top_file) libvirt_disk.cleanup_snapshots(vm, snap_del_disks) del snap_del_disks[:] vm_name = params.get("main_vm") vm = env.get_vm(vm_name) vm_state = params.get("vm_state", "running") virsh_dargs = {'debug': True} status_error = ("yes" == params.get("status_error", "no")) restart_libvirtd = ("yes" == params.get("restart_libvirtd", "no")) validate_delete_option = ("yes" == params.get("validate_delete_option", "no")) tmp_dir = data_dir.get_data_dir() top_inactive = ("yes" == params.get("top_inactive")) base_option = params.get("base_option", "none") bandwidth = params.get("blockcommit_bandwidth", "") disk_target = params.get("disk_target", "vda") disk_format = params.get("disk_format", "qcow2") disk_type = params.get("disk_type") disk_src_protocol = params.get("disk_source_protocol") pool_name = params.get("pool_name") pool_target = params.get("pool_target") pool_type = params.get("pool_type") emulated_image = params.get("emulated_image") syslink_top_img = params.get("syslink_top_img") snapshot_take = int(params.get("snapshot_take", "4")) snapshot_prefix = params.get("snapshot_prefix", "snapshot") first_src_file = libvirt_disk.get_first_disk_source(vm) blk_source_image = os.path.basename(first_src_file) pre_set_root_dir = os.path.dirname(first_src_file) snapshot_external_disks = [] skip_first_one = False snap_del_disks = [] volume_path_list = [] kkwargs = params.copy() pvt = libvirt.PoolVolumeTest(test, params) # A backup of original vm vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Abort the test if there are snapshots already exsiting_snaps = virsh.snapshot_list(vm_name) if len(exsiting_snaps) != 0: test.fail("There are snapshots created for %s already" % vm_name) try: if vm.is_alive(): vm.destroy(gracefully=False) if disk_src_protocol == 'iscsi': replace_disk_image, blk_source_image_after_converted, backing_chain_list = setup_iscsi_env( ) if disk_src_protocol == "rbd": replace_disk_image, blk_source_image_after_converted, backing_chain_list = setup_rbd_env( ) if disk_src_protocol == "pool": replace_disk_image, blk_source_image_after_converted, skip_first_one, backing_chain_list = setup_volume_pool_env( ) libvirt.set_vm_disk(vm, params, tmp_dir) # get a vm session before snapshot session = vm.wait_for_login() old_parts = utils_disk.get_parts_list(session) # Check backing files check_chain_backing_files(replace_disk_image, backing_chain_list) if vm_state == "paused": vm.pause() # Do phase one blockcommit phase_one_blockcommit_options = "--active --verbose --shallow --pivot --keep-relative" counts = len(backing_chain_list) if bandwidth and base_option == "base": phase_one_blockcommit_options = "--top vda[1] --base vda[3] --keep-relative --bandwidth %s --active" % bandwidth if restart_libvirtd: utils_libvirtd.libvirtd_restart() if base_option == "shallow": libvirt_disk.do_blockcommit_repeatedly( vm, 'vda', phase_one_blockcommit_options, counts) elif base_option == "base": counts = 1 libvirt_disk.do_blockcommit_repeatedly( vm, 'vda', phase_one_blockcommit_options, counts) check_blockcommit_with_bandwidth(backing_chain_list[::-1]) virsh.blockjob(vm_name, disk_target, '--abort', ignore_status=True) # Pivot commits to bottom one of backing chain phase_one_blockcommit_options = "--active --verbose --shallow --pivot --keep-relative" counts = len(backing_chain_list) libvirt_disk.do_blockcommit_repeatedly( vm, 'vda', phase_one_blockcommit_options, counts) #Check top image after phase one block commit check_top_image_in_xml(blk_source_image_after_converted) # Do snapshots _, snapshot_external_disks = libvirt_disk.create_reuse_external_snapshots( vm, pre_set_root_dir, skip_first_one, disk_target) # Set blockcommit_options phase_two_blockcommit_options = "--verbose --keep-relative --shallow --active --pivot" # Run phase two blockcommit with snapshots counts = len(snapshot_external_disks) - 1 libvirt_disk.do_blockcommit_repeatedly(vm, 'vda', phase_two_blockcommit_options, counts) #Check top image after phase two block commit check_top_image_in_xml(snapshot_external_disks) # Run dependent restart_libvirtd case if restart_libvirtd: validate_blockcommit_after_libvirtd_restart() # Run dependent validate_delete_option case if validate_delete_option: # Run blockcommit with snapshots to validate delete option # Test scenarios can be referred from https://bugzilla.redhat.com/show_bug.cgi?id=1008350 logging.debug("Blockcommit with delete option .....") base_file = first_src_file # Get first attempt snapshot lists if vm.is_alive(): vm.destroy(gracefully=False) # Reset VM to initial state vmxml_backup.sync("--snapshots-metadata") vm.start() snap_del_disks = libvirt_disk.make_external_disk_snapshots( vm, disk_target, snapshot_prefix, snapshot_take) scenarios = prepare_case_scenarios(snap_del_disks, base_file) libvirt_disk.cleanup_snapshots(vm, snap_del_disks) del snap_del_disks[:] loop_case_in_scenarios(scenarios) finally: if vm.is_alive(): vm.destroy(gracefully=False) # Recover xml of vm. vmxml_backup.sync("--snapshots-metadata") # Delete reuse external disk if exists for disk in snapshot_external_disks: if os.path.exists(disk): os.remove(disk) # Delete snapshot disk libvirt_disk.cleanup_snapshots(vm, snap_del_disks) # Clean up created folders for folder in [ chr(letter) for letter in range(ord('a'), ord('a') + 4) ]: rm_cmd = "rm -rf %s" % os.path.join(pre_set_root_dir, folder) process.run(rm_cmd, shell=True) # Remove ceph config file if created if disk_src_protocol == "rbd": libvirt_ceph_utils.create_or_cleanup_ceph_backend_vm_disk( vm, params, is_setup=False) elif disk_src_protocol == 'iscsi' or 'iscsi_target' in locals(): libvirt.setup_or_cleanup_iscsi(is_setup=False) elif disk_src_protocol == 'pool': pvt.cleanup_pool(pool_name, pool_type, pool_target, emulated_image) rm_cmd = "rm -rf %s" % pool_target process.run(rm_cmd, shell=True) # Recover images xattr if having some dirty_images = libvirt_disk.get_images_with_xattr(vm) if dirty_images: libvirt_disk.clean_images_with_xattr(dirty_images) test.error("VM's image(s) having xattr left")
def get_attached_disk(): session = vm.wait_for_login() new_parts = utils_disk.get_parts_list(session) session.close() added_parts = list(set(new_parts).difference(set(old_parts))) return added_parts
def run(test, params, env): """ Test for vhba hostdev passthrough. 1. create a vhba 2. prepare hostdev xml for lun device of the newly created vhba 3.1 If hot attach, attach-device the hostdev xml to vm 3.2 If cold attach, add the hostdev to vm and start it 4. login the vm and check the attached disk 5. detach-device the hostdev xml 6. login the vm to check the partitions """ def check_in_vm(vm, target, old_parts): """ Check mount/read/write disk in VM. :param vm: VM guest. :param target: Disk dev in VM. :return: True if check successfully. """ try: def get_attached_disk(): session = vm.wait_for_login() new_parts = utils_disk.get_parts_list(session) session.close() added_parts = list(set(new_parts).difference(set(old_parts))) return added_parts added_parts = utils_misc.wait_for(get_attached_disk, _TIMEOUT) logging.info("Added parts:%s", added_parts) if len(added_parts) != 1: logging.error("The number of new partitions is invalid in VM") return False added_part = None if target.startswith("vd"): if added_parts[0].startswith("vd"): added_part = added_parts[0] elif target.startswith("hd"): if added_parts[0].startswith("sd"): added_part = added_parts[0] if not added_part: logging.error("Can't see added partition in VM") return False cmd = ("fdisk -l /dev/{0} && mkfs.ext4 -F /dev/{0} && " "mkdir -p test && mount /dev/{0} test && echo" " teststring > test/testfile && umount test".format( added_part)) try: cmd_status, cmd_output = session.cmd_status_output(cmd) except Exception as detail: test.error("Error occurred when run cmd: fdisk, %s" % detail) logging.info("Check disk operation in VM:\n%s", cmd_output) session.close() if cmd_status != 0: return False return True except (remote.LoginError, virt_vm.VMError, aexpect.ShellError) as detail: logging.error(str(detail)) return False try: status_error = "yes" == params.get("status_error", "no") vm_name = params.get("main_vm", "avocado-vt-vm1") device_target = params.get("hostdev_disk_target", "hdb") scsi_wwnn = params.get("scsi_wwnn", "ENTER.YOUR.WWNN") scsi_wwpn = params.get("scsi_wwpn", "ENTER.YOUR.WWPN") attach_method = params.get('attach_method', 'hot') vm = env.get_vm(vm_name) vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) virsh_dargs = {'debug': True, 'ignore_status': True} new_vhbas = [] if scsi_wwnn.count("ENTER.YOUR.WWNN") or \ scsi_wwpn.count("ENTER.YOUR.WWPN"): test.cancel("You didn't provide proper wwpn/wwnn") # Load sg module if necessary process.run("modprobe sg", shell=True, ignore_status=True, verbose=True) if vm.is_dead(): vm.start() session = vm.wait_for_login() old_parts = utils_disk.get_parts_list(session) # find first online hba online_hbas = [] online_hbas = utils_npiv.find_hbas("hba") if not online_hbas: test.cancel("NO ONLINE HBAs!") first_online_hba = online_hbas[0] # create vhba based on the first online hba old_vhbas = utils_npiv.find_hbas("vhba") logging.debug("Original online vHBAs: %s", old_vhbas) new_vhba = utils_npiv.nodedev_create_from_xml({ "nodedev_parent": first_online_hba, "scsi_wwnn": scsi_wwnn, "scsi_wwpn": scsi_wwpn }) # enable multipath service process.run("mpathconf --enable", shell=True) if not utils_misc.wait_for( lambda: utils_npiv.is_vhbas_added(old_vhbas), timeout=_TIMEOUT): test.fail("vhba not successfully created") new_vhbas.append(new_vhba) # find first available lun of the newly created vhba lun_dicts = [] first_lun = {} if not utils_misc.wait_for(lambda: utils_npiv.find_scsi_luns(new_vhba), timeout=_TIMEOUT): test.fail("There is no available lun storage for " "wwpn: %s, please check your wwns or " "contact IT admins" % scsi_wwpn) lun_dicts = utils_npiv.find_scsi_luns(new_vhba) logging.debug("The luns discovered are: %s", lun_dicts) first_lun = lun_dicts[0] # prepare hostdev xml for the first lun kwargs = { 'addr_bus': first_lun['bus'], 'addr_target': first_lun['target'], 'addr_unit': first_lun['unit'] } new_hostdev_xml = utils_npiv.create_hostdev_xml( adapter_name="scsi_host" + first_lun['scsi'], **kwargs) logging.info("New hostdev xml as follow:") logging.info(new_hostdev_xml) new_hostdev_xml.xmltreefile.write() if attach_method == "hot": # attach-device the lun's hostdev xml to guest vm result = virsh.attach_device(vm_name, new_hostdev_xml.xml) libvirt.check_exit_status(result, status_error) elif attach_method == "cold": if vm.is_alive(): vm.destroy(gracefully=False) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) vmxml.devices = vmxml.devices.append(new_hostdev_xml) vmxml.sync() vm.start() session = vm.wait_for_login() logging.debug("The new vm's xml is: \n%s", vmxml) # login vm and check the disk check_result = check_in_vm(vm, device_target, old_parts) if not check_result: test.fail("check disk in vm failed") result = virsh.detach_device(vm_name, new_hostdev_xml.xml) libvirt.check_exit_status(result, status_error) # login vm and check disk actually removed if not vm.session: session = vm.wait_for_login() parts_after_detach = utils_disk.get_parts_list(session) old_parts.sort() parts_after_detach.sort() if parts_after_detach == old_parts: logging.info("hostdev successfully detached.") else: test.fail("Device not successfully detached. " "Still existing in vm's /proc/partitions") finally: utils_npiv.vhbas_cleanup(new_vhbas) # recover vm if vm.is_alive(): vm.destroy(gracefully=False) logging.info("Restoring vm...") vmxml_backup.sync() process.system('service multipathd restart', verbose=True)