def run_test_dimm(case): """ Multi-operation for dimm devices :param case: test case """ vm_attrs = eval(params.get('vm_attrs', '{}')) vmxml.setup_attrs(**vm_attrs) # Start a guest with 3 dimm device dimm_devices_attrs = [ eval(v) for k, v in params.items() if k.startswith('dimm_device_') ] for attrs in dimm_devices_attrs: dimm_device = Memory() dimm_device.setup_attrs(**attrs) logging.debug(dimm_device) vmxml.add_device(dimm_device) vmxml.sync() logging.debug(virsh.dumpxml(vm_name).stdout_text) vm.start() # Check qemu cmd line for amount of dimm device dimm_device_num = len(dimm_devices_attrs) qemu_cmd = 'pgrep -a qemu' qemu_cmd_output = process.run(qemu_cmd, verbose=True).stdout_text qemu_cmd_num = len(re.findall("-device.*?pc-dimm", qemu_cmd_output)) if qemu_cmd_num != dimm_device_num: test.fail('The amount of dimm device in qemu command line does not' ' match vmxml, expect %d, but get %d' % (dimm_device_num, qemu_cmd_num)) # Attach a mem device at_dimm_device_attrs = eval(params.get('at_dimm_device')) at_dim_device = Memory() at_dim_device.setup_attrs(**at_dimm_device_attrs) virsh.attach_device(vm_name, at_dim_device.xml, **VIRSH_ARGS) # Managedsave guest and restore virsh.managedsave(vm_name, **VIRSH_ARGS) virsh.start(vm_name, **VIRSH_ARGS) # Check qemu cmd line for attached dimm device new_qemu_cmd_output = process.run(qemu_cmd, verbose=True).stdout_text new_qemu_cmd_num = len( re.findall("-device.*?pc-dimm", new_qemu_cmd_output)) if new_qemu_cmd_num != dimm_device_num + 1: test.fail('The amount of dimm device in qemu command line does not' ' match vmxml, expect %d, but get %d' % (dimm_device_num + 1, new_qemu_cmd_num)) libvirt.check_qemu_cmd_line(qemu_check)
def run(test, params, env): """ Test vm features """ vm_name = params.get('main_vm') vm = env.get_vm(vm_name) hyperv_attr = eval(params.get('hyperv_attr', '{}')) pmu_attr = eval(params.get('pmu_attr', '{}')) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bkxml = vmxml.copy() try: # Set hyperv attribs if there're attribs to set if hyperv_attr: if set(hyperv_attr.keys()).intersection( ('tlbflush', 'frequencies', 'reenlightenment')): # Compare libvirt version to decide if test is valid if not libvirt_version.version_compare(5, 0, 0): test.cancel('This version of libvirt does\'nt support ' 'the setting: %r' % hyperv_attr) vm_xml.VMXML.set_vm_features( vm_name, **{ 'hyperv_%s_state' % key: value for key, value in hyperv_attr.items() }) if pmu_attr: vm_xml.VMXML.set_vm_features(vm_name, **{'pmu': pmu_attr['pmu']}) # Test vm start ret = virsh.start(vm_name, debug=True) libvirt.check_exit_status(ret) vm.wait_for_login().close() if hyperv_attr: # Check hyperv settings in qemu command line for attr in hyperv_attr: libvirt.check_qemu_cmd_line('hv_' + attr) if pmu_attr: libvirt.check_qemu_cmd_line('pmu=' + pmu_attr['pmu']) finally: bkxml.sync()
def run(test, params, env): """ Test vm features """ vm_name = params.get('main_vm') vm = env.get_vm(vm_name) hyperv_attr = eval(params.get('hyperv_attr', '{}')) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bkxml = vmxml.copy() try: # Set hyperv attribs if there're attribs to set if hyperv_attr: if set(hyperv_attr.keys()).intersection(('tlbflush', 'frequencies', 'reenlightenment')): # Compare libvirt version to decide if test is valid if not libvirt_version.version_compare(5, 0, 0): test.cancel('This version of libvirt does\'nt support ' 'the setting: %r' % hyperv_attr) vm_xml.VMXML.set_vm_features( vm_name, **{'hyperv_%s_state' % key: value for key, value in hyperv_attr.items()} ) # Test vm start ret = virsh.start(vm_name, debug=True) libvirt.check_exit_status(ret) vm.wait_for_login().close() # Check hyperv settings in qemu command line for attr in hyperv_attr: libvirt.check_qemu_cmd_line('hv_' + attr) finally: bkxml.sync()
def verify_test_mem_device(vm, params, test): """ Verify steps for memory device :param vm: VM object :param params: dict, test parameters :param test: test object """ verify_test_default(vm, params, test) remote_ip = params.get("remote_ip") remote_user = params.get("remote_user") remote_pwd = params.get("remote_pwd") # Create a remote runner for later use runner_on_target = remote.RemoteRunner(host=remote_ip, username=remote_user, password=remote_pwd) qemu_checks = params.get('qemu_checks', '').split('`') test.log.debug("qemu_checks:%s" % qemu_checks[0]) for qemu_check in qemu_checks: libvirt.check_qemu_cmd_line(qemu_check, False, params, runner_on_target)
def test_pmem_alignsize(vm, params, test): """ Test nvdimm with pmem and alignsize setting :param vm: vm object :param params: dict, test parameters :param test: test object :raises: test.fail if checkpoints fail """ error_msg = eval(params.get('error_msg')) libvirt.check_qemu_cmd_line(params.get('qemu_checks')) vm_session = vm.wait_for_login() # Create a file on the nvdimm device. output = vm_session.cmd_output('mkfs.xfs -f /dev/pmem0'.format()) if not re.search(error_msg[0], output): test.fail("The error '{}' should be in the output \n'{}'".format(error_msg[0], output)) output = vm_session.cmd_output('mount /dev/pmem0 /mnt') if not re.search(error_msg[1], output): test.fail("The error '{}' should be in the output \n'{}'".format(error_msg[1], output)) vm_session.close()
def run(test, params, env): """ Test hmat of memory """ vm_name = params.get('main_vm') qemu_checks = [] for i in range(1, 5): qemu_checks.extend(params.get('qemu_checks%d' % i, '').split('`')) def check_numainfo_in_guest(check_list, content): """ Check if numa information in guest is correct :param check_list: list of string under checking :param content: the whole output from the numactl cmd :raise: test.fail if numa info item is not in content """ content_str = ' '.join(content.split()) logging.debug("content_str:%s" % content_str) for item in check_list: item_str = ' '.join(item.split(' ')) if content_str.find(item_str) != -1: logging.info(item) else: test.fail('Item %s not in content %s' % (item_str, content)) def check_list_in_content(check_list, content): """ Check if items in check_list are in content :param check_list: list of string under checking :param content: the whole content which may includes the strings :raise: test.fail if the item in check_list is not in content """ for item in check_list: if item in content: logging.info("item: %s" % item) else: test.fail('Item %s not in content %s' % (item, content)) bkxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) chk_case = params.get('chk') try: vm = env.get_vm(vm_name) if not libvirt_version.version_compare(6, 6, 0): test.cancel("Current version doesn't support the function") vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Set cpu according to params libvirt_cpu.add_cpu_settings(vmxml, params) if chk_case == "hmat": libvirt_numa.create_hmat_xml(vmxml, params) if chk_case == "cell_distances": libvirt_numa.create_cell_distances_xml(vmxml, params) logging.debug(virsh.dumpxml(vm_name)) virsh.start(vm_name, debug=True, ignore_status=False) # Check qemu command line one by one for item in qemu_checks: libvirt.check_qemu_cmd_line(item) vm_session = vm.wait_for_login() if chk_case == "hmat": dmsg_list = [] for i in range(1, 5): dmsg_list.extend(params.get('dmsg_checks%d' % i, '').split('`')) content = vm_session.cmd('dmesg').strip() check_list_in_content(dmsg_list, content) if chk_case == "cell_distances": # Install numactl in guest if not utils_package.package_install('numactl', vm_session): test.fail("package {} installation fail".format('numactl')) check_list = [] for i in range(1, 4): check_list.extend(params.get('numactl_exp%d' % i, '').split('`')) numactl_output = vm_session.cmd('numactl -H').strip() check_numainfo_in_guest(check_list, numactl_output) finally: if vm.is_alive(): vm.destroy(gracefully=False) bkxml.sync()
def run(test, params, env): """ Test hpt resizing """ resizing = params.get('resizing') vm_name = params.get('main_vm') vm = env.get_vm(vm_name) status_error = 'yes' == params.get('status_error', 'no') error_msg = params.get('error_msg', '') hpt_order_path = params.get('hpt_order_path', '') qemu_check = params.get('qemu_check', '') def set_hpt(resizing, vmxml, sync=True): """ Set resizing value to vm xml """ features_xml = vm_xml.VMFeaturesXML() features_xml.hpt_resizing = resizing vmxml.features = features_xml if sync: vmxml.sync() def set_memory(vmxml): """ Set memory attributes in vm xml """ vmxml.max_mem_rt = int(params.get('max_mem_rt', 30670848)) vmxml.max_mem_rt_slots = int(params.get('max_mem_rt_slots', 16)) vmxml.max_mem_rt_unit = params.get('max_mem_rt_unit', 'KiB') cpu = vm_xml.VMCPUXML() cpu.xml = "<cpu><numa/></cpu>" numa_cell = eval(params.get('numa_cell')) logging.debug(numa_cell) vmxml.vcpu = max([int(cell['cpus'][-1]) for cell in numa_cell]) + 1 cpu.numa_cell = numa_cell vmxml.cpu = cpu vmxml.sync() def check_hpt_order(session, resizing=''): """ Return htp order in hpt_order file by default If 'resizing' is disabled, test updating htp_order """ if not hpt_order_path: test.cancel('No hpt order path provided.') hpt_order = session.cmd_output('cat %s' % hpt_order_path).strip() hpt_order = int(hpt_order) logging.info('Current hpt_order is %d', hpt_order) if resizing == 'disabled': cmd_result = session.cmd_status_output( 'echo %d > %s' % (hpt_order + 1, hpt_order_path)) result = process.CmdResult(stderr=cmd_result[1], exit_status=cmd_result[0]) libvirt.check_exit_status(result, True) libvirt.check_result(result, [error_msg]) return hpt_order bk_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) try: arch = platform.machine() new_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Test on ppc64le hosts if arch.lower() == 'ppc64le': set_hpt(resizing, new_xml) if resizing == 'enabled': set_memory(new_xml) # Start vm and check if start succeeds libvirt.check_exit_status(virsh.start(vm_name, debug=True)) libvirt.check_qemu_cmd_line(qemu_check) session = vm.wait_for_login() hpt_order = check_hpt_order(session, resizing) if resizing == 'enabled': mem_xml = utils_hotplug.create_mem_xml( tg_size=int(params.get('mem_size', 2048000)), tg_sizeunit=params.get('size_unit', 'KiB'), tg_node=int(params.get('mem_node', 0)), mem_model=params.get('mem_model', 'dimm')) logging.debug(mem_xml) # Attach memory device to the guest for 12 times # that will reach the maxinum memory limitation for i in range(12): virsh.attach_device(vm_name, mem_xml.xml, debug=True, ignore_status=False) xml_after_attach = vm_xml.VMXML.new_from_dumpxml(vm_name) logging.debug(xml_after_attach) # Check dumpxml of the guest, # check if each device has its alias for i in range(12): pattern = "alias\s+name=[\'\"]dimm%d[\'\"]" % i logging.debug('Searching for %s', pattern) if not re.search(pattern, str( xml_after_attach.xmltreefile)): test.fail('Missing memory alias: %s' % pattern) # Log in the guest and check dmesg dmesg = session.cmd('dmesg') logging.debug(dmesg) dmesg_content = params.get('dmesg_content', '').split('|') for order in range(1, 3): order += hpt_order for content in dmesg_content: if content % order not in dmesg: test.fail('Missing dmesg: %s' % (content % order)) # Test on non-ppc64le hosts else: set_hpt(resizing, new_xml, sync=False) result = virsh.define(new_xml.xml) libvirt.check_exit_status(result, status_error) libvirt.check_result(result, [error_msg]) finally: bk_xml.sync()
def run(test, params, env): """ Test vm features """ vm_name = params.get('main_vm') vm = env.get_vm(vm_name) hyperv_attr = eval(params.get('hyperv_attr', '{}')) pmu_attr = eval(params.get('pmu_attr', '{}')) pvspinlock_attr = eval(params.get('pvspinlock_attr', '{}')) kvm_poll_control_attr = eval(params.get('kvm_poll_control_attr', '{}')) hidden_attr = eval(params.get('hidden_attr', '{}')) qemu_include = params.get('qemu_include', '') qemu_exclude = params.get('qemu_exclude', '') cmd_in_guest = params.get('cmd_in_guest') pkgs = params.get('pkgs') vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bkxml = vmxml.copy() vm_session = None try: # Set hyperv attribs if there're attribs to set if hyperv_attr: if set(hyperv_attr.keys()).intersection(('tlbflush', 'frequencies', 'reenlightenment')): # Compare libvirt version to decide if test is valid if not libvirt_version.version_compare(5, 0, 0): test.cancel('This version of libvirt does\'nt support ' 'the setting: %r' % hyperv_attr) vm_xml.VMXML.set_vm_features( vm_name, **{'hyperv_%s_state' % key: value for key, value in hyperv_attr.items()} ) if kvm_poll_control_attr: if not libvirt_version.version_compare(6, 10, 0): test.cancel('This version of libvirt does not support' ' kvm poll-control') # Set feature attrs test_attrs = [pmu_attr, pvspinlock_attr, kvm_poll_control_attr, hidden_attr] [vm_xml.VMXML.set_vm_features(vm_name, **fea_attr) for fea_attr in test_attrs if fea_attr] # Test vm start try: ret = virsh.start(vm_name, debug=True) libvirt.check_exit_status(ret) except exceptions.TestFail as details: if re.search(r"host doesn\'t support paravirtual spinlocks", str(details)): test.cancel("This host doesn't support paravirtual spinlocks.") else: test.fail('VM failed to start:\n%s' % details) vm_session = vm.wait_for_login() install_pkgs(vm_session, pkgs, test) if hyperv_attr: # Check hyperv settings in qemu command line for attr in hyperv_attr: if libvirt_version.version_compare(5, 6, 0): exp_str = 'hv-' + attr else: exp_str = 'hv_' + attr if hyperv_attr[attr] == 'off': if libvirt.check_qemu_cmd_line(exp_str, True): test.fail("Unexpected '%s' was found in " "qemu command line" % exp_str) else: libvirt.check_qemu_cmd_line(exp_str) if pmu_attr: libvirt.check_qemu_cmd_line('pmu=' + pmu_attr['pmu']) if pvspinlock_attr: if distro.detect().name == 'rhel' and int(distro.detect().version) < 8: if pvspinlock_attr['pvspinlock_state'] == 'on': exp_str = r'\+kvm_pv_unhalt' else: exp_str = r'\-kvm_pv_unhalt' else: exp_str = 'kvm-pv-unhalt=' + pvspinlock_attr['pvspinlock_state'] libvirt.check_qemu_cmd_line(exp_str) if qemu_include: libvirt.check_qemu_cmd_line(qemu_include) if qemu_exclude: if libvirt.check_qemu_cmd_line(qemu_exclude, err_ignore=True): test.fail('Unexpected "%s" was found ' 'in qemu command line' % qemu_exclude) if cmd_in_guest: cmd_params = {'hidden_attr': hidden_attr} check_cmd_in_guest(cmd_in_guest, vm_session, cmd_params, test) finally: if vm_session: vm_session.close() bkxml.sync()
def run(test, params, env): """ Attach/Detach an iscsi network/volume disk to domain 1. For secret usage testing: 1.1. Setup an iscsi target with CHAP authentication. 1.2. Define a secret for iscsi target usage 1.3. Set secret value 2. Create 4. Create an iscsi network disk XML 5. Attach disk with the XML file and check the disk inside the VM 6. Detach the disk """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) disk_device = params.get("disk_device", "disk") disk_type = params.get("disk_type", "network") disk_src_protocol = params.get("disk_source_protocol", "iscsi") disk_src_host = params.get("disk_source_host", "127.0.0.1") disk_src_port = params.get("disk_source_port", "3260") disk_src_pool = params.get("disk_source_pool") disk_src_mode = params.get("disk_source_mode", "host") pool_type = params.get("pool_type", "iscsi") pool_src_host = params.get("pool_source_host", "127.0.0.1") pool_target = params.get("pool_target", "/dev/disk/by-path") disk_target = params.get("disk_target", "vdb") disk_target_bus = params.get("disk_target_bus", "virtio") disk_readonly = params.get("disk_readonly", "no") chap_auth = "yes" == params.get("chap_auth", "no") chap_user = params.get("chap_username", "") chap_passwd = params.get("chap_password", "") secret_usage_target = params.get("secret_usage_target") secret_ephemeral = params.get("secret_ephemeral", "no") secret_private = params.get("secret_private", "yes") status_error = "yes" == params.get("status_error", "no") vg_name = params.get("virt_disk_vg_name", "vg_test_0") lv_name = params.get("virt_disk_lv_name", "lv_test_0") driver_packed = params.get("driver_packed", "on") disk_packed = "yes" == params.get("disk_packed", "no") scsi_packed = "yes" == params.get("scsi_packed", "no") # Indicate the PPC platform on_ppc = False if platform.platform().count('ppc64'): on_ppc = True if disk_src_protocol == 'iscsi': if not libvirt_version.version_compare(1, 0, 4): test.cancel("'iscsi' disk doesn't support in" " current libvirt version.") if disk_type == "volume": if not libvirt_version.version_compare(1, 0, 5): test.cancel("'volume' type disk doesn't support in" " current libvirt version.") if pool_type == "iscsi-direct": if not libvirt_version.version_compare(4, 7, 0): test.cancel("iscsi-direct pool is not supported in" " current libvirt version.") if ((disk_packed or scsi_packed) and not libvirt_version.version_compare(6, 3, 0)): test.cancel("The virtio packed attribute is not supported in" " current libvirt version.") # Back VM XML vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Fix no more PCI slots issue in certain cases. vm_dump_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) machine_type = params.get("machine_type", "pc") if machine_type == 'q35': 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, 12)): q35_pcie_dict1.update({'controller_index': "%d" % i}) vm_dump_xml.add_device( libvirt.create_controller_xml(q35_pcie_dict1)) vm_dump_xml.sync() virsh_dargs = {'debug': True, 'ignore_status': True} try: start_vm = "yes" == params.get("start_vm", "yes") if start_vm: if vm.is_dead(): vm.start() vm.wait_for_login() else: if not vm.is_dead(): vm.destroy() if chap_auth: # Create a secret xml to define it secret_xml = SecretXML(secret_ephemeral, secret_private) secret_xml.auth_type = "chap" secret_xml.auth_username = chap_user secret_xml.usage = disk_src_protocol secret_xml.target = secret_usage_target with open(secret_xml.xml) as f: logging.debug("Define secret by XML: %s", f.read()) # Define secret cmd_result = virsh.secret_define(secret_xml.xml, **virsh_dargs) libvirt.check_exit_status(cmd_result) # Get secret uuid try: secret_uuid = cmd_result.stdout.strip().split()[1] except IndexError: test.error("Fail to get new created secret uuid") # Set secret value encoding = locale.getpreferredencoding() secret_string = base64.b64encode( chap_passwd.encode(encoding)).decode(encoding) cmd_result = virsh.secret_set_value(secret_uuid, secret_string, **virsh_dargs) libvirt.check_exit_status(cmd_result) else: # Set chap_user and chap_passwd to empty to avoid setup # CHAP authentication when export iscsi target chap_user = "" chap_passwd = "" # Setup iscsi target if disk_type == "block": iscsi_target = libvirt.setup_or_cleanup_iscsi( is_setup=True, is_login=True, image_size="1G", chap_user=chap_user, chap_passwd=chap_passwd, portal_ip=disk_src_host) else: iscsi_target, lun_num = libvirt.setup_or_cleanup_iscsi( is_setup=True, is_login=False, image_size='1G', chap_user=chap_user, chap_passwd=chap_passwd, portal_ip=disk_src_host) # Create iscsi pool if disk_type == "volume": # Create an iscsi pool xml to create it pool_src_xml = pool_xml.SourceXML() pool_src_xml.host_name = pool_src_host pool_src_xml.device_path = iscsi_target poolxml = pool_xml.PoolXML(pool_type=pool_type) poolxml.name = disk_src_pool poolxml.set_source(pool_src_xml) poolxml.target_path = pool_target if chap_auth: pool_src_xml.auth_type = "chap" pool_src_xml.auth_username = chap_user pool_src_xml.secret_usage = secret_usage_target poolxml.set_source(pool_src_xml) if pool_type == "iscsi-direct": iscsi_initiator = params.get('iscsi_initiator') pool_src_xml.iqn_name = iscsi_initiator poolxml.set_source(pool_src_xml) # Create iscsi/iscsi-direct pool cmd_result = virsh.pool_create(poolxml.xml, **virsh_dargs) libvirt.check_exit_status(cmd_result) xml = virsh.pool_dumpxml(disk_src_pool) logging.debug("Pool '%s' XML:\n%s", disk_src_pool, xml) def get_vol(): """Get the volume info""" # Refresh the pool cmd_result = virsh.pool_refresh(disk_src_pool) libvirt.check_exit_status(cmd_result) # Get volume name cmd_result = virsh.vol_list(disk_src_pool, **virsh_dargs) libvirt.check_exit_status(cmd_result) vol_list = [] vol_list = re.findall(r"(\S+)\ +(\S+)", str(cmd_result.stdout.strip())) if len(vol_list) > 1: return vol_list[1] else: return None # Wait for a while so that we can get the volume info vol_info = utils_misc.wait_for(get_vol, 10) if vol_info: vol_name, vol_path = vol_info else: test.error("Failed to get volume info") # Snapshot doesn't support raw disk format, create a qcow2 volume # disk for snapshot operation. if pool_type == "iscsi": process.run('qemu-img create -f qcow2 %s %s' % (vol_path, '100M'), shell=True, verbose=True) else: # Get iscsi URL to create a qcow2 volume disk disk_path = ("iscsi://[%s]/%s/%s" % (disk_src_host, iscsi_target, lun_num)) blk_source = "/mnt/test.qcow2" process.run('qemu-img create -f qcow2 %s %s' % (blk_source, '100M'), shell=True, verbose=True) process.run('qemu-img convert -O qcow2 %s %s' % (blk_source, disk_path), shell=True, verbose=True) # Create block device if disk_type == "block": logging.debug("iscsi dev name: %s", iscsi_target) lv_utils.vg_create(vg_name, iscsi_target) device_source = libvirt.create_local_disk("lvm", size="10M", vgname=vg_name, lvname=lv_name) logging.debug("New created volume: %s", lv_name) # Create iscsi network disk XML disk_params = { 'device_type': disk_device, 'type_name': disk_type, 'target_dev': disk_target, 'target_bus': disk_target_bus, 'readonly': disk_readonly } disk_params_src = {} if disk_type == "network": disk_params_src = { 'source_protocol': disk_src_protocol, 'source_name': iscsi_target + "/%s" % lun_num, 'source_host_name': disk_src_host, 'source_host_port': disk_src_port } elif disk_type == "volume": if pool_type == "iscsi": disk_params_src = { 'source_pool': disk_src_pool, 'source_volume': vol_name, 'driver_type': 'qcow2', 'source_mode': disk_src_mode } # iscsi-direct pool don't include source_mode option else: disk_params_src = { 'source_pool': disk_src_pool, 'source_volume': vol_name, 'driver_type': 'qcow2' } elif disk_type == "block": disk_params_src = { 'source_file': device_source, 'driver_type': 'raw' } # Start guest with packed attribute in disk if disk_packed: disk_params_src['driver_packed'] = driver_packed # Start guest with packed attribute in scsi controller if scsi_packed: scsi_controller = Controller("controller") scsi_controller.type = "scsi" scsi_controller.model = "virtio-scsi" scsi_controller.driver = {'packed': driver_packed} vm_dump_xml.add_device(scsi_controller) vm_dump_xml.sync() else: test.cancel("Unsupported disk type in this test") disk_params.update(disk_params_src) if chap_auth and disk_type != "volume": disk_params_auth = { 'auth_user': chap_user, 'secret_type': disk_src_protocol, 'secret_usage': secret_xml.target } disk_params.update(disk_params_auth) disk_xml = libvirt.create_disk_xml(disk_params) attach_option = params.get("attach_option", "") cmd_result = virsh.attach_device(domainarg=vm_name, filearg=disk_xml, flagstr=attach_option, dargs=virsh_dargs) libvirt.check_exit_status(cmd_result, status_error) if vm.is_dead(): cmd_result = virsh.start(vm_name, **virsh_dargs) libvirt.check_exit_status(cmd_result) # Wait for domain is stable vm.wait_for_login().close() domain_operation = params.get("domain_operation", "") if domain_operation == "save": save_file = os.path.join(data_dir.get_tmp_dir(), "vm.save") cmd_result = virsh.save(vm_name, save_file, **virsh_dargs) libvirt.check_exit_status(cmd_result) cmd_result = virsh.restore(save_file) libvirt.check_exit_status(cmd_result) if os.path.exists(save_file): os.remove(save_file) elif domain_operation == "snapshot": # Run snapshot related commands: snapshot-create-as, snapshot-list # snapshot-info, snapshot-dumpxml, snapshot-create # virsh snapshot-revert is not supported on combined internal and external snapshots # see more details from,https://bugzilla.redhat.com/show_bug.cgi?id=1733173 snapshot_name1 = "snap1" snapshot_name2 = "snap2" cmd_result = virsh.snapshot_create_as(vm_name, snapshot_name1, **virsh_dargs) libvirt.check_exit_status(cmd_result) try: virsh.snapshot_list(vm_name, **virsh_dargs) except process.CmdError: test.fail("Failed getting snapshots list for %s" % vm_name) try: virsh.snapshot_info(vm_name, snapshot_name1, **virsh_dargs) except process.CmdError: test.fail("Failed getting snapshots info for %s" % vm_name) cmd_result = virsh.snapshot_dumpxml(vm_name, snapshot_name1, **virsh_dargs) libvirt.check_exit_status(cmd_result) cmd_result = virsh.snapshot_create(vm_name, **virsh_dargs) libvirt.check_exit_status(cmd_result) cmd_result = virsh.snapshot_current(vm_name, **virsh_dargs) libvirt.check_exit_status(cmd_result) virsh.snapshot_create_as(vm_name, snapshot_name2, ignore_status=False, debug=True) cmd_result = virsh.snapshot_revert(vm_name, snapshot_name1, **virsh_dargs) cmd_result = virsh.snapshot_list(vm_name, **virsh_dargs) if snapshot_name2 not in cmd_result: test.error("Snapshot %s not found" % snapshot_name2) elif domain_operation == "start_with_packed": expect_xml_line = "packed=\"%s\"" % driver_packed libvirt.check_dumpxml(vm, expect_xml_line) expect_qemu_line = "packed=%s" % driver_packed libvirt.check_qemu_cmd_line(expect_qemu_line) elif domain_operation == "": logging.debug("No domain operation provided, so skip it") else: logging.error("Unsupported operation %s in this case, so skip it", domain_operation) def find_attach_disk(expect=True): """ Find attached disk inside the VM """ found_disk = False if vm.is_dead(): test.error("Domain %s is not running" % vm_name) else: try: session = vm.wait_for_login() # Here the script needs wait for a while for the guest to # recognize the hotplugged disk on PPC if on_ppc: time.sleep(10) cmd = "grep %s /proc/partitions" % disk_target s, o = session.cmd_status_output(cmd) logging.info("%s output: %s", cmd, o) session.close() if s == 0: found_disk = True except (LoginError, VMError, ShellError) as e: logging.error(str(e)) if found_disk == expect: logging.debug("Check disk inside the VM PASS as expected") else: test.error("Check disk inside the VM FAIL") # Check disk inside the VM, expect is False if status_error=True find_attach_disk(not status_error) # Detach disk cmd_result = virsh.detach_disk(vm_name, disk_target, wait_remove_event=True) libvirt.check_exit_status(cmd_result, status_error) # Check disk inside the VM find_attach_disk(False) finally: # Clean up snapshot # Shut down before cleaning up snapshots if vm.is_alive(): vm.destroy() libvirt.clean_up_snapshots(vm_name, domxml=vmxml_backup) # Restore vm vmxml_backup.sync("--snapshots-metadata") # Destroy pool and undefine secret, which may not exist try: if disk_type == "volume": virsh.pool_destroy(disk_src_pool) if disk_type == "block": clean_up_lvm(iscsi_target, vg_name, lv_name) if chap_auth: virsh.secret_undefine(secret_uuid) except Exception: pass libvirt.setup_or_cleanup_iscsi(is_setup=False)
def run(test, params, env): """ Test virsh migrate command. """ def set_feature(vmxml, feature, value): """ Set guest features for PPC :param state: the htm status :param vmxml: guest xml """ features_xml = vm_xml.VMFeaturesXML() if feature == 'hpt': features_xml.hpt_resizing = value elif feature == 'htm': features_xml.htm = value vmxml.features = features_xml vmxml.sync() def trigger_hpt_resize(session): """ Check the HPT order file and dmesg :param session: the session to guest :raise: test.fail if required message is not found """ hpt_order_path = "/sys/kernel/debug/powerpc/hpt_order" hpt_order = session.cmd_output('cat %s' % hpt_order_path).strip() hpt_order = int(hpt_order) logging.info('Current hpt_order is %d', hpt_order) hpt_order += 1 cmd = 'echo %d > %s' % (hpt_order, hpt_order_path) cmd_result = session.cmd_status_output(cmd) result = process.CmdResult(stderr=cmd_result[1], stdout=cmd_result[1], exit_status=cmd_result[0]) libvirt.check_exit_status(result) dmesg = session.cmd('dmesg') dmesg_content = params.get('dmesg_content').split('|') for content in dmesg_content: if content % hpt_order not in dmesg: test.fail("'%s' is missing in dmesg" % (content % hpt_order)) else: logging.info("'%s' is found in dmesg", content % hpt_order) def check_vm_network_accessed(session=None): """ The operations to the VM need to be done before or after migration happens :param session: The session object to the host :raise: test.error when ping fails """ # Confirm local/remote VM can be accessed through network. logging.info("Check VM network connectivity") s_ping, _ = utils_test.ping(vm.get_address(), count=10, timeout=20, output_func=logging.debug, session=session) if s_ping != 0: if session: session.close() test.fail("%s did not respond after %d sec." % (vm.name, 20)) def check_virsh_command_and_option(command, option=None): """ Check if virsh command exists :param command: the command to be checked :param option: the command option to be checked """ msg = "This version of libvirt does not support " if not virsh.has_help_command(command): test.cancel(msg + "virsh command '%s'" % command) if option and not virsh.has_command_help_match(command, option): test.cancel(msg + "virsh command '%s' with option '%s'" % (command, option)) def add_ctrls(vm_xml, dev_type="pci", dev_index="0", dev_model="pci-root"): """ Add multiple devices :param dev_type: the type of the device to be added :param dev_index: the maximum index of the device to be added :param dev_model: the model of the device to be added """ for inx in range(0, int(dev_index) + 1): newcontroller = Controller("controller") newcontroller.type = dev_type newcontroller.index = inx newcontroller.model = dev_model logging.debug("New device is added:\n%s", newcontroller) vm_xml.add_device(newcontroller) vm_xml.sync() def do_migration(vm, dest_uri, options, extra): """ Execute the migration with given parameters :param vm: the guest to be migrated :param dest_uri: the destination uri for migration :param options: options next to 'migrate' command :param extra: options in the end of the migrate command line :return: CmdResult object """ logging.info("Sleeping 10 seconds before migration") time.sleep(10) # Migrate the guest. virsh_args.update({"ignore_status": True}) migration_res = vm.migrate(dest_uri, options, extra, **virsh_args) if int(migration_res.exit_status) != 0: logging.error("Migration failed for %s.", vm_name) return migration_res if vm.is_alive(): # vm.connect_uri was updated logging.info("VM is alive on destination %s.", dest_uri) else: test.fail("VM is not alive on destination %s" % dest_uri) # Throws exception if console shows panic message vm.verify_kernel_crash() return migration_res def cleanup_libvirtd_log(log_file): """ Remove existing libvirtd log file on source and target host. :param log_file: log file with absolute path """ if os.path.exists(log_file): logging.debug("Delete local libvirt log file '%s'", log_file) os.remove(log_file) cmd = "rm -f %s" % log_file logging.debug("Delete remote libvirt log file '%s'", log_file) cmd_parms = { 'server_ip': server_ip, 'server_user': server_user, 'server_pwd': server_pwd } remote.run_remote_cmd(cmd, cmd_parms, runner_on_target) def cleanup_dest(vm): """ Clean up the destination host environment when doing the uni-direction migration. :param vm: the guest to be cleaned up """ logging.info("Cleaning up VMs on %s", vm.connect_uri) try: if virsh.domain_exists(vm.name, uri=vm.connect_uri): vm_state = vm.state() if vm_state == "paused": vm.resume() elif vm_state == "shut off": vm.start() vm.destroy(gracefully=False) if vm.is_persistent(): vm.undefine() except Exception as detail: logging.error("Cleaning up destination failed.\n%s", detail) def run_stress_in_vm(): """ The function to load stress in VM """ stress_args = params.get( "stress_args", "--cpu 8 --io 4 " "--vm 2 --vm-bytes 128M " "--timeout 20s") try: vm_session.cmd('stress %s' % stress_args) except Exception as detail: logging.debug(detail) def control_migrate_speed(to_speed=1): """ Control migration duration :param to_speed: the speed value in Mbps to be set for migration :return int: the new migration speed after setting """ virsh_args.update({"ignore_status": False}) old_speed = virsh.migrate_getspeed(vm_name, **virsh_args) logging.debug("Current migration speed is %s MiB/s\n", old_speed.stdout.strip()) logging.debug("Set migration speed to %d MiB/s\n", to_speed) cmd_result = virsh.migrate_setspeed(vm_name, to_speed, "", **virsh_args) actual_speed = virsh.migrate_getspeed(vm_name, **virsh_args) logging.debug("New migration speed is %s MiB/s\n", actual_speed.stdout.strip()) return int(actual_speed.stdout.strip()) def check_setspeed(params): """ Set/get migration speed :param params: the parameters used :raise: test.fail if speed set does not take effect """ expected_value = int(params.get("migrate_speed", '41943040')) // (1024 * 1024) actual_value = control_migrate_speed(to_speed=expected_value) params.update({'compare_to_value': actual_value}) if actual_value != expected_value: test.fail( "Migration speed is expected to be '%d MiB/s', but '%d MiB/s' " "found" % (expected_value, actual_value)) def check_domjobinfo(params, option=""): """ Check given item in domjobinfo of the guest is as expected :param params: the parameters used :param option: options for domjobinfo :raise: test.fail if the value of given item is unexpected """ def search_jobinfo(jobinfo): """ Find value of given item in domjobinfo :param jobinfo: cmdResult object :raise: test.fail if not found """ for item in jobinfo.stdout.splitlines(): if item.count(jobinfo_item): groups = re.findall(r'[0-9.]+', item.strip()) logging.debug("In '%s' search '%s'\n", item, groups[0]) if (math.fabs(float(groups[0]) - float(compare_to_value)) // float(compare_to_value) > diff_rate): test.fail("{} {} has too much difference from " "{}".format(jobinfo_item, groups[0], compare_to_value)) break jobinfo_item = params.get("jobinfo_item") compare_to_value = params.get("compare_to_value") logging.debug("compare_to_value:%s", compare_to_value) diff_rate = float(params.get("diff_rate", "0")) if not jobinfo_item or not compare_to_value: return vm_ref = '{}{}'.format(vm_name, option) jobinfo = virsh.domjobinfo(vm_ref, **virsh_args) search_jobinfo(jobinfo) check_domjobinfo_remote = params.get("check_domjobinfo_remote") if check_domjobinfo_remote: remote_virsh_session = virsh.VirshPersistent(**remote_virsh_dargs) jobinfo = remote_virsh_session.domjobinfo(vm_ref, **virsh_args) search_jobinfo(jobinfo) remote_virsh_session.close_session() def check_maxdowntime(params): """ Set/get migration maxdowntime :param params: the parameters used :raise: test.fail if maxdowntime set does not take effect """ expected_value = int( float(params.get("migrate_maxdowntime", '0.3')) * 1000) virsh_args.update({"ignore_status": False}) old_value = int(virsh.migrate_getmaxdowntime(vm_name).stdout.strip()) logging.debug("Current migration maxdowntime is %d ms", old_value) logging.debug("Set migration maxdowntime to %d ms", expected_value) virsh.migrate_setmaxdowntime(vm_name, expected_value, **virsh_args) actual_value = int( virsh.migrate_getmaxdowntime(vm_name).stdout.strip()) logging.debug("New migration maxdowntime is %d ms", actual_value) if actual_value != expected_value: test.fail( "Migration maxdowntime is expected to be '%d ms', but '%d ms' " "found" % (expected_value, actual_value)) params.update({'compare_to_value': actual_value}) def do_actions_during_migrate(params): """ The entry point to execute action list during migration :param params: the parameters used """ actions_during_migration = params.get("actions_during_migration") if not actions_during_migration: return for action in actions_during_migration.split(","): if action == 'setspeed': check_setspeed(params) elif action == 'domjobinfo': check_domjobinfo(params) elif action == 'setmaxdowntime': check_maxdowntime(params) time.sleep(3) def attach_channel_xml(): """ Create channel xml and attach it to guest configuration """ # Check if pty channel exists already for elem in new_xml.devices.by_device_tag('channel'): if elem.type_name == channel_type_name: logging.debug( "{0} channel already exists in guest. " "No need to add new one".format(channel_type_name)) return params = { 'channel_type_name': channel_type_name, 'target_type': target_type, 'target_name': target_name } channel_xml = libvirt.create_channel_xml(params) virsh.attach_device(domain_opt=vm_name, file_opt=channel_xml.xml, flagstr="--config", ignore_status=False) logging.debug("New VMXML with channel:\n%s", virsh.dumpxml(vm_name)) def check_timeout_postcopy(params): """ Check the vm state on target host after timeout when --postcopy and --timeout-postcopy are used. The vm state is expected as running. :param params: the parameters used """ timeout = int(params.get("timeout_postcopy", 10)) time.sleep(timeout + 1) remote_virsh_session = virsh.VirshPersistent(**remote_virsh_dargs) vm_state = results_stdout_52lts( remote_virsh_session.domstate(vm_name)).strip() if vm_state != "running": remote_virsh_session.close_session() test.fail( "After timeout '%s' seconds, " "the vm state on target host should " "be 'running', but '%s' found", timeout, vm_state) remote_virsh_session.close_session() def get_usable_compress_cache(pagesize): """ Get a number which is bigger than pagesize and is power of two. :param pagesize: the given integer :return: an integer satisfying the criteria """ def calculate(num): result = num & (num - 1) return (result == 0) item = pagesize found = False while (not found): item += 1 found = calculate(item) logging.debug( "%d is smallest one that is bigger than '%s' and " "is power of 2", item, pagesize) return item def check_migration_res(result): """ Check if the migration result is as expected :param result: the output of migration :raise: test.fail if test is failed """ logging.info("Migration out: %s", results_stdout_52lts(result).strip()) logging.info("Migration error: %s", results_stderr_52lts(result).strip()) if status_error: # Migration should fail if err_msg: # Special error messages are expected if not re.search(err_msg, results_stderr_52lts(result).strip()): test.fail("Can not find the expected patterns '%s' in " "output '%s'" % (err_msg, results_stderr_52lts(result).strip())) else: logging.debug("It is the expected error message") else: if int(result.exit_status) != 0: logging.debug("Migration failure is expected result") else: test.fail("Migration success is unexpected result") else: if int(result.exit_status) != 0: test.fail(results_stderr_52lts(result).strip()) check_parameters(test, params) # Params for NFS shared storage shared_storage = params.get("migrate_shared_storage", "") if shared_storage == "": default_guest_asset = defaults.get_default_guest_os_info()['asset'] default_guest_asset = "%s.qcow2" % default_guest_asset shared_storage = os.path.join(params.get("nfs_mount_dir"), default_guest_asset) logging.debug("shared_storage:%s", shared_storage) # params for migration connection params["virsh_migrate_desturi"] = libvirt_vm.complete_uri( params.get("migrate_dest_host")) # Params to update disk using shared storage params["disk_type"] = "file" params["disk_source_protocol"] = "netfs" params["mnt_path_name"] = params.get("nfs_mount_dir") # Local variables virsh_args = {"debug": True} virsh_opt = params.get("virsh_opt", "") server_ip = params.get("server_ip") server_user = params.get("server_user", "root") server_pwd = params.get("server_pwd") extra = params.get("virsh_migrate_extra") options = params.get("virsh_migrate_options") src_uri = params.get("virsh_migrate_connect_uri") dest_uri = params.get("virsh_migrate_desturi") log_file = params.get("libvirt_log", "/var/log/libvirt/libvirtd.log") check_complete_job = "yes" == params.get("check_complete_job", "no") config_libvirtd = "yes" == params.get("config_libvirtd", "no") contrl_index = params.get("new_contrl_index", None) asynch_migration = "yes" == params.get("asynch_migrate", "no") grep_str_remote_log = params.get("grep_str_remote_log", "") grep_str_local_log = params.get("grep_str_local_log", "") disable_verify_peer = "yes" == params.get("disable_verify_peer", "no") status_error = "yes" == params.get("status_error", "no") stress_in_vm = "yes" == params.get("stress_in_vm", "no") low_speed = params.get("low_speed", None) remote_virsh_dargs = { 'remote_ip': server_ip, 'remote_user': server_user, 'remote_pwd': server_pwd, 'unprivileged_user': None, 'ssh_remote_auth': True } hpt_resize = params.get("hpt_resize", None) htm_state = params.get("htm_state", None) # For pty channel test add_channel = "yes" == params.get("add_channel", "no") channel_type_name = params.get("channel_type_name", None) target_type = params.get("target_type", None) target_name = params.get("target_name", None) cmd_run_in_remote_guest = params.get("cmd_run_in_remote_guest", None) cmd_run_in_remote_guest_1 = params.get("cmd_run_in_remote_guest_1", None) cmd_run_in_remote_host = params.get("cmd_run_in_remote_host", None) cmd_run_in_remote_host_1 = params.get("cmd_run_in_remote_host_1", None) cmd_run_in_remote_host_2 = params.get("cmd_run_in_remote_host_2", None) # For qemu command line checking qemu_check = params.get("qemu_check", None) xml_check_after_mig = params.get("guest_xml_check_after_mig", None) # params for cache matrix test cache = params.get("cache") remove_cache = "yes" == params.get("remove_cache", "no") err_msg = params.get("err_msg") arch = platform.machine() if any([hpt_resize, contrl_index, htm_state]) and 'ppc64' not in arch: test.cancel("The case is PPC only.") # For TLS tls_recovery = params.get("tls_auto_recovery", "yes") # qemu config qemu_conf_dict = None # libvirtd config libvirtd_conf_dict = None remote_virsh_session = None vm = None vm_session = None libvirtd_conf = None qemu_conf = None mig_result = None test_exception = None is_TestError = False is_TestFail = False is_TestSkip = False # Objects to be cleaned up in the end objs_list = [] tls_obj = None # Local variables vm_name = params.get("migrate_main_vm") vm = env.get_vm(vm_name) vm.verify_alive() # For safety reasons, we'd better back up xmlfile. new_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) orig_config_xml = new_xml.copy() if not orig_config_xml: test.error("Backing up xmlfile failed.") try: # Create a remote runner for later use runner_on_target = remote.RemoteRunner(host=server_ip, username=server_user, password=server_pwd) # Change the configuration files if needed before starting guest # For qemu.conf if extra.count("--tls"): # Setup TLS tls_obj = TLSConnection(params) if tls_recovery == "yes": objs_list.append(tls_obj) tls_obj.auto_recover = True tls_obj.conn_setup() if not disable_verify_peer: qemu_conf_dict = {"migrate_tls_x509_verify": "1"} # Setup qemu configure logging.debug("Configure the qemu") cleanup_libvirtd_log(log_file) qemu_conf = libvirt.customize_libvirt_config( qemu_conf_dict, config_type="qemu", remote_host=True, extra_params=params) # Setup libvirtd if config_libvirtd: logging.debug("Configure the libvirtd") cleanup_libvirtd_log(log_file) libvirtd_conf_dict = setup_libvirtd_conf_dict(params) libvirtd_conf = libvirt.customize_libvirt_config( libvirtd_conf_dict, remote_host=True, extra_params=params) # Prepare required guest xml before starting guest if contrl_index: new_xml.remove_all_device_by_type('controller') logging.debug("After removing controllers, current XML:\n%s\n", new_xml) add_ctrls(new_xml, dev_index=contrl_index) if add_channel: attach_channel_xml() if hpt_resize: set_feature(new_xml, 'hpt', hpt_resize) if htm_state: set_feature(new_xml, 'htm', htm_state) if cache: params["driver_cache"] = cache if remove_cache: params["enable_cache"] = "no" # Change the disk of the vm to shared disk and then start VM libvirt.set_vm_disk(vm, params) if not vm.is_alive(): vm.start() logging.debug("Guest xml after starting:\n%s", vm_xml.VMXML.new_from_dumpxml(vm_name)) # Check qemu command line after guest is started if qemu_check: check_content = qemu_check if hpt_resize: check_content = "%s%s" % (qemu_check, hpt_resize) if htm_state: check_content = "%s%s" % (qemu_check, htm_state) libvirt.check_qemu_cmd_line(check_content) # Check local guest network connection before migration vm_session = vm.wait_for_login() check_vm_network_accessed() # Preparation for the running guest before migration if hpt_resize and hpt_resize != 'disabled': trigger_hpt_resize(vm_session) if low_speed: control_migrate_speed(int(low_speed)) if stress_in_vm: pkg_name = 'stress' logging.debug("Check if stress tool is installed") pkg_mgr = utils_package.package_manager(vm_session, pkg_name) if not pkg_mgr.is_installed(pkg_name): logging.debug("Stress tool will be installed") if not pkg_mgr.install(): test.error("Package '%s' installation fails" % pkg_name) stress_thread = threading.Thread(target=run_stress_in_vm, args=()) stress_thread.start() if extra.count("timeout-postcopy"): func_name = check_timeout_postcopy if params.get("actions_during_migration"): func_name = do_actions_during_migrate if extra.count("comp-xbzrle-cache"): cache = get_usable_compress_cache(memory.get_page_size()) extra = "%s %s" % (extra, cache) # For --postcopy enable postcopy_options = params.get("postcopy_options") if postcopy_options: extra = "%s %s" % (extra, postcopy_options) # Execute migration process if not asynch_migration: mig_result = do_migration(vm, dest_uri, options, extra) else: migration_test = libvirt.MigrationTest() logging.debug("vm.connect_uri=%s", vm.connect_uri) vms = [vm] try: migration_test.do_migration(vms, None, dest_uri, 'orderly', options, thread_timeout=900, ignore_status=True, virsh_opt=virsh_opt, func=func_name, extra_opts=extra, func_params=params) mig_result = migration_test.ret except exceptions.TestFail as fail_detail: test.fail(fail_detail) except exceptions.TestSkipError as skip_detail: test.cancel(skip_detail) except exceptions.TestError as error_detail: test.error(error_detail) except Exception as details: mig_result = migration_test.ret logging.error(details) check_migration_res(mig_result) if add_channel: # Get the channel device source path of remote guest if not remote_virsh_session: remote_virsh_session = virsh.VirshPersistent( **remote_virsh_dargs) file_path = tempfile.mktemp(dir=data_dir.get_tmp_dir()) remote_virsh_session.dumpxml(vm_name, to_file=file_path, debug=True, ignore_status=True) local_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) local_vmxml.xmltreefile = xml_utils.XMLTreeFile(file_path) for elem in local_vmxml.devices.by_device_tag('channel'): logging.debug("Found channel device {}".format(elem)) if elem.type_name == channel_type_name: host_source = elem.source.get('path') logging.debug( "Remote guest uses {} for channel device".format( host_source)) break remote_virsh_session.close_session() if not host_source: test.fail("Can not find source for %s channel on remote host" % channel_type_name) # Prepare to wait for message on remote host from the channel cmd_parms = { 'server_ip': server_ip, 'server_user': server_user, 'server_pwd': server_pwd } cmd_result = remote.run_remote_cmd( cmd_run_in_remote_host % host_source, cmd_parms, runner_on_target) # Send message from remote guest to the channel file remote_vm_obj = utils_test.RemoteVMManager(cmd_parms) vm_ip = vm.get_address() vm_pwd = params.get("password") remote_vm_obj.setup_ssh_auth(vm_ip, vm_pwd) cmd_result = remote_vm_obj.run_command(vm_ip, cmd_run_in_remote_guest_1) remote_vm_obj.run_command( vm_ip, cmd_run_in_remote_guest % results_stdout_52lts(cmd_result).strip()) logging.debug("Sending message is done") # Check message on remote host from the channel remote.run_remote_cmd(cmd_run_in_remote_host_1, cmd_parms, runner_on_target) logging.debug("Receiving message is done") remote.run_remote_cmd(cmd_run_in_remote_host_2, cmd_parms, runner_on_target) if check_complete_job: opts = " --completed" check_virsh_command_and_option("domjobinfo", opts) if extra.count("comp-xbzrle-cache"): params.update({'compare_to_value': cache // 1024}) check_domjobinfo(params, option=opts) if grep_str_local_log: cmd = "grep -E '%s' %s" % (grep_str_local_log, log_file) cmdRes = process.run(cmd, shell=True, ignore_status=True) if cmdRes.exit_status: test.fail(results_stderr_52lts(cmdRes).strip()) if grep_str_remote_log: cmd = "grep -E '%s' %s" % (grep_str_remote_log, log_file) cmd_parms = { 'server_ip': server_ip, 'server_user': server_user, 'server_pwd': server_pwd } remote.run_remote_cmd(cmd, cmd_parms, runner_on_target) if xml_check_after_mig: if not remote_virsh_session: remote_virsh_session = virsh.VirshPersistent( **remote_virsh_dargs) target_guest_dumpxml = results_stdout_52lts( remote_virsh_session.dumpxml(vm_name, debug=True, ignore_status=True)).strip() if hpt_resize: check_str = hpt_resize elif htm_state: check_str = htm_state if hpt_resize or htm_state: xml_check_after_mig = "%s'%s'" % (xml_check_after_mig, check_str) if not re.search(xml_check_after_mig, target_guest_dumpxml): remote_virsh_session.close_session() test.fail("Fail to search '%s' in target guest XML:\n%s" % (xml_check_after_mig, target_guest_dumpxml)) if contrl_index: all_ctrls = re.findall(xml_check_after_mig, target_guest_dumpxml) if len(all_ctrls) != int(contrl_index) + 1: remote_virsh_session.close_session() test.fail( "%s pci-root controllers are expected in guest XML, " "but found %s" % (int(contrl_index) + 1, len(all_ctrls))) remote_virsh_session.close_session() if int(mig_result.exit_status) == 0: server_session = remote.wait_for_login('ssh', server_ip, '22', server_user, server_pwd, r"[\#\$]\s*$") check_vm_network_accessed(server_session) server_session.close() except exceptions.TestFail as details: is_TestFail = True test_exception = details except exceptions.TestSkipError as details: is_TestSkip = True test_exception = details except exceptions.TestError as details: is_TestError = True test_exception = details except Exception as details: test_exception = details finally: logging.debug("Recover test environment") try: # Clean VM on destination vm.connect_uri = dest_uri cleanup_dest(vm) vm.connect_uri = src_uri logging.info("Recovery VM XML configration") orig_config_xml.sync() logging.debug("The current VM XML:\n%s", orig_config_xml.xmltreefile) if remote_virsh_session: remote_virsh_session.close_session() if extra.count("--tls") and not disable_verify_peer: logging.debug("Recover the qemu configuration") libvirt.customize_libvirt_config(None, config_type="qemu", remote_host=True, extra_params=params, is_recover=True, config_object=qemu_conf) if config_libvirtd: logging.debug("Recover the libvirtd configuration") libvirt.customize_libvirt_config(None, remote_host=True, extra_params=params, is_recover=True, config_object=libvirtd_conf) logging.info("Remove local NFS image") source_file = params.get("source_file") libvirt.delete_local_disk("file", path=source_file) if objs_list: for obj in objs_list: logging.debug("Clean up local objs") del obj except Exception as exception_detail: if (not test_exception and not is_TestError and not is_TestFail and not is_TestSkip): raise exception_detail else: # if any of above exceptions has been raised, only print # error log here to avoid of hiding the original issue logging.error(exception_detail) # Check result if is_TestFail: test.fail(test_exception) if is_TestSkip: test.cancel(test_exception) if is_TestError: test.error(test_exception) if not test_exception: logging.info("Case execution is done.") else: test.error(test_exception)
def run(test, params, env): """ Test migration with memory related configuration :param test: test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ migrate_vm_back = "yes" == params.get("migrate_vm_back", "no") remote_ip = params.get("remote_ip") remote_user = params.get("remote_user") remote_pwd = params.get("remote_pwd") local_ip = params.get("local_ip") local_pwd = params.get("local_pwd") ballooned_mem = params.get("ballooned_mem") check = params.get("check") remove_dict = {} src_libvirt_file = None remote_virsh_dargs = { 'remote_ip': remote_ip, 'remote_user': remote_user, 'remote_pwd': remote_pwd, 'unprivileged_user': None, 'ssh_remote_auth': True } migration_test = migration.MigrationTest() migration_test.check_parameters(params) # Params for NFS shared storage shared_storage = params.get("migrate_shared_storage", "") if shared_storage == "": default_guest_asset = defaults.get_default_guest_os_info()['asset'] default_guest_asset = "%s.qcow2" % default_guest_asset shared_storage = os.path.join(params.get("nfs_mount_dir"), default_guest_asset) logging.debug("shared_storage:%s", shared_storage) # Params to update disk using shared storage params["disk_type"] = "file" params["disk_source_protocol"] = "netfs" params["mnt_path_name"] = params.get("nfs_mount_dir") # Local variables server_ip = params.get("server_ip") server_user = params.get("server_user", "root") server_pwd = params.get("server_pwd") virsh_args = {"debug": True} virsh_options = params.get("virsh_options", "") options = params.get("virsh_migrate_options", "--live --verbose") func_params_exists = "yes" == params.get("func_params_exists", "yes") log_file = params.get("log_outputs", "/var/log/libvirt/libvirtd_daemons.log") check_str_local_log = params.get("check_str_local_log", "") libvirtd_conf_dict = eval(params.get("libvirtd_conf_dict", '{}')) func_name = None libvirtd_conf = None mig_result = None # params for migration connection params["virsh_migrate_desturi"] = libvirt_vm.complete_uri( params.get("migrate_dest_host")) dest_uri = params.get("virsh_migrate_desturi") vm_name = params.get("migrate_main_vm") vm = env.get_vm(vm_name) vm.verify_alive() extra_args = {} if func_params_exists: extra_args.update({'func_params': params}) # For safety reasons, we'd better back up xmlfile. new_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) orig_config_xml = new_xml.copy() try: if check == "mem_balloon": # Update memory balloon device to correct model membal_dict = { 'membal_model': 'virtio', 'membal_stats_period': '10' } libvirt.update_memballoon_xml(new_xml, membal_dict) if check == "mem_device": libvirt_cpu.add_cpu_settings(new_xml, params) dimm_params = { k.replace('memdev_', ''): v for k, v in params.items() if k.startswith('memdev_') } dimm_xml = utils_hotplug.create_mem_xml(**dimm_params) libvirt.add_vm_device(new_xml, dimm_xml) logging.debug(virsh.dumpxml(vm_name)) # Change the disk of the vm libvirt.set_vm_disk(vm, params) remove_dict = {"do_search": '{"%s": "ssh:/"}' % dest_uri} src_libvirt_file = libvirt_config.remove_key_for_modular_daemon( remove_dict) # Update libvirtd configuration if libvirtd_conf_dict: if os.path.exists(log_file): logging.debug("Delete local libvirt log file '%s'", log_file) os.remove(log_file) logging.debug("Update libvirtd configuration file") conf_type = params.get("conf_type", "libvirtd") if conf_type == "libvirtd" and utils_split_daemons.is_modular_daemon( ): conf_type = "virtqemud" libvirtd_conf = libvirt.customize_libvirt_config( libvirtd_conf_dict, conf_type) try: if not vm.is_alive(): vm.start() except virt_vm.VMStartError as e: logging.info("Failed to start VM") test.fail("Failed to start VM: %s" % vm_name) logging.debug("Guest xml after starting:\n%s", vm_xml.VMXML.new_from_dumpxml(vm_name)) # Check local guest network connection before migration vm.wait_for_login(restart_network=True).close() migration_test.ping_vm(vm, params) # Execute migration process vms = [vm] migration_test.do_migration(vms, None, dest_uri, 'orderly', options, thread_timeout=900, ignore_status=True, virsh_opt=virsh_options, func=func_name, **extra_args) mig_result = migration_test.ret migration_test.check_result(mig_result, params) if int(mig_result.exit_status) == 0: migration_test.ping_vm(vm, params, uri=dest_uri) if check_str_local_log: libvirt.check_logfile(check_str_local_log, log_file) if check == "mem_balloon": remote_virsh_session = virsh.VirshPersistent(**remote_virsh_dargs) remote_virsh_session.setmem(vm_name, ballooned_mem, None, None, False, "", **virsh_args) def check_mem_balloon(): """Check if memory balloon worked""" memstat_ouput = remote_virsh_session.dommemstat( vm_name, "", **virsh_args) memstat_after = memstat_ouput.stdout_text mem_after = memstat_after.splitlines()[0].split()[1] if mem_after != ballooned_mem: logging.debug("Current memory size is: %s" % mem_after) return False return True check_ret = utils_misc.wait_for(check_mem_balloon, timeout=20) if not check_ret: test.fail("Memory is not ballooned to the expected size: %s" % ballooned_mem) remote_virsh_session.close_session() # Create a remote runner for later use runner_on_target = remote.RemoteRunner(host=remote_ip, username=remote_user, password=remote_pwd) if check == "mem_device": qemu_checks = params.get('qemu_checks', '').split('`') logging.debug("qemu_checks:%s" % qemu_checks[0]) for qemu_check in qemu_checks: libvirt.check_qemu_cmd_line(qemu_check, False, params, runner_on_target) if migrate_vm_back: ssh_connection = utils_conn.SSHConnection(server_ip=remote_ip, server_pwd=remote_pwd, client_ip=local_ip, client_pwd=local_pwd) try: ssh_connection.conn_check() except utils_conn.ConnectionError: ssh_connection.conn_setup() ssh_connection.conn_check() # Pre migration setup for local machine src_full_uri = libvirt_vm.complete_uri( params.get("migrate_source_host")) migration_test.migrate_pre_setup(src_full_uri, params) cmd = "virsh migrate %s %s %s" % (vm_name, options, src_full_uri) logging.debug("Start migration: %s", cmd) cmd_result = remote.run_remote_cmd(cmd, params, runner_on_target) logging.info(cmd_result) if cmd_result.exit_status: destroy_cmd = "virsh destroy %s" % vm_name remote.run_remote_cmd(destroy_cmd, params, runner_on_target, ignore_status=False) test.fail("Failed to run '%s' on remote: %s" % (cmd, cmd_result)) finally: logging.debug("Recover test environment") # Clean VM on destination and source try: migration_test.cleanup_dest_vm(vm, vm.connect_uri, dest_uri) if vm.is_alive(): vm.destroy(gracefully=False) except Exception as err: logging.error(err) logging.info("Recovery VM XML configration") orig_config_xml.sync() if libvirtd_conf: logging.debug("Recover the configurations") libvirt.customize_libvirt_config(None, is_recover=True, config_object=libvirtd_conf) if src_libvirt_file: src_libvirt_file.restore()
def run(test, params, env): """ Test extended TSEG on Q35 machine types <smm state='on'> <tseg unit='MiB'>48</tseg> </smm> Steps: 1) Edit VM xml for smm or tseg sub element 2) Verify if Guest can boot as expected 3) On i440 machine types, the property does not support. On Q35 machine types, both Seabios and OVMF Guest can bootup """ vm_name = params.get("main_vm", "") vm = env.get_vm(vm_name) smm_state = params.get("smm_state", "off") unit = params.get("tseg_unit") size = params.get("tseg_size") boot_type = params.get("boot_type", "") loader_type = params.get("loader_type") loader = params.get("loader") err_msg = params.get("error_msg", "") vm_arch_name = params.get("vm_arch_name", "x86_64") status_error = ("yes" == params.get("status_error", "no")) if not libvirt_version.version_compare(4, 5, 0): test.cancel("TSEG does not support in " "current libvirt version") if (boot_type == "seabios" and not utils_package.package_install('seabios-bin')): test.cancel("Failed to install Seabios") if (boot_type == 'ovmf' and not utils_package.package_install('OVMF')): test.cancel("Failed to install OVMF") # Back VM XML v_xml_backup = vm_xml.VMXML.new_from_dumpxml(vm_name) v_xml = vm_xml.VMXML.new_from_dumpxml(vm_name) try: # Specify boot loader for OVMF if boot_type == 'ovmf': os_xml = v_xml.os os_xml.loader_type = loader_type os_xml.loader = loader os_xml.loader_readonly = "yes" v_xml.os = os_xml try: features_xml = v_xml.features except xcepts.LibvirtXMLNotFoundError: if vm_arch_name == 'x86_64': # ACPI is required for UEFI on x86_64 v_xml.xmltreefile.create_by_xpath("/features/acpi") features_xml = v_xml.features else: features_xml = vm_xml.VMFeaturesXML() features_xml.smm = smm_state if unit and size: features_xml.smm_tseg_unit = unit features_xml.smm_tseg = size v_xml.features = features_xml logging.debug("New VM XML is:\n%s", v_xml) ret = virsh.define(v_xml.xml) utlv.check_result(ret, expected_fails=err_msg) # Check result if not status_error: vm.start() if unit and size: # If tseg unit is KiB, convert it to MiB # as vm dumpxml convert it automatically if unit == 'KiB': unit, size = unify_to_MiB(unit, size) expect_line = "<tseg unit=\"%s\">%s</tseg>" % (unit, size) utlv.check_dumpxml(vm, expect_line) # Qemu cmdline use mbytes unit, tseg_mbytes = unify_to_MiB(unit, size) expect_line = '-global mch.extended-tseg-mbytes=%s' % size utlv.check_qemu_cmd_line(expect_line) finally: logging.debug("Restore the VM XML") if vm.is_alive(): vm.destroy() # OVMF enable nvram by default v_xml_backup.sync(options="--nvram")
def run(test, params, env): """ Test virsh migrate command. """ def set_feature(vmxml, feature, value): """ Set guest features for PPC :param state: the htm status :param vmxml: guest xml """ features_xml = vm_xml.VMFeaturesXML() if feature == 'hpt': features_xml.hpt_resizing = value elif feature == 'htm': features_xml.htm = value vmxml.features = features_xml vmxml.sync() def trigger_hpt_resize(session): """ Check the HPT order file and dmesg :param session: the session to guest :raise: test.fail if required message is not found """ hpt_order_path = "/sys/kernel/debug/powerpc/hpt_order" hpt_order = session.cmd_output('cat %s' % hpt_order_path).strip() hpt_order = int(hpt_order) logging.info('Current hpt_order is %d', hpt_order) hpt_order += 1 cmd = 'echo %d > %s' % (hpt_order, hpt_order_path) cmd_result = session.cmd_status_output(cmd) result = process.CmdResult(stderr=cmd_result[1], stdout=cmd_result[1], exit_status=cmd_result[0]) libvirt.check_exit_status(result) dmesg = session.cmd('dmesg') dmesg_content = params.get('dmesg_content').split('|') for content in dmesg_content: if content % hpt_order not in dmesg: test.fail("'%s' is missing in dmesg" % (content % hpt_order)) else: logging.info("'%s' is found in dmesg", content % hpt_order) def check_vm_network_accessed(session=None): """ The operations to the VM need to be done before or after migration happens :param session: The session object to the host :raise: test.error when ping fails """ # Confirm local/remote VM can be accessed through network. logging.info("Check VM network connectivity") s_ping, _ = utils_test.ping(vm.get_address(), count=10, timeout=20, output_func=logging.debug, session=session) if s_ping != 0: if session: session.close() test.fail("%s did not respond after %d sec." % (vm.name, 20)) def check_virsh_command_and_option(command, option=None): """ Check if virsh command exists :param command: the command to be checked :param option: the command option to be checked """ msg = "This version of libvirt does not support " if not virsh.has_help_command(command): test.cancel(msg + "virsh command '%s'" % command) if option and not virsh.has_command_help_match(command, option): test.cancel(msg + "virsh command '%s' with option '%s'" % (command, option)) def add_ctrls(vm_xml, dev_type="pci", dev_index="0", dev_model="pci-root"): """ Add multiple devices :param dev_type: the type of the device to be added :param dev_index: the maximum index of the device to be added :param dev_model: the model of the device to be added """ for inx in range(0, int(dev_index) + 1): newcontroller = Controller("controller") newcontroller.type = dev_type newcontroller.index = inx newcontroller.model = dev_model logging.debug("New device is added:\n%s", newcontroller) vm_xml.add_device(newcontroller) vm_xml.sync() def do_migration(vm, dest_uri, options, extra): """ Execute the migration with given parameters :param vm: the guest to be migrated :param dest_uri: the destination uri for migration :param options: options next to 'migrate' command :param extra: options in the end of the migrate command line :return: CmdResult object """ logging.info("Sleeping 10 seconds before migration") time.sleep(10) # Migrate the guest. virsh_args.update({"ignore_status": True}) migration_res = vm.migrate(dest_uri, options, extra, **virsh_args) if int(migration_res.exit_status) != 0: logging.error("Migration failed for %s.", vm_name) return migration_res if vm.is_alive(): # vm.connect_uri was updated logging.info("VM is alive on destination %s.", dest_uri) else: test.fail("VM is not alive on destination %s" % dest_uri) # Throws exception if console shows panic message vm.verify_kernel_crash() return migration_res def cleanup_libvirtd_log(log_file): """ Remove existing libvirtd log file on source and target host. :param log_file: log file with absolute path """ if os.path.exists(log_file): logging.debug("Delete local libvirt log file '%s'", log_file) os.remove(log_file) cmd = "rm -f %s" % log_file logging.debug("Delete remote libvirt log file '%s'", log_file) cmd_parms = {'server_ip': server_ip, 'server_user': server_user, 'server_pwd': server_pwd} remote.run_remote_cmd(cmd, cmd_parms, runner_on_target) def cleanup_dest(vm): """ Clean up the destination host environment when doing the uni-direction migration. :param vm: the guest to be cleaned up """ logging.info("Cleaning up VMs on %s", vm.connect_uri) try: if virsh.domain_exists(vm.name, uri=vm.connect_uri): vm_state = vm.state() if vm_state == "paused": vm.resume() elif vm_state == "shut off": vm.start() vm.destroy(gracefully=False) if vm.is_persistent(): vm.undefine() except Exception as detail: logging.error("Cleaning up destination failed.\n%s", detail) def run_stress_in_vm(): """ The function to load stress in VM """ stress_args = params.get("stress_args", "--cpu 8 --io 4 " "--vm 2 --vm-bytes 128M " "--timeout 20s") try: vm_session.cmd('stress %s' % stress_args) except Exception as detail: logging.debug(detail) def control_migrate_speed(to_speed=1): """ Control migration duration :param to_speed: the speed value in Mbps to be set for migration :return int: the new migration speed after setting """ virsh_args.update({"ignore_status": False}) old_speed = virsh.migrate_getspeed(vm_name, **virsh_args) logging.debug("Current migration speed is %s MiB/s\n", old_speed.stdout.strip()) logging.debug("Set migration speed to %d MiB/s\n", to_speed) cmd_result = virsh.migrate_setspeed(vm_name, to_speed, "", **virsh_args) actual_speed = virsh.migrate_getspeed(vm_name, **virsh_args) logging.debug("New migration speed is %s MiB/s\n", actual_speed.stdout.strip()) return int(actual_speed.stdout.strip()) def check_setspeed(params): """ Set/get migration speed :param params: the parameters used :raise: test.fail if speed set does not take effect """ expected_value = int(params.get("migrate_speed", '41943040')) // (1024 * 1024) actual_value = control_migrate_speed(to_speed=expected_value) params.update({'compare_to_value': actual_value}) if actual_value != expected_value: test.fail("Migration speed is expected to be '%d MiB/s', but '%d MiB/s' " "found" % (expected_value, actual_value)) def check_domjobinfo(params, option=""): """ Check given item in domjobinfo of the guest is as expected :param params: the parameters used :param option: options for domjobinfo :raise: test.fail if the value of given item is unexpected """ def search_jobinfo(jobinfo): """ Find value of given item in domjobinfo :param jobinfo: cmdResult object :raise: test.fail if not found """ for item in jobinfo.stdout.splitlines(): if item.count(jobinfo_item): groups = re.findall(r'[0-9.]+', item.strip()) logging.debug("In '%s' search '%s'\n", item, groups[0]) if (math.fabs(float(groups[0]) - float(compare_to_value)) // float(compare_to_value) > diff_rate): test.fail("{} {} has too much difference from " "{}".format(jobinfo_item, groups[0], compare_to_value)) break jobinfo_item = params.get("jobinfo_item") compare_to_value = params.get("compare_to_value") logging.debug("compare_to_value:%s", compare_to_value) diff_rate = float(params.get("diff_rate", "0")) if not jobinfo_item or not compare_to_value: return vm_ref = '{}{}'.format(vm_name, option) jobinfo = virsh.domjobinfo(vm_ref, **virsh_args) search_jobinfo(jobinfo) check_domjobinfo_remote = params.get("check_domjobinfo_remote") if check_domjobinfo_remote: remote_virsh_session = virsh.VirshPersistent(**remote_virsh_dargs) jobinfo = remote_virsh_session.domjobinfo(vm_ref, **virsh_args) search_jobinfo(jobinfo) remote_virsh_session.close_session() def check_maxdowntime(params): """ Set/get migration maxdowntime :param params: the parameters used :raise: test.fail if maxdowntime set does not take effect """ expected_value = int(float(params.get("migrate_maxdowntime", '0.3')) * 1000) virsh_args.update({"ignore_status": False}) old_value = int(virsh.migrate_getmaxdowntime(vm_name).stdout.strip()) logging.debug("Current migration maxdowntime is %d ms", old_value) logging.debug("Set migration maxdowntime to %d ms", expected_value) virsh.migrate_setmaxdowntime(vm_name, expected_value, **virsh_args) actual_value = int(virsh.migrate_getmaxdowntime(vm_name).stdout.strip()) logging.debug("New migration maxdowntime is %d ms", actual_value) if actual_value != expected_value: test.fail("Migration maxdowntime is expected to be '%d ms', but '%d ms' " "found" % (expected_value, actual_value)) params.update({'compare_to_value': actual_value}) def do_actions_during_migrate(params): """ The entry point to execute action list during migration :param params: the parameters used """ actions_during_migration = params.get("actions_during_migration") if not actions_during_migration: return for action in actions_during_migration.split(","): if action == 'setspeed': check_setspeed(params) elif action == 'domjobinfo': check_domjobinfo(params) elif action == 'setmaxdowntime': check_maxdowntime(params) time.sleep(3) def attach_channel_xml(): """ Create channel xml and attach it to guest configuration """ # Check if pty channel exists already for elem in new_xml.devices.by_device_tag('channel'): if elem.type_name == channel_type_name: logging.debug("{0} channel already exists in guest. " "No need to add new one".format(channel_type_name)) return params = {'channel_type_name': channel_type_name, 'target_type': target_type, 'target_name': target_name} channel_xml = libvirt.create_channel_xml(params) virsh.attach_device(domain_opt=vm_name, file_opt=channel_xml.xml, flagstr="--config", ignore_status=False) logging.debug("New VMXML with channel:\n%s", virsh.dumpxml(vm_name)) def check_timeout_postcopy(params): """ Check the vm state on target host after timeout when --postcopy and --timeout-postcopy are used. The vm state is expected as running. :param params: the parameters used """ timeout = int(params.get("timeout_postcopy", 10)) time.sleep(timeout + 1) remote_virsh_session = virsh.VirshPersistent(**remote_virsh_dargs) vm_state = results_stdout_52lts(remote_virsh_session.domstate(vm_name)).strip() if vm_state != "running": remote_virsh_session.close_session() test.fail("After timeout '%s' seconds, " "the vm state on target host should " "be 'running', but '%s' found", timeout, vm_state) remote_virsh_session.close_session() def get_usable_compress_cache(pagesize): """ Get a number which is bigger than pagesize and is power of two. :param pagesize: the given integer :return: an integer satisfying the criteria """ def calculate(num): result = num & (num - 1) return (result == 0) item = pagesize found = False while (not found): item += 1 found = calculate(item) logging.debug("%d is smallest one that is bigger than '%s' and " "is power of 2", item, pagesize) return item def check_migration_res(result): """ Check if the migration result is as expected :param result: the output of migration :raise: test.fail if test is failed """ logging.info("Migration out: %s", results_stdout_52lts(result).strip()) logging.info("Migration error: %s", results_stderr_52lts(result).strip()) if status_error: # Migration should fail if err_msg: # Special error messages are expected if not re.search(err_msg, results_stderr_52lts(result).strip()): test.fail("Can not find the expected patterns '%s' in " "output '%s'" % (err_msg, results_stderr_52lts(result).strip())) else: logging.debug("It is the expected error message") else: if int(result.exit_status) != 0: logging.debug("Migration failure is expected result") else: test.fail("Migration success is unexpected result") else: if int(result.exit_status) != 0: test.fail(results_stderr_52lts(result).strip()) check_parameters(test, params) # Params for NFS shared storage shared_storage = params.get("migrate_shared_storage", "") if shared_storage == "": default_guest_asset = defaults.get_default_guest_os_info()['asset'] default_guest_asset = "%s.qcow2" % default_guest_asset shared_storage = os.path.join(params.get("nfs_mount_dir"), default_guest_asset) logging.debug("shared_storage:%s", shared_storage) # params for migration connection params["virsh_migrate_desturi"] = libvirt_vm.complete_uri( params.get("migrate_dest_host")) # Params to update disk using shared storage params["disk_type"] = "file" params["disk_source_protocol"] = "netfs" params["mnt_path_name"] = params.get("nfs_mount_dir") # Local variables virsh_args = {"debug": True} virsh_opt = params.get("virsh_opt", "") server_ip = params.get("server_ip") server_user = params.get("server_user", "root") server_pwd = params.get("server_pwd") extra = params.get("virsh_migrate_extra") options = params.get("virsh_migrate_options") src_uri = params.get("virsh_migrate_connect_uri") dest_uri = params.get("virsh_migrate_desturi") log_file = params.get("libvirt_log", "/var/log/libvirt/libvirtd.log") check_complete_job = "yes" == params.get("check_complete_job", "no") config_libvirtd = "yes" == params.get("config_libvirtd", "no") contrl_index = params.get("new_contrl_index", None) asynch_migration = "yes" == params.get("asynch_migrate", "no") grep_str_remote_log = params.get("grep_str_remote_log", "") grep_str_local_log = params.get("grep_str_local_log", "") disable_verify_peer = "yes" == params.get("disable_verify_peer", "no") status_error = "yes" == params.get("status_error", "no") stress_in_vm = "yes" == params.get("stress_in_vm", "no") low_speed = params.get("low_speed", None) remote_virsh_dargs = {'remote_ip': server_ip, 'remote_user': server_user, 'remote_pwd': server_pwd, 'unprivileged_user': None, 'ssh_remote_auth': True} hpt_resize = params.get("hpt_resize", None) htm_state = params.get("htm_state", None) # For pty channel test add_channel = "yes" == params.get("add_channel", "no") channel_type_name = params.get("channel_type_name", None) target_type = params.get("target_type", None) target_name = params.get("target_name", None) cmd_run_in_remote_guest = params.get("cmd_run_in_remote_guest", None) cmd_run_in_remote_guest_1 = params.get("cmd_run_in_remote_guest_1", None) cmd_run_in_remote_host = params.get("cmd_run_in_remote_host", None) cmd_run_in_remote_host_1 = params.get("cmd_run_in_remote_host_1", None) cmd_run_in_remote_host_2 = params.get("cmd_run_in_remote_host_2", None) # For qemu command line checking qemu_check = params.get("qemu_check", None) xml_check_after_mig = params.get("guest_xml_check_after_mig", None) # params for cache matrix test cache = params.get("cache") remove_cache = "yes" == params.get("remove_cache", "no") err_msg = params.get("err_msg") arch = platform.machine() if any([hpt_resize, contrl_index, htm_state]) and 'ppc64' not in arch: test.cancel("The case is PPC only.") # For TLS tls_recovery = params.get("tls_auto_recovery", "yes") # qemu config qemu_conf_dict = None # libvirtd config libvirtd_conf_dict = None remote_virsh_session = None vm = None vm_session = None libvirtd_conf = None qemu_conf = None mig_result = None test_exception = None is_TestError = False is_TestFail = False is_TestSkip = False # Objects to be cleaned up in the end objs_list = [] tls_obj = None # Local variables vm_name = params.get("migrate_main_vm") vm = env.get_vm(vm_name) vm.verify_alive() # For safety reasons, we'd better back up xmlfile. new_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) orig_config_xml = new_xml.copy() if not orig_config_xml: test.error("Backing up xmlfile failed.") try: # Create a remote runner for later use runner_on_target = remote.RemoteRunner(host=server_ip, username=server_user, password=server_pwd) # Change the configuration files if needed before starting guest # For qemu.conf if extra.count("--tls"): # Setup TLS tls_obj = TLSConnection(params) if tls_recovery == "yes": objs_list.append(tls_obj) tls_obj.auto_recover = True tls_obj.conn_setup() if not disable_verify_peer: qemu_conf_dict = {"migrate_tls_x509_verify": "1"} # Setup qemu configure logging.debug("Configure the qemu") cleanup_libvirtd_log(log_file) qemu_conf = libvirt.customize_libvirt_config(qemu_conf_dict, config_type="qemu", remote_host=True, extra_params=params) # Setup libvirtd if config_libvirtd: logging.debug("Configure the libvirtd") cleanup_libvirtd_log(log_file) libvirtd_conf_dict = setup_libvirtd_conf_dict(params) libvirtd_conf = libvirt.customize_libvirt_config(libvirtd_conf_dict, remote_host=True, extra_params=params) # Prepare required guest xml before starting guest if contrl_index: new_xml.remove_all_device_by_type('controller') logging.debug("After removing controllers, current XML:\n%s\n", new_xml) add_ctrls(new_xml, dev_index=contrl_index) if add_channel: attach_channel_xml() if hpt_resize: set_feature(new_xml, 'hpt', hpt_resize) if htm_state: set_feature(new_xml, 'htm', htm_state) if cache: params["driver_cache"] = cache if remove_cache: params["enable_cache"] = "no" # Change the disk of the vm to shared disk and then start VM libvirt.set_vm_disk(vm, params) if not vm.is_alive(): vm.start() logging.debug("Guest xml after starting:\n%s", vm_xml.VMXML.new_from_dumpxml(vm_name)) # Check qemu command line after guest is started if qemu_check: check_content = qemu_check if hpt_resize: check_content = "%s%s" % (qemu_check, hpt_resize) if htm_state: check_content = "%s%s" % (qemu_check, htm_state) libvirt.check_qemu_cmd_line(check_content) # Check local guest network connection before migration vm_session = vm.wait_for_login() check_vm_network_accessed() # Preparation for the running guest before migration if hpt_resize and hpt_resize != 'disabled': trigger_hpt_resize(vm_session) if low_speed: control_migrate_speed(int(low_speed)) if stress_in_vm: pkg_name = 'stress' logging.debug("Check if stress tool is installed") pkg_mgr = utils_package.package_manager(vm_session, pkg_name) if not pkg_mgr.is_installed(pkg_name): logging.debug("Stress tool will be installed") if not pkg_mgr.install(): test.error("Package '%s' installation fails" % pkg_name) stress_thread = threading.Thread(target=run_stress_in_vm, args=()) stress_thread.start() if extra.count("timeout-postcopy"): func_name = check_timeout_postcopy if params.get("actions_during_migration"): func_name = do_actions_during_migrate if extra.count("comp-xbzrle-cache"): cache = get_usable_compress_cache(memory.get_page_size()) extra = "%s %s" % (extra, cache) # For --postcopy enable postcopy_options = params.get("postcopy_options") if postcopy_options: extra = "%s %s" % (extra, postcopy_options) # Execute migration process if not asynch_migration: mig_result = do_migration(vm, dest_uri, options, extra) else: migration_test = libvirt.MigrationTest() logging.debug("vm.connect_uri=%s", vm.connect_uri) vms = [vm] try: migration_test.do_migration(vms, None, dest_uri, 'orderly', options, thread_timeout=900, ignore_status=True, virsh_opt=virsh_opt, func=func_name, extra_opts=extra, func_params=params) mig_result = migration_test.ret except exceptions.TestFail as fail_detail: test.fail(fail_detail) except exceptions.TestSkipError as skip_detail: test.cancel(skip_detail) except exceptions.TestError as error_detail: test.error(error_detail) except Exception as details: mig_result = migration_test.ret logging.error(details) check_migration_res(mig_result) if add_channel: # Get the channel device source path of remote guest if not remote_virsh_session: remote_virsh_session = virsh.VirshPersistent(**remote_virsh_dargs) file_path = tempfile.mktemp(dir=data_dir.get_tmp_dir()) remote_virsh_session.dumpxml(vm_name, to_file=file_path, debug=True, ignore_status=True) local_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) local_vmxml.xmltreefile = xml_utils.XMLTreeFile(file_path) for elem in local_vmxml.devices.by_device_tag('channel'): logging.debug("Found channel device {}".format(elem)) if elem.type_name == channel_type_name: host_source = elem.source.get('path') logging.debug("Remote guest uses {} for channel device".format(host_source)) break remote_virsh_session.close_session() if not host_source: test.fail("Can not find source for %s channel on remote host" % channel_type_name) # Prepare to wait for message on remote host from the channel cmd_parms = {'server_ip': server_ip, 'server_user': server_user, 'server_pwd': server_pwd} cmd_result = remote.run_remote_cmd(cmd_run_in_remote_host % host_source, cmd_parms, runner_on_target) # Send message from remote guest to the channel file remote_vm_obj = utils_test.RemoteVMManager(cmd_parms) vm_ip = vm.get_address() vm_pwd = params.get("password") remote_vm_obj.setup_ssh_auth(vm_ip, vm_pwd) cmd_result = remote_vm_obj.run_command(vm_ip, cmd_run_in_remote_guest_1) remote_vm_obj.run_command(vm_ip, cmd_run_in_remote_guest % results_stdout_52lts(cmd_result).strip()) logging.debug("Sending message is done") # Check message on remote host from the channel remote.run_remote_cmd(cmd_run_in_remote_host_1, cmd_parms, runner_on_target) logging.debug("Receiving message is done") remote.run_remote_cmd(cmd_run_in_remote_host_2, cmd_parms, runner_on_target) if check_complete_job: opts = " --completed" check_virsh_command_and_option("domjobinfo", opts) if extra.count("comp-xbzrle-cache"): params.update({'compare_to_value': cache // 1024}) check_domjobinfo(params, option=opts) if grep_str_local_log: cmd = "grep -E '%s' %s" % (grep_str_local_log, log_file) cmdRes = process.run(cmd, shell=True, ignore_status=True) if cmdRes.exit_status: test.fail(results_stderr_52lts(cmdRes).strip()) if grep_str_remote_log: cmd = "grep -E '%s' %s" % (grep_str_remote_log, log_file) cmd_parms = {'server_ip': server_ip, 'server_user': server_user, 'server_pwd': server_pwd} remote.run_remote_cmd(cmd, cmd_parms, runner_on_target) if xml_check_after_mig: if not remote_virsh_session: remote_virsh_session = virsh.VirshPersistent(**remote_virsh_dargs) target_guest_dumpxml = results_stdout_52lts( remote_virsh_session.dumpxml(vm_name, debug=True, ignore_status=True)).strip() if hpt_resize: check_str = hpt_resize elif htm_state: check_str = htm_state if hpt_resize or htm_state: xml_check_after_mig = "%s'%s'" % (xml_check_after_mig, check_str) if not re.search(xml_check_after_mig, target_guest_dumpxml): remote_virsh_session.close_session() test.fail("Fail to search '%s' in target guest XML:\n%s" % (xml_check_after_mig, target_guest_dumpxml)) if contrl_index: all_ctrls = re.findall(xml_check_after_mig, target_guest_dumpxml) if len(all_ctrls) != int(contrl_index) + 1: remote_virsh_session.close_session() test.fail("%s pci-root controllers are expected in guest XML, " "but found %s" % (int(contrl_index) + 1, len(all_ctrls))) remote_virsh_session.close_session() if int(mig_result.exit_status) == 0: server_session = remote.wait_for_login('ssh', server_ip, '22', server_user, server_pwd, r"[\#\$]\s*$") check_vm_network_accessed(server_session) server_session.close() except exceptions.TestFail as details: is_TestFail = True test_exception = details except exceptions.TestSkipError as details: is_TestSkip = True test_exception = details except exceptions.TestError as details: is_TestError = True test_exception = details except Exception as details: test_exception = details finally: logging.debug("Recover test environment") try: # Clean VM on destination vm.connect_uri = dest_uri cleanup_dest(vm) vm.connect_uri = src_uri logging.info("Recovery VM XML configration") orig_config_xml.sync() logging.debug("The current VM XML:\n%s", orig_config_xml.xmltreefile) if remote_virsh_session: remote_virsh_session.close_session() if extra.count("--tls") and not disable_verify_peer: logging.debug("Recover the qemu configuration") libvirt.customize_libvirt_config(None, config_type="qemu", remote_host=True, extra_params=params, is_recover=True, config_object=qemu_conf) if config_libvirtd: logging.debug("Recover the libvirtd configuration") libvirt.customize_libvirt_config(None, remote_host=True, extra_params=params, is_recover=True, config_object=libvirtd_conf) logging.info("Remove local NFS image") source_file = params.get("source_file") libvirt.delete_local_disk("file", path=source_file) if objs_list: for obj in objs_list: logging.debug("Clean up local objs") del obj except Exception as exception_detail: if (not test_exception and not is_TestError and not is_TestFail and not is_TestSkip): raise exception_detail else: # if any of above exceptions has been raised, only print # error log here to avoid of hiding the original issue logging.error(exception_detail) # Check result if is_TestFail: test.fail(test_exception) if is_TestSkip: test.cancel(test_exception) if is_TestError: test.error(test_exception) if not test_exception: logging.info("Case execution is done.") else: test.error(test_exception)
def run(test, params, env): """ Test memory management of nvdimm """ vm_name = params.get('main_vm') nvdimm_file = params.get('nvdimm_file') check = params.get('check', '') qemu_checks = params.get('qemu_checks', '').split('`') test_str = 'This is a test!' def check_boot_config(session): """ Check /boot/config-$KVER file """ check_list = [ 'CONFIG_LIBNVDIMM=m', 'CONFIG_BLK_DEV_PMEM=m', 'CONFIG_ACPI_NFIT=m' ] current_boot = session.cmd('uname -r').strip() content = session.cmd('cat /boot/config-%s' % current_boot).strip() for item in check_list: if item in content: logging.info(item) else: logging.error(item) test.fail('/boot/config content not correct') def check_file_in_vm(session, path, expect=True): """ Check whether the existance of file meets expectation """ exist = session.cmd_status('ls %s' % path) logging.debug(exist) exist = True if exist == 0 else False status = '' if exist else 'NOT' logging.info('File %s does %s exist', path, status) if exist != expect: err_msg = 'Existance doesn\'t meet expectation: %s ' % path if expect: err_msg += 'should exist.' else: err_msg += 'should not exist' test.fail(err_msg) def create_cpuxml(): """ Create cpu xml for test """ cpu_params = {k: v for k, v in params.items() if k.startswith('cpuxml_')} logging.debug(cpu_params) cpu_xml = vm_xml.VMCPUXML() cpu_xml.xml = "<cpu><numa/></cpu>" for attr_key in cpu_params: val = cpu_params[attr_key] logging.debug('Set cpu params') setattr(cpu_xml, attr_key.replace('cpuxml_', ''), eval(val) if ':' in val else val) logging.debug(cpu_xml) return cpu_xml.copy() def create_nvdimm_xml(**mem_param): """ Create xml of nvdimm memory device """ mem_xml = utils_hotplug.create_mem_xml( tg_size=mem_param['target_size'], mem_addr={'slot': mem_param['address_slot']}, tg_sizeunit=mem_param['target_size_unit'], tg_node=mem_param['target_node'], mem_model="nvdimm", lb_size=mem_param.get('label_size'), lb_sizeunit=mem_param.get('label_size_unit'), mem_access=mem_param['mem_access'] ) source_xml = memory.Memory.Source() source_xml.path = mem_param['source_path'] mem_xml.source = source_xml logging.debug(mem_xml) return mem_xml.copy() bkxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) try: vm = env.get_vm(vm_name) # Create nvdimm file on the host process.run('truncate -s 512M %s' % nvdimm_file, verbose=True) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Set cpu according to params cpu_xml = create_cpuxml() vmxml.cpu = cpu_xml # Update other vcpu, memory info according to params update_vm_args = {k: params[k] for k in params if k.startswith('setvm_')} logging.debug(update_vm_args) for key, value in list(update_vm_args.items()): attr = key.replace('setvm_', '') logging.debug('Set %s = %s', attr, value) setattr(vmxml, attr, int(value) if value.isdigit() else value) logging.debug(virsh.dumpxml(vm_name)) # Add an nvdimm mem device to vm xml nvdimm_params = {k.replace('nvdimmxml_', ''): v for k, v in params.items() if k.startswith('nvdimmxml_')} nvdimm_xml = create_nvdimm_xml(**nvdimm_params) vmxml.add_device(nvdimm_xml) vmxml.sync() logging.debug(virsh.dumpxml(vm_name)) virsh.start(vm_name, debug=True, ignore_status=False) # Check qemu command line one by one map(libvirt.check_qemu_cmd_line, qemu_checks) alive_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) # Check if the guest support NVDIMM: # check /boot/config-$KVER file vm_session = vm.wait_for_login() check_boot_config(vm_session) # check /dev/pmem0 existed inside guest check_file_in_vm(vm_session, '/dev/pmem0') if check == 'back_file': # Create an ext4 file system on /dev/pmem0 cmd_list = [ "mkfs.ext4 /dev/pmem0", "mount -o dax /dev/pmem0 /mnt", "echo '%s' >/mnt/foo" % test_str, "umount /mnt" ] map(vm_session.cmd, cmd_list) vm_session.close() # Shutdown the guest, then start it, remount /dev/pmem0, # check if the test file is still on the file system vm.destroy() vm.start() vm_session = vm.wait_for_login() vm_session.cmd('mount -o dax /dev/pmem0 /mnt') if test_str not in vm_session.cmd('cat /mnt/foo'): test.fail('"%s" should be in /mnt/foo') # From the host, check the file has changed: host_output = process.run('hexdump -C /tmp/nvdimm', shell=True, verbose=True).stdout_text if test_str not in host_output: test.fail('"%s" should be in output') # Shutdown the guest, and edit the xml, # include: access='private' vm_session.close() vm.destroy() vm_devices = vmxml.devices nvdimm_device = vm_devices.by_device_tag('memory')[0] nvdimm_index = vm_devices.index(nvdimm_device) vm_devices[nvdimm_index].mem_access = 'private' vmxml.devices = vm_devices vmxml.sync() # Login to the guest, mount the /dev/pmem0 and . # create a file: foo-private vm.start() vm_session = vm.wait_for_login() libvirt.check_qemu_cmd_line('mem-path=/tmp/nvdimm,share=no') private_str = 'This is a test for foo-private!' vm_session.cmd('mount -o dax /dev/pmem0 /mnt/') file_private = 'foo-private' vm_session.cmd("echo '%s' >/mnt/%s" % (private_str, file_private)) if private_str not in vm_session.cmd('cat /mnt/%s' % file_private): test.fail('"%s" should be in output' % private_str) # Shutdown the guest, then start it, # check the file: foo-private is no longer existed vm_session.close() vm.destroy() vm.start() vm_session = vm.wait_for_login() vm_session.cmd('mount -o dax /dev/pmem0 /mnt/') if file_private in vm_session.cmd('ls /mnt/'): test.fail('%s should not exist, for it was ' 'created when access=private' % file_private) if check == 'label_back_file': # Create an xfs file system on /dev/pmem0 vm_session.cmd('mkfs.xfs -f -b size=4096 /dev/pmem0') # Mount the file system with DAX enabled for page cache bypass output = vm_session.cmd_output('mount -o dax /dev/pmem0 /mnt/') logging.info(output) # Create a file on the nvdimm device. test_str = 'This is a test with label' vm_session.cmd('echo "%s" >/mnt/foo-label' % test_str) if test_str not in vm_session.cmd('cat /mnt/foo-label '): test.fail('"%s" should be in output' % test_str) # Reboot the guest, and remount the nvdimm device in the guest. # Check the file foo-label is exited vm_session.close() virsh.reboot(vm_name, debug=True) vm_session = vm.wait_for_login() vm_session.cmd('mount -o dax /dev/pmem0 /mnt') if test_str not in vm_session.cmd('cat /mnt/foo-label '): test.fail('"%s" should be in output' % test_str) if check == 'hot_plug': # Create file for 2nd nvdimm device nvdimm_file_2 = params.get('nvdimm_file_2') process.run('truncate -s 512M %s' % nvdimm_file_2) # Add 2nd nvdimm device to vm xml nvdimm2_params = {k.replace('nvdimmxml2_', ''): v for k, v in params.items() if k.startswith('nvdimmxml2_')} nvdimm2_xml = create_nvdimm_xml(**nvdimm2_params) ori_devices = vm_xml.VMXML.new_from_dumpxml(vm_name).get_devices('memory') logging.debug('Starts with %d memory devices', len(ori_devices)) result = virsh.attach_device(vm_name, nvdimm2_xml.xml, debug=True) libvirt.check_exit_status(result) # After attach, there should be an extra memory device devices_after_attach = vm_xml.VMXML.new_from_dumpxml(vm_name).get_devices('memory') logging.debug('After detach, vm has %d memory devices', len(devices_after_attach)) if len(ori_devices) != len(devices_after_attach) - 1: test.fail('Number of memory devices after attach is %d, should be %d' % (len(devices_after_attach), len(ori_devices) + 1)) time.sleep(5) check_file_in_vm(vm_session, '/dev/pmem1') nvdimm_detach = alive_vmxml.get_devices('memory')[-1] logging.debug(nvdimm_detach) # Hot-unplug nvdimm device result = virsh.detach_device(vm_name, nvdimm_detach.xml, debug=True) libvirt.check_exit_status(result) vm_session.close() vm_session = vm.wait_for_login() virsh.dumpxml(vm_name, debug=True) left_devices = vm_xml.VMXML.new_from_dumpxml(vm_name).get_devices('memory') logging.debug(left_devices) if len(left_devices) != len(ori_devices): test.fail('Number of memory devices after detach is %d, should be %d' % (len(left_devices), len(ori_devices))) time.sleep(5) check_file_in_vm(vm_session, '/dev/pmem1', expect=False) finally: if vm.is_alive(): vm.destroy(gracefully=False) bkxml.sync() os.remove(nvdimm_file)
def run(test, params, env): """ Test hpt resizing """ resizing = params.get('resizing') vm_name = params.get('main_vm') vm = env.get_vm(vm_name) status_error = 'yes' == params.get('status_error', 'no') error_msg = params.get('error_msg', '') hpt_order_path = params.get('hpt_order_path', '') qemu_check = params.get('qemu_check', '') def set_hpt(resizing, vmxml, sync=True): """ Set resizing value to vm xml """ features_xml = vm_xml.VMFeaturesXML() features_xml.hpt_resizing = resizing vmxml.features = features_xml if sync: vmxml.sync() def set_memory(vmxml): """ Set memory attributes in vm xml """ vmxml.max_mem_rt = int(params.get('max_mem_rt', 30670848)) vmxml.max_mem_rt_slots = int(params.get('max_mem_rt_slots', 16)) vmxml.max_mem_rt_unit = params.get('max_mem_rt_unit', 'KiB') cpu = vm_xml.VMCPUXML() cpu.xml = "<cpu><numa/></cpu>" numa_cell = eval(params.get('numa_cell')) logging.debug(numa_cell) vmxml.vcpu = max([int(cell['cpus'][-1]) for cell in numa_cell]) + 1 cpu.numa_cell = numa_cell vmxml.cpu = cpu vmxml.sync() def check_hpt_order(session, resizing=''): """ Return htp order in hpt_order file by default If 'resizing' is disabled, test updating htp_order """ if not hpt_order_path: test.cancel('No hpt order path provided.') hpt_order = session.cmd_output('cat %s' % hpt_order_path).strip() hpt_order = int(hpt_order) logging.info('Current hpt_order is %d', hpt_order) if resizing == 'disabled': cmd_result = session.cmd_status_output( 'echo %d > %s' % (hpt_order + 1, hpt_order_path)) result = process.CmdResult(stderr=cmd_result[1], exit_status=cmd_result[0]) libvirt.check_exit_status(result, True) libvirt.check_result(result, [error_msg]) return hpt_order bk_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) try: arch = platform.machine() new_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Test on ppc64le hosts if arch.lower() == 'ppc64le': set_hpt(resizing, new_xml) if resizing == 'enabled': set_memory(new_xml) # Start vm and check if start succeeds libvirt.check_exit_status(virsh.start(vm_name, debug=True)) libvirt.check_qemu_cmd_line(qemu_check) session = vm.wait_for_login() hpt_order = check_hpt_order(session, resizing) if resizing == 'enabled': mem_xml = utils_hotplug.create_mem_xml( tg_size=int(params.get('mem_size', 2048000)), tg_sizeunit=params.get('size_unit', 'KiB'), tg_node=int(params.get('mem_node', 0)), mem_model=params.get('mem_model', 'dimm') ) logging.debug(mem_xml) # Attach memory device to the guest for 12 times # that will reach the maxinum memory limitation for i in range(12): virsh.attach_device(vm_name, mem_xml.xml, debug=True, ignore_status=False) xml_after_attach = vm_xml.VMXML.new_from_dumpxml(vm_name) logging.debug(xml_after_attach) # Check dumpxml of the guest, # check if each device has its alias for i in range(12): pattern = "alias\s+name=[\'\"]dimm%d[\'\"]" % i logging.debug('Searching for %s', pattern) if not re.search(pattern, str(xml_after_attach.xmltreefile)): test.fail('Missing memory alias: %s' % pattern) # Log in the guest and check dmesg dmesg = session.cmd('dmesg') logging.debug(dmesg) dmesg_content = params.get('dmesg_content', '').split('|') for order in range(1, 3): order += hpt_order for content in dmesg_content: if content % order not in dmesg: test.fail('Missing dmesg: %s' % (content % order)) # Test on non-ppc64le hosts else: set_hpt(resizing, new_xml, sync=False) result = virsh.define(new_xml.xml) libvirt.check_exit_status(result, status_error) libvirt.check_result(result, [error_msg]) finally: bk_xml.sync()
def run(test, params, env): """ Test virsh migrate command. """ def set_feature(vmxml, feature, value): """ Set guest features for PPC :param state: the htm status :param vmxml: guest xml """ features_xml = vm_xml.VMFeaturesXML() if feature == 'hpt': hpt_xml = vm_xml.VMFeaturesHptXML() hpt_xml.resizing = value features_xml.hpt = hpt_xml elif feature == 'htm': features_xml.htm = value vmxml.features = features_xml vmxml.sync() def trigger_hpt_resize(session): """ Check the HPT order file and dmesg :param session: the session to guest :raise: test.fail if required message is not found """ hpt_order_path = "/sys/kernel/debug/powerpc/hpt_order" hpt_order = session.cmd_output('cat %s' % hpt_order_path).strip() hpt_order = int(hpt_order) logging.info('Current hpt_order is %d', hpt_order) hpt_order += 1 cmd = 'echo %d > %s' % (hpt_order, hpt_order_path) cmd_result = session.cmd_status_output(cmd) result = process.CmdResult(stderr=cmd_result[1], stdout=cmd_result[1], exit_status=cmd_result[0]) libvirt.check_exit_status(result) dmesg = session.cmd('dmesg') dmesg_content = params.get('dmesg_content').split('|') for content in dmesg_content: if content % hpt_order not in dmesg: test.fail("'%s' is missing in dmesg" % (content % hpt_order)) else: logging.info("'%s' is found in dmesg", content % hpt_order) def check_vm_network_accessed(session=None): """ The operations to the VM need to be done before or after migration happens :param session: The session object to the host :raise: test.error when ping fails """ # Confirm local/remote VM can be accessed through network. logging.info("Check VM network connectivity") s_ping, _ = utils_test.ping(vm.get_address(), count=10, timeout=20, output_func=logging.debug, session=session) if s_ping != 0: if session: session.close() test.fail("%s did not respond after %d sec." % (vm.name, 20)) def check_virsh_command_and_option(command, option=None): """ Check if virsh command exists :param command: the command to be checked :param option: the command option to be checked """ msg = "This version of libvirt does not support " if not virsh.has_help_command(command): test.cancel(msg + "virsh command '%s'" % command) if option and not virsh.has_command_help_match(command, option): test.cancel(msg + "virsh command '%s' with option '%s'" % (command, option)) def add_ctrls(vm_xml, dev_type="pci", dev_index="0", dev_model="pci-root"): """ Add multiple devices :param dev_type: the type of the device to be added :param dev_index: the maximum index of the device to be added :param dev_model: the model of the device to be added """ for inx in range(0, int(dev_index) + 1): newcontroller = Controller("controller") newcontroller.type = dev_type newcontroller.index = inx newcontroller.model = dev_model logging.debug("New device is added:\n%s", newcontroller) vm_xml.add_device(newcontroller) vm_xml.sync() def do_migration(vm, dest_uri, options, extra): """ Execute the migration with given parameters :param vm: the guest to be migrated :param dest_uri: the destination uri for migration :param options: options next to 'migrate' command :param extra: options in the end of the migrate command line :return: CmdResult object """ logging.info("Sleeping 10 seconds before migration") time.sleep(10) # Migrate the guest. virsh_args.update({"ignore_status": True}) migration_res = vm.migrate(dest_uri, options, extra, **virsh_args) if int(migration_res.exit_status) != 0: logging.error("Migration failed for %s.", vm_name) return migration_res if vm.is_alive(): # vm.connect_uri was updated logging.info("VM is alive on destination %s.", dest_uri) else: test.fail("VM is not alive on destination %s" % dest_uri) # Throws exception if console shows panic message vm.verify_kernel_crash() return migration_res def cleanup_libvirtd_log(log_file): """ Remove existing libvirtd log file on source and target host. :param log_file: log file with absolute path """ if os.path.exists(log_file): logging.debug("Delete local libvirt log file '%s'", log_file) os.remove(log_file) cmd = "rm -f %s" % log_file logging.debug("Delete remote libvirt log file '%s'", log_file) remote.run_remote_cmd(cmd, cmd_parms, runner_on_target) def cleanup_dest(vm): """ Clean up the destination host environment when doing the uni-direction migration. :param vm: the guest to be cleaned up """ logging.info("Cleaning up VMs on %s", vm.connect_uri) try: if virsh.domain_exists(vm.name, uri=vm.connect_uri): vm_state = vm.state() if vm_state == "paused": vm.resume() elif vm_state == "shut off": vm.start() vm.destroy(gracefully=False) if vm.is_persistent(): vm.undefine() except Exception as detail: logging.error("Cleaning up destination failed.\n%s", detail) def run_stress_in_vm(): """ The function to load stress in VM """ stress_args = params.get("stress_args", "--cpu 8 --io 4 " "--vm 2 --vm-bytes 128M " "--timeout 20s") try: vm_session.cmd('stress %s' % stress_args) except Exception as detail: logging.debug(detail) def control_migrate_speed(to_speed=1, opts=""): """ Control migration duration :param to_speed: the speed value in Mbps to be set for migration :return int: the new migration speed after setting """ virsh_args.update({"ignore_status": False}) old_speed = virsh.migrate_getspeed(vm_name, extra=opts, **virsh_args) logging.debug("Current migration speed is %s MiB/s\n", old_speed.stdout.strip()) logging.debug("Set migration speed to %d MiB/s\n", to_speed) cmd_result = virsh.migrate_setspeed(vm_name, to_speed, extra=opts, **virsh_args) actual_speed = virsh.migrate_getspeed(vm_name, extra=opts, **virsh_args) logging.debug("New migration speed is %s MiB/s\n", actual_speed.stdout.strip()) return int(actual_speed.stdout.strip()) def check_setspeed(params): """ Set/get migration speed :param params: the parameters used :raise: test.fail if speed set does not take effect """ expected_value = int(params.get("migrate_speed", '41943040')) // (1024 * 1024) actual_value = control_migrate_speed(to_speed=expected_value) params.update({'compare_to_value': actual_value}) if actual_value != expected_value: test.fail("Migration speed is expected to be '%d MiB/s', but '%d MiB/s' " "found" % (expected_value, actual_value)) def check_domjobinfo(params, option=""): """ Check given item in domjobinfo of the guest is as expected :param params: the parameters used :param option: options for domjobinfo :raise: test.fail if the value of given item is unexpected """ def search_jobinfo(jobinfo): """ Find value of given item in domjobinfo :param jobinfo: cmdResult object :raise: test.fail if not found """ for item in jobinfo.stdout.splitlines(): if item.count(jobinfo_item): groups = re.findall(r'[0-9.]+', item.strip()) logging.debug("In '%s' search '%s'\n", item, groups[0]) if (math.fabs(float(groups[0]) - float(compare_to_value)) // float(compare_to_value) > diff_rate): test.fail("{} {} has too much difference from " "{}".format(jobinfo_item, groups[0], compare_to_value)) break jobinfo_item = params.get("jobinfo_item") compare_to_value = params.get("compare_to_value") logging.debug("compare_to_value:%s", compare_to_value) diff_rate = float(params.get("diff_rate", "0")) if not jobinfo_item or not compare_to_value: return vm_ref = '{}{}'.format(vm_name, option) jobinfo = virsh.domjobinfo(vm_ref, **virsh_args) search_jobinfo(jobinfo) check_domjobinfo_remote = params.get("check_domjobinfo_remote") if check_domjobinfo_remote: remote_virsh_session = virsh.VirshPersistent(**remote_virsh_dargs) jobinfo = remote_virsh_session.domjobinfo(vm_ref, **virsh_args) search_jobinfo(jobinfo) remote_virsh_session.close_session() def search_jobinfo_output(jobinfo, items_to_check, postcopy_req=False): """ Check the results of domjobinfo :param jobinfo: cmdResult object :param items_to_check: expected value :param postcopy_req: True for postcopy migration and False for precopy :return: False if not found """ expected_value = copy.deepcopy(items_to_check) logging.debug("The items_to_check is %s", expected_value) for item in jobinfo.splitlines(): item_key = item.strip().split(':')[0] if "all_items" in expected_value and len(item_key) > 0: # "Time elapsed w/o network" and "Downtime w/o network" # have a chance to be missing, it is normal if item_key in ['Downtime w/o network', 'Time elapsed w/o network']: continue if expected_value["all_items"][0] == item_key: del expected_value["all_items"][0] else: test.fail("The item '%s' should be '%s'" % (item_key, expected_value["all_items"][0])) if item_key in expected_value: item_value = ':'.join(item.strip().split(':')[1:]).strip() if item_value != expected_value.get(item_key): test.fail("The value of {} is {} which is not " "expected".format(item_key, item_value)) else: del expected_value[item_key] if postcopy_req and item_key == "Postcopy requests": if int(item.strip().split(':')[1]) <= 0: test.fail("The value of Postcopy requests is incorrect") # Check if all the items in expect_dict checked or not if "all_items" in expected_value: if len(expected_value["all_items"]) > 0: test.fail("Missing item: {} from all_items" .format(expected_value["all_items"])) else: del expected_value["all_items"] if len(expected_value) != 0: test.fail("Missing item: {}".format(expected_value)) def set_migratepostcopy(): """ Switch to postcopy during migration """ res = virsh.migrate_postcopy(vm_name) logging.debug("Command output: %s", res) if not utils_misc.wait_for( lambda: migration_test.check_vm_state(vm_name, "paused", "post-copy"), 10): test.fail("vm status is expected to 'paused (post-copy)'") def check_domjobinfo_output(option="", is_mig_compelete=False): """ Check all items in domjobinfo of the guest on both remote and local :param option: options for domjobinfo :param is_mig_compelete: False for domjobinfo checking during migration, True for domjobinfo checking after migration :raise: test.fail if the value of given item is unexpected """ expected_list_during_mig = ["Job type", "Operation", "Time elapsed", "Data processed", "Data remaining", "Data total", "Memory processed", "Memory remaining", "Memory total", "Memory bandwidth", "Dirty rate", "Page size", "Iteration", "Constant pages", "Normal pages", "Normal data", "Expected downtime", "Setup time"] if libvirt_version.version_compare(4, 10, 0): expected_list_during_mig.insert(13, "Postcopy requests") expected_list_after_mig_src = copy.deepcopy(expected_list_during_mig) expected_list_after_mig_src[-2] = 'Total downtime' expected_list_after_mig_dest = copy.deepcopy(expected_list_after_mig_src) # Check version in remote if not expected_list_after_mig_dest.count("Postcopy requests"): remote_session = remote.remote_login("ssh", server_ip, "22", server_user, server_pwd, "#") if libvirt_version.version_compare(4, 10, 0, session=remote_session): expected_list_after_mig_dest.insert(14, "Postcopy requests") remote_session.close() expect_dict = {"src_notdone": {"Job type": "Unbounded", "Operation": "Outgoing migration", "all_items": expected_list_during_mig}, "dest_notdone": {"error": "Operation not supported: mig" "ration statistics are availab" "le only on the source host"}, "src_done": {"Job type": "Completed", "Operation": "Outgoing migration", "all_items": expected_list_after_mig_src}, "dest_done": {"Job type": "Completed", "Operation": "Incoming migration", "all_items": expected_list_after_mig_dest}} pc_opt = False if postcopy_options: pc_opt = True if is_mig_compelete: expect_dict["dest_done"].clear() expect_dict["dest_done"]["Job type"] = "None" else: set_migratepostcopy() vm_ref = '{}{}'.format(vm_name, option) src_jobinfo = virsh.domjobinfo(vm_ref, **virsh_args) cmd = "virsh domjobinfo {} {}".format(vm_name, option) dest_jobinfo = remote.run_remote_cmd(cmd, cmd_parms, runner_on_target) if not is_mig_compelete: search_jobinfo_output(src_jobinfo.stdout, expect_dict["src_notdone"], postcopy_req=pc_opt) search_jobinfo_output(dest_jobinfo.stderr, expect_dict["dest_notdone"]) else: search_jobinfo_output(src_jobinfo.stdout, expect_dict["src_done"]) search_jobinfo_output(dest_jobinfo.stdout, expect_dict["dest_done"]) def check_maxdowntime(params): """ Set/get migration maxdowntime :param params: the parameters used :raise: test.fail if maxdowntime set does not take effect """ expected_value = int(float(params.get("migrate_maxdowntime", '0.3')) * 1000) virsh_args.update({"ignore_status": False}) old_value = int(virsh.migrate_getmaxdowntime(vm_name).stdout.strip()) logging.debug("Current migration maxdowntime is %d ms", old_value) logging.debug("Set migration maxdowntime to %d ms", expected_value) virsh.migrate_setmaxdowntime(vm_name, expected_value, **virsh_args) actual_value = int(virsh.migrate_getmaxdowntime(vm_name).stdout.strip()) logging.debug("New migration maxdowntime is %d ms", actual_value) if actual_value != expected_value: test.fail("Migration maxdowntime is expected to be '%d ms', but '%d ms' " "found" % (expected_value, actual_value)) params.update({'compare_to_value': actual_value}) def run_time(init_time=2): """ Compare the duration of func to an expected one :param init_time: Expected run time :raise: test.fail if func takes more than init_time(second) """ def check_time(func): def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) duration = time.time() - start if duration > init_time: test.fail("It takes too long to check {}. The duration is " "{}s which should be less than {}s" .format(func.__doc__, duration, init_time)) return result return wrapper return check_time def run_domstats(vm_name): """ Run domstats and domstate during migration in source and destination :param vm_name: VM name :raise: test.fail if domstats does not return in 2s or domstate is incorrect """ @run_time() def check_source_stats(vm_name): """domstats in source""" vm_stats = virsh.domstats(vm_name) logging.debug("domstats in source: {}".format(vm_stats)) @run_time() def check_dest_stats(vm_name): """domstats in target""" cmd = "virsh domstats {}".format(vm_name) dest_stats = remote.run_remote_cmd(cmd, cmd_parms, runner_on_target) logging.debug("domstats in destination: {}".format(dest_stats)) expected_remote_state = "paused" expected_source_state = ["paused", "running"] if postcopy_options: set_migratepostcopy() expected_remote_state = "running" expected_source_state = ["paused"] check_source_stats(vm_name) vm_stat = virsh.domstate(vm_name, ignore_status=False) if ((not len(vm_stat.stdout.split())) or vm_stat.stdout.split()[0] not in expected_source_state): test.fail("Incorrect VM stat on source machine: {}" .format(vm_stat.stdout)) check_dest_stats(vm_name) cmd = "virsh domstate {}".format(vm_name) remote_vm_state = remote.run_remote_cmd(cmd, cmd_parms, runner_on_target, ignore_status=False) if ((not len(remote_vm_state.stdout.split())) or remote_vm_state.stdout.split()[0] != expected_remote_state): test.fail("Incorrect VM stat on destination machine: {}" .format(remote_vm_state.stdout)) else: logging.debug("vm stat on destination: {}".format(remote_vm_state)) if postcopy_options: vm_stat = virsh.domstate(vm_name, ignore_status=False) if ((not len(vm_stat.stdout.split())) or vm_stat.stdout.split()[0] != "paused"): test.fail("Incorrect VM stat on source machine: {}" .format(vm_stat.stdout)) def kill_qemu_target(): """ Kill qemu process on target host during Finish Phase of migration :raise: test.fail if domstate is not "post-copy failed" after qemu killed """ if not vm.is_qemu(): test.cancel("This case is qemu guest only.") set_migratepostcopy() emulator = new_xml.get_devices('emulator')[0] logging.debug("emulator is %s", emulator.path) cmd = 'pkill -9 {}'.format(os.path.basename(emulator.path)) runner_on_target.run(cmd) if not utils_misc.wait_for( lambda: migration_test.check_vm_state(vm_name, "paused", "post-copy failed"), 60): test.fail("vm status is expected to 'paused (post-copy failed)'") def do_actions_during_migrate(params): """ The entry point to execute action list during migration :param params: the parameters used """ actions_during_migration = params.get("actions_during_migration") if not actions_during_migration: return for action in actions_during_migration.split(","): if action == 'setspeed': check_setspeed(params) elif action == 'domjobinfo': check_domjobinfo(params) elif action == 'setmaxdowntime': check_maxdowntime(params) elif action == 'converge': check_converge(params) elif action == 'domjobinfo_output_all': check_domjobinfo_output() elif action == 'checkdomstats': run_domstats(vm_name) elif action == 'killqemutarget': kill_qemu_target() time.sleep(3) def attach_channel_xml(): """ Create channel xml and attach it to guest configuration """ # Check if pty channel exists already for elem in new_xml.devices.by_device_tag('channel'): if elem.type_name == channel_type_name: logging.debug("{0} channel already exists in guest. " "No need to add new one".format(channel_type_name)) return params = {'channel_type_name': channel_type_name, 'target_type': target_type, 'target_name': target_name} channel_xml = libvirt.create_channel_xml(params) virsh.attach_device(domain_opt=vm_name, file_opt=channel_xml.xml, flagstr="--config", ignore_status=False) logging.debug("New VMXML with channel:\n%s", virsh.dumpxml(vm_name)) def check_timeout_postcopy(params): """ Check the vm state on target host after timeout when --postcopy and --timeout-postcopy are used. The vm state is expected as running. :param params: the parameters used """ timeout = int(params.get("timeout_postcopy", 10)) time.sleep(timeout + 1) remote_virsh_session = virsh.VirshPersistent(**remote_virsh_dargs) vm_state = results_stdout_52lts(remote_virsh_session.domstate(vm_name)).strip() if vm_state != "running": remote_virsh_session.close_session() test.fail("After timeout '%s' seconds, " "the vm state on target host should " "be 'running', but '%s' found" % (timeout, vm_state)) remote_virsh_session.close_session() def check_converge(params): """ Handle option '--auto-converge --auto-converge-initial --auto-converge-increment '. 'Auto converge throttle' in domjobinfo should start with the initial value and increase with correct increment and max value is 99. :param params: The parameters used :raise: exceptions.TestFail when unexpected or no throttle is found """ initial = int(params.get("initial", 20)) increment = int(params.get("increment", 10)) max_converge = int(params.get("max_converge", 99)) allow_throttle_list = [initial + count * increment for count in range(0, (100 - initial) // increment + 1) if (initial + count * increment) < 100] allow_throttle_list.append(max_converge) logging.debug("The allowed 'Auto converge throttle' value " "is %s", allow_throttle_list) throttle = 0 jobtype = "None" while throttle < 100: cmd_result = virsh.domjobinfo(vm_name, debug=True, ignore_status=True) if cmd_result.exit_status: logging.debug(cmd_result.stderr) # Check if migration is completed if "domain is not running" in cmd_result.stderr: args = vm_name + " --completed" cmd_result = virsh.domjobinfo(args, debug=True, ignore_status=True) if cmd_result.exit_status: test.error("Failed to get domjobinfo and domjobinfo " "--completed: %s" % cmd_result.stderr) else: test.error("Failed to get domjobinfo: %s" % cmd_result.stderr) jobinfo = cmd_result.stdout for line in jobinfo.splitlines(): key = line.split(':')[0] if key.count("Job type"): jobtype = line.split(':')[-1].strip() elif key.count("Auto converge throttle"): throttle = int(line.split(':')[-1].strip()) logging.debug("Auto converge throttle:%s", str(throttle)) if throttle and throttle not in allow_throttle_list: test.fail("Invalid auto converge throttle " "value '%s'" % throttle) if throttle == 99: logging.debug("'Auto converge throttle' reaches maximum " "allowed value 99") break if jobtype == "None" or jobtype == "Completed": logging.debug("Jobtype:%s", jobtype) if not throttle: test.fail("'Auto converge throttle' is " "not found in the domjobinfo") break time.sleep(5) def get_usable_compress_cache(pagesize): """ Get a number which is bigger than pagesize and is power of two. :param pagesize: the given integer :return: an integer satisfying the criteria """ def calculate(num): result = num & (num - 1) return (result == 0) item = pagesize found = False while (not found): item += 1 found = calculate(item) logging.debug("%d is smallest one that is bigger than '%s' and " "is power of 2", item, pagesize) return item def update_config_file(config_type, new_conf, remote_host=True, params=None): """ Update the specified configuration file with dict :param config_type: Like libvirtd, qemu :param new_conf: The str including new configuration :param remote_host: True to also update in remote host :param params: The dict including parameters to connect remote host :return: utils_config.LibvirtConfigCommon object """ logging.debug("Update configuration file") cleanup_libvirtd_log(log_file) config_dict = eval(new_conf) updated_conf = libvirt.customize_libvirt_config(config_dict, config_type=config_type, remote_host=remote_host, extra_params=params) return updated_conf def check_migration_res(result): """ Check if the migration result is as expected :param result: the output of migration :raise: test.fail if test is failed """ logging.info("Migration out: %s", results_stdout_52lts(result).strip()) logging.info("Migration error: %s", results_stderr_52lts(result).strip()) if status_error: # Migration should fail if err_msg: # Special error messages are expected if not re.search(err_msg, results_stderr_52lts(result).strip()): test.fail("Can not find the expected patterns '%s' in " "output '%s'" % (err_msg, results_stderr_52lts(result).strip())) else: logging.debug("It is the expected error message") else: if int(result.exit_status) != 0: logging.debug("Migration failure is expected result") else: test.fail("Migration success is unexpected result") else: if int(result.exit_status) != 0: test.fail(results_stderr_52lts(result).strip()) check_parameters(test, params) # Params for NFS shared storage shared_storage = params.get("migrate_shared_storage", "") if shared_storage == "": default_guest_asset = defaults.get_default_guest_os_info()['asset'] default_guest_asset = "%s.qcow2" % default_guest_asset shared_storage = os.path.join(params.get("nfs_mount_dir"), default_guest_asset) logging.debug("shared_storage:%s", shared_storage) # params for migration connection params["virsh_migrate_desturi"] = libvirt_vm.complete_uri( params.get("migrate_dest_host")) # Params to update disk using shared storage params["disk_type"] = "file" params["disk_source_protocol"] = "netfs" params["mnt_path_name"] = params.get("nfs_mount_dir") # Local variables virsh_args = {"debug": True} virsh_opt = params.get("virsh_opt", "") server_ip = params.get("server_ip") server_user = params.get("server_user", "root") server_pwd = params.get("server_pwd") extra = params.get("virsh_migrate_extra") options = params.get("virsh_migrate_options") src_uri = params.get("virsh_migrate_connect_uri") dest_uri = params.get("virsh_migrate_desturi") log_file = params.get("libvirt_log", "/var/log/libvirt/libvirtd.log") check_complete_job = "yes" == params.get("check_complete_job", "no") check_domjobinfo_results = "yes" == params.get("check_domjobinfo_results") contrl_index = params.get("new_contrl_index", None) asynch_migration = "yes" == params.get("asynch_migrate", "no") grep_str_remote_log = params.get("grep_str_remote_log", "") grep_str_local_log = params.get("grep_str_local_log", "") disable_verify_peer = "yes" == params.get("disable_verify_peer", "no") status_error = "yes" == params.get("status_error", "no") stress_in_vm = "yes" == params.get("stress_in_vm", "no") low_speed = params.get("low_speed", None) remote_virsh_dargs = {'remote_ip': server_ip, 'remote_user': server_user, 'remote_pwd': server_pwd, 'unprivileged_user': None, 'ssh_remote_auth': True} cmd_parms = {'server_ip': server_ip, 'server_user': server_user, 'server_pwd': server_pwd} hpt_resize = params.get("hpt_resize", None) htm_state = params.get("htm_state", None) # For pty channel test add_channel = "yes" == params.get("add_channel", "no") channel_type_name = params.get("channel_type_name", None) target_type = params.get("target_type", None) target_name = params.get("target_name", None) cmd_run_in_remote_guest = params.get("cmd_run_in_remote_guest", None) cmd_run_in_remote_guest_1 = params.get("cmd_run_in_remote_guest_1", None) cmd_run_in_remote_host = params.get("cmd_run_in_remote_host", None) cmd_run_in_remote_host_1 = params.get("cmd_run_in_remote_host_1", None) cmd_run_in_remote_host_2 = params.get("cmd_run_in_remote_host_2", None) # For qemu command line checking qemu_check = params.get("qemu_check", None) xml_check_after_mig = params.get("guest_xml_check_after_mig", None) # params for cache matrix test cache = params.get("cache") remove_cache = "yes" == params.get("remove_cache", "no") err_msg = params.get("err_msg") arch = platform.machine() if any([hpt_resize, contrl_index, htm_state]) and 'ppc64' not in arch: test.cancel("The case is PPC only.") # For TLS tls_recovery = params.get("tls_auto_recovery", "yes") # qemu config qemu_conf_dict = None # libvirtd config libvirtd_conf_dict = None # remote shell session remote_session = None remote_virsh_session = None vm = None vm_session = None libvirtd_conf = None qemu_conf = None mig_result = None test_exception = None is_TestError = False is_TestFail = False is_TestSkip = False # Objects to be cleaned up in the end objs_list = [] tls_obj = None # Local variables vm_name = params.get("migrate_main_vm") vm = env.get_vm(vm_name) vm.verify_alive() # For safety reasons, we'd better back up xmlfile. new_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) orig_config_xml = new_xml.copy() if not orig_config_xml: test.error("Backing up xmlfile failed.") try: # Create a remote runner for later use runner_on_target = remote.RemoteRunner(host=server_ip, username=server_user, password=server_pwd) # Change the configuration files if needed before starting guest # For qemu.conf if extra.count("--tls"): # Setup TLS tls_obj = TLSConnection(params) if tls_recovery == "yes": objs_list.append(tls_obj) tls_obj.auto_recover = True tls_obj.conn_setup() # Setup qemu.conf qemu_conf_dict = params.get("qemu_conf_dict") if qemu_conf_dict: qemu_conf = update_config_file('qemu', qemu_conf_dict, params=params) # Setup libvirtd libvirtd_conf_dict = params.get("libvirtd_conf_dict") if libvirtd_conf_dict: libvirtd_conf = update_config_file('libvirtd', libvirtd_conf_dict, params=params) # Prepare required guest xml before starting guest if contrl_index: new_xml.remove_all_device_by_type('controller') logging.debug("After removing controllers, current XML:\n%s\n", new_xml) add_ctrls(new_xml, dev_index=contrl_index) if add_channel: attach_channel_xml() if hpt_resize: set_feature(new_xml, 'hpt', hpt_resize) if htm_state: set_feature(new_xml, 'htm', htm_state) if cache: params["driver_cache"] = cache if remove_cache: params["enable_cache"] = "no" # Change the disk of the vm to shared disk and then start VM libvirt.set_vm_disk(vm, params) if not vm.is_alive(): vm.start() logging.debug("Guest xml after starting:\n%s", vm_xml.VMXML.new_from_dumpxml(vm_name)) # Check qemu command line after guest is started if qemu_check: check_content = qemu_check if hpt_resize: check_content = "%s%s" % (qemu_check, hpt_resize) if htm_state: check_content = "%s%s" % (qemu_check, htm_state) libvirt.check_qemu_cmd_line(check_content) # Check local guest network connection before migration vm_session = vm.wait_for_login() check_vm_network_accessed() # Preparation for the running guest before migration if hpt_resize and hpt_resize != 'disabled': trigger_hpt_resize(vm_session) if stress_in_vm: pkg_name = 'stress' logging.debug("Check if stress tool is installed") pkg_mgr = utils_package.package_manager(vm_session, pkg_name) if not pkg_mgr.is_installed(pkg_name): logging.debug("Stress tool will be installed") if not pkg_mgr.install(): test.error("Package '%s' installation fails" % pkg_name) stress_thread = threading.Thread(target=run_stress_in_vm, args=()) stress_thread.start() if extra.count("timeout-postcopy"): func_name = check_timeout_postcopy if params.get("actions_during_migration"): func_name = do_actions_during_migrate if extra.count("comp-xbzrle-cache"): cache = get_usable_compress_cache(memory.get_page_size()) extra = "%s %s" % (extra, cache) # For --postcopy enable postcopy_options = params.get("postcopy_options") if postcopy_options: extra = "%s %s" % (extra, postcopy_options) if low_speed: control_migrate_speed(int(low_speed)) if postcopy_options and libvirt_version.version_compare(5, 0, 0): control_migrate_speed(int(low_speed), opts=postcopy_options) # Execute migration process if not asynch_migration: mig_result = do_migration(vm, dest_uri, options, extra) else: migration_test = libvirt.MigrationTest() logging.debug("vm.connect_uri=%s", vm.connect_uri) vms = [vm] try: migration_test.do_migration(vms, None, dest_uri, 'orderly', options, thread_timeout=900, ignore_status=True, virsh_opt=virsh_opt, func=func_name, extra_opts=extra, func_params=params) mig_result = migration_test.ret except exceptions.TestFail as fail_detail: test.fail(fail_detail) except exceptions.TestSkipError as skip_detail: test.cancel(skip_detail) except exceptions.TestError as error_detail: test.error(error_detail) except Exception as details: mig_result = migration_test.ret logging.error(details) check_migration_res(mig_result) if add_channel: # Get the channel device source path of remote guest if not remote_virsh_session: remote_virsh_session = virsh.VirshPersistent(**remote_virsh_dargs) file_path = tempfile.mktemp(dir=data_dir.get_tmp_dir()) remote_virsh_session.dumpxml(vm_name, to_file=file_path, debug=True, ignore_status=True) local_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) local_vmxml.xmltreefile = xml_utils.XMLTreeFile(file_path) for elem in local_vmxml.devices.by_device_tag('channel'): logging.debug("Found channel device {}".format(elem)) if elem.type_name == channel_type_name: host_source = elem.source.get('path') logging.debug("Remote guest uses {} for channel device".format(host_source)) break remote_virsh_session.close_session() if not host_source: test.fail("Can not find source for %s channel on remote host" % channel_type_name) # Prepare to wait for message on remote host from the channel cmd_result = remote.run_remote_cmd(cmd_run_in_remote_host % host_source, cmd_parms, runner_on_target) # Send message from remote guest to the channel file remote_vm_obj = utils_test.RemoteVMManager(cmd_parms) vm_ip = vm.get_address() vm_pwd = params.get("password") remote_vm_obj.setup_ssh_auth(vm_ip, vm_pwd) cmd_result = remote_vm_obj.run_command(vm_ip, cmd_run_in_remote_guest_1) remote_vm_obj.run_command(vm_ip, cmd_run_in_remote_guest % results_stdout_52lts(cmd_result).strip()) logging.debug("Sending message is done") # Check message on remote host from the channel remote.run_remote_cmd(cmd_run_in_remote_host_1, cmd_parms, runner_on_target) logging.debug("Receiving message is done") remote.run_remote_cmd(cmd_run_in_remote_host_2, cmd_parms, runner_on_target) if check_complete_job: opts = " --completed" check_virsh_command_and_option("domjobinfo", opts) if extra.count("comp-xbzrle-cache"): params.update({'compare_to_value': cache // 1024}) check_domjobinfo(params, option=opts) if check_domjobinfo_results: check_domjobinfo_output(option=opts, is_mig_compelete=True) if grep_str_local_log: cmd = "grep -E '%s' %s" % (grep_str_local_log, log_file) cmdRes = process.run(cmd, shell=True, ignore_status=True) if cmdRes.exit_status: test.fail(results_stderr_52lts(cmdRes).strip()) if grep_str_remote_log: cmd = "grep -E '%s' %s" % (grep_str_remote_log, log_file) remote.run_remote_cmd(cmd, cmd_parms, runner_on_target) if xml_check_after_mig: if not remote_virsh_session: remote_virsh_session = virsh.VirshPersistent(**remote_virsh_dargs) target_guest_dumpxml = results_stdout_52lts( remote_virsh_session.dumpxml(vm_name, debug=True, ignore_status=True)).strip() if hpt_resize: check_str = hpt_resize elif htm_state: check_str = htm_state if hpt_resize or htm_state: xml_check_after_mig = "%s'%s'" % (xml_check_after_mig, check_str) if not re.search(xml_check_after_mig, target_guest_dumpxml): remote_virsh_session.close_session() test.fail("Fail to search '%s' in target guest XML:\n%s" % (xml_check_after_mig, target_guest_dumpxml)) if contrl_index: all_ctrls = re.findall(xml_check_after_mig, target_guest_dumpxml) if len(all_ctrls) != int(contrl_index) + 1: remote_virsh_session.close_session() test.fail("%s pci-root controllers are expected in guest XML, " "but found %s" % (int(contrl_index) + 1, len(all_ctrls))) remote_virsh_session.close_session() if int(mig_result.exit_status) == 0: server_session = remote.wait_for_login('ssh', server_ip, '22', server_user, server_pwd, r"[\#\$]\s*$") check_vm_network_accessed(server_session) server_session.close() except exceptions.TestFail as details: is_TestFail = True test_exception = details except exceptions.TestSkipError as details: is_TestSkip = True test_exception = details except exceptions.TestError as details: is_TestError = True test_exception = details except Exception as details: test_exception = details finally: logging.debug("Recover test environment") try: # Clean VM on destination vm.connect_uri = dest_uri cleanup_dest(vm) vm.connect_uri = src_uri logging.info("Recovery VM XML configration") orig_config_xml.sync() logging.debug("The current VM XML:\n%s", orig_config_xml.xmltreefile) if remote_virsh_session: remote_virsh_session.close_session() if remote_session: remote_session.close() # Delete files on target # Killing qemu process on target may lead a problem like # qemu process becomes a zombie process whose ppid is 1. # As a workaround, have to remove the files under # /var/run/libvirt/qemu to make libvirt work. if vm.is_qemu(): dest_pid_files = os.path.join("/var/run/libvirt/qemu", vm_name + '*') cmd = "rm -f %s" % dest_pid_files logging.debug("Delete remote pid files '%s'", dest_pid_files) remote.run_remote_cmd(cmd, cmd_parms, runner_on_target) if extra.count("--tls") and not disable_verify_peer: logging.debug("Recover the qemu configuration") libvirt.customize_libvirt_config(None, config_type="qemu", remote_host=True, extra_params=params, is_recover=True, config_object=qemu_conf) for update_conf in [libvirtd_conf, qemu_conf]: if update_conf: logging.debug("Recover the configurations") libvirt.customize_libvirt_config(None, remote_host=True, extra_params=params, is_recover=True, config_object=update_conf) logging.info("Remove local NFS image") source_file = params.get("source_file") libvirt.delete_local_disk("file", path=source_file) if objs_list: for obj in objs_list: logging.debug("Clean up local objs") del obj except Exception as exception_detail: if (not test_exception and not is_TestError and not is_TestFail and not is_TestSkip): raise exception_detail else: # if any of above exceptions has been raised, only print # error log here to avoid of hiding the original issue logging.error(exception_detail) # Check result if is_TestFail: test.fail(test_exception) if is_TestSkip: test.cancel(test_exception) if is_TestError: test.error(test_exception) if not test_exception: logging.info("Case execution is done.") else: test.error(test_exception)
def run(test, params, env): """ Test virtual L3 cache as follows. 1) Start vm with virtual L3 cache and none cpu mode 2) Start vm with virtual L3 cache and host-passthrough cpu mode 3) Start vm with virtual L3 cache and host-model cpu mode 4) Invalid virtual L3 cache info for VM :param test: test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ def create_cpu_xml(): """ Create cpu xml :return: cpu object """ cpu_xml = vm_xml.VMCPUXML() cache_attrs = {} if cpu_mode: cpu_xml.mode = cpu_mode if cache_level: cache_attrs.update({'level': cache_level}) if cache_mode: cache_attrs.update({'mode': cache_mode}) cpu_xml.cache = cache_attrs logging.debug(cpu_xml) return cpu_xml vm_name = params.get('main_vm') vm = env.get_vm(vm_name) cpu_mode = params.get('cpu_mode') cache_level = params.get('cache_level') cache_mode = params.get('cache_mode') cmd_in_vm = params.get('cmd_in_vm') qemu_line = params.get('qemu_line') cmd_output_regex = params.get('cmd_output_regex') string_in_cmd_output = "yes" == params.get("string_in_cmd_output", "no") status_error = "yes" == params.get("status_error", "no") err_msg = params.get("err_msg") qemu_lines = [] if qemu_line: qemu_lines.append(qemu_line) bkxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) try: # Create cpu xml for test cpu_xml = create_cpu_xml() # Update vm's cpu vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) vmxml.cpu = cpu_xml # Update for "passthrough" test if cpu_mode == "host-passthrough": qemu_line_cacheinfo = params.get("qemu_line_cacheinfo", "host-cache-info=off") qemu_lines.append(qemu_line_cacheinfo) if cache_mode == "passthrough" and cmd_in_vm: cmd_output_regex = process.run(cmd_in_vm, shell=True).stdout_text if not status_error: vmxml.sync() vm_xml_cxt = virsh.dumpxml(vm_name).stdout_text.strip() logging.debug("The VM XML with cpu cache: \n%s", vm_xml_cxt) # Check if vm could start successfully try: result = virsh.start(vm_name, debug=True) libvirt.check_exit_status(result) except virt_vm.VMStartError as details: test.fail('VM failed to start:\n%s' % details) # Check qemu command line and other checkpoints for qemuline in qemu_lines: libvirt.check_qemu_cmd_line(qemuline) if cmd_in_vm: vm_session = vm.wait_for_login() status, output = vm_session.cmd_status_output(cmd_in_vm) if status != 0 or not output: test.fail( "Failed to run command '%s'.status: [%s] output: " "[%s]" % (cmd_in_vm, status, output)) if cmd_output_regex: logging.debug("checking regex %s", cmd_output_regex) res = re.findall(cmd_output_regex, output.strip()) if string_in_cmd_output != bool(len(res)): test.fail("The string '{}' {} included in {}".format( cmd_output_regex, "is not" if string_in_cmd_output else "is", output.strip())) else: result_need_check = virsh.define(vmxml.xml, debug=True) libvirt.check_result(result_need_check, err_msg) finally: logging.debug("Recover test environment") vm.destroy(gracefully=False) bkxml.sync()
def run(test, params, env): """ Test sysinfo in guest <sysinfo type='fwcfg'>...</sysinfo> <sysinfo type='smbios'>...</sysinfo> Steps: 1) Edit VM XML for sysinfo element 2) Verify if guest can boot as expected 3) Check if the sysinfo is correct """ vm_name = params.get("main_vm", "") vm = env.get_vm(vm_name) boot_type = params.get("boot_type", "") loader_type = params.get("loader_type") loader = params.get("loader") sysinfo_type = params.get("sysinfo_type", "") entry_name = params.get("entry_name") value_string = params.get("value_string") with_file = ("yes" == params.get("with_file", "no")) with_value = ("yes" == params.get("with_value", "no")) entry_file = os.path.join(data_dir.get_tmp_dir(), "provision.ign") err_msg = params.get("error_msg", "") status_error = ("yes" == params.get("status_error", "no")) without_name = ("yes" == params.get("without_name", "no")) if not libvirt_version.version_compare(6, 5, 0): test.cancel("FWCFG sysinfo is not supported in " "current libvirt version") if (boot_type == "seabios" and not utils_package.package_install('seabios-bin')): test.cancel("Failed to install Seabios") if (boot_type == "ovmf" and not utils_package.package_install('OVMF')): test.cancel("Failed to install OVMF") # Back VM XML vmxml_backup = vm_xml.VMXML.new_from_dumpxml(vm_name) vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) try: # Specify boot loader for OVMF if boot_type == "ovmf": os_xml = vmxml.os os_xml.loader_type = loader_type os_xml.loader = loader os_xml.loader_readonly = "yes" vmxml.os = os_xml # Set attributes of fwcfg sysinfo in VMSysinfoXML if sysinfo_type == "fwcfg": sysinfo_xml = vm_xml.VMSysinfoXML() sysinfo_xml.type = sysinfo_type # Test with entry value in text if with_value: sysinfo_xml.entry_name = entry_name sysinfo_xml.entry = value_string # Test with entry file if with_file: with open('%s' % entry_file, 'w+') as f: f.write('%s' % value_string) sysinfo_xml.entry_name = entry_name sysinfo_xml.entry_file = entry_file # Negative test without entry name elif without_name: sysinfo_xml.entry = value_string # Negative test without file in entry else: sysinfo_xml.entry_name = entry_name vmxml.sysinfo = sysinfo_xml logging.debug("New VM XML is:\n%s" % vmxml) ret = virsh.define(vmxml.xml) libvirt.check_result(ret, expected_fails=err_msg) result = virsh.start(vm_name, debug=True) libvirt.check_exit_status(result) if not status_error: # Check result in dumpxml and qemu cmdline if with_file: expect_xml_line = "<entry file=\"%s\" name=\"%s\" />" % ( entry_file, entry_name) expect_qemu_line = "-fw_cfg name=%s,file=%s" % (entry_name, entry_file) if with_value: expect_xml_line = "<entry name=\"%s\">%s</entry>" % ( entry_name, value_string) expect_qemu_line = "-fw_cfg name=%s,string=%s" % (entry_name, value_string) libvirt.check_dumpxml(vm, expect_xml_line) libvirt.check_qemu_cmd_line(expect_qemu_line) # Check result in guest kwargs = { "sysinfo_type": sysinfo_type, "value_string": value_string, "entry_name": entry_name } check_in_vm(test, vm, **kwargs) finally: logging.debug("Start to cleanup") if vm.is_alive(): vm.destroy() logging.debug("Restore the VM XML") vmxml_backup.sync(options="--nvram") # Remove tmp file if os.path.exists(entry_file): os.remove(entry_file)
def run(test, params, env): """ Test command: virsh setmem. 1) Prepare vm environment. 2) Handle params 3) Prepare libvirtd status. 4) Run test command and wait for current memory's stable. 5) Recover environment. 4) Check result. """ def get_vm_usable_mem(session): """ Get total usable RAM from /proc/meminfo """ cmd = "cat /proc/meminfo" proc_mem = session.cmd_output(cmd) total_usable_mem = re.search(r'MemTotal:\s+(\d+)\s+[kK]B', proc_mem).group(1) return int(total_usable_mem) def vm_unusable_mem(session): """ Get the unusable RAM of the VM. """ # Get total physical memory from dmidecode cmd = "dmidecode -t 17" dmi_mem = session.cmd_output(cmd) dmi_mem_size = re.findall(r'Size:\s(\d+\s+[K|M|G]B)', dmi_mem) if not dmi_mem_size: test.fail("Cannot get memory size info inside VM.") total_physical_mem = 0 for size_info in dmi_mem_size: mem_size = int(size_info.split()[0].strip()) mem_unit = size_info.split()[1].strip() if mem_unit.lower() == 'kb': total_physical_mem += mem_size elif mem_unit.lower() == 'mb': total_physical_mem += mem_size * 1024 elif mem_unit.lower() == 'gb': total_physical_mem += mem_size * 1048576 return total_physical_mem - get_vm_usable_mem(session) def make_domref(domarg, vm_ref, domid, vm_name, domuuid): """ Create domain options of command """ # Specify domain as argument or parameter if domarg == "yes": dom_darg_key = "domainarg" else: dom_darg_key = "domain" # How to reference domain if vm_ref == "domid": dom_darg_value = domid elif vm_ref == "domname": dom_darg_value = vm_name elif vm_ref == "domuuid": dom_darg_value = domuuid elif vm_ref == "none": dom_darg_value = None elif vm_ref == "emptystring": dom_darg_value = '""' else: # stick in value directly dom_darg_value = vm_ref return {dom_darg_key: dom_darg_value} def make_sizeref(sizearg, mem_ref, original_mem): """ Create size options of command """ if sizearg == "yes": size_darg_key = "sizearg" else: size_darg_key = "size" if mem_ref == "halfless": size_darg_value = "%d" % (original_mem // 2) elif mem_ref == "halfmore": size_darg_value = "%d" % int(original_mem * 1.5) # no fraction elif mem_ref == "same": size_darg_value = "%d" % original_mem elif mem_ref == "emptystring": size_darg_value = '""' elif mem_ref == "zero": size_darg_value = "0" elif mem_ref == "toosmall": size_darg_value = "1024" elif mem_ref == "toobig": size_darg_value = "1099511627776" # (KiB) One Petabyte elif mem_ref == "none": size_darg_value = None else: # stick in value directly size_darg_value = mem_ref return {size_darg_key: size_darg_value} def cal_deviation(actual, expected): """ Calculate deviation of actual result and expected result """ numerator = float(actual) denominator = float(expected) if numerator > denominator: numerator = denominator denominator = float(actual) return 100 - (100 * (numerator / denominator)) def is_old_libvirt(): """ Check if libvirt is old version """ regex = r'\s+\[--size\]\s+' return bool(not virsh.has_command_help_match('setmem', regex)) def print_debug_stats(original_inside_mem, original_outside_mem, test_inside_mem, test_outside_mem, expected_outside_mem, expected_inside_mem, delta_percentage, unusable_mem): """ Print debug message for test """ # Calculate deviation inside_deviation = cal_deviation(test_inside_mem, expected_inside_mem) outside_deviation = cal_deviation(test_outside_mem, expected_outside_mem) dbgmsg = ("Unusable memory of VM : %d KiB\n" "Original inside memory : %d KiB\n" "Expected inside memory : %d KiB\n" "Actual inside memory : %d KiB\n" "Inside memory deviation : %0.2f%%\n" "Original outside memory : %d KiB\n" "Expected outside memory : %d KiB\n" "Actual outside memory : %d KiB\n" "Outside memory deviation: %0.2f%%\n" "Acceptable deviation : %0.2f%%" % (unusable_mem, original_inside_mem, expected_inside_mem, test_inside_mem, inside_deviation, original_outside_mem, expected_outside_mem, test_outside_mem, outside_deviation, delta_percentage)) for dbgline in dbgmsg.splitlines(): logging.debug(dbgline) # MAIN TEST CODE ### # Process cartesian parameters vm_ref = params.get("setmem_vm_ref", "") mem_ref = params.get("setmem_mem_ref", "") flags = params.get("setmem_flags", "") status_error = "yes" == params.get("status_error", "no") old_libvirt_fail = "yes" == params.get("setmem_old_libvirt_fail", "no") quiesce_delay = int(params.get("setmem_quiesce_delay", "1")) domarg = params.get("setmem_domarg", "no") sizearg = params.get("setmem_sizearg", "no") libvirt_status = params.get("libvirt", "on") delta_percentage = float(params.get("setmem_delta_per", "10")) start_vm = "yes" == params.get("start_vm", "yes") vm_name = params.get("main_vm", "avocado-vt-vm1") paused_after_start_vm = "yes" == params.get("paused_after_start_vm", "no") manipulate_dom_before_setmem = "yes" == params.get( "manipulate_dom_before_setmem", "no") manipulate_dom_after_setmem = "yes" == params.get( "manipulate_dom_after_setmem", "no") manipulate_action = params.get("manipulate_action", "") readonly = "yes" == params.get("setmem_readonly", "no") expect_msg = params.get("setmem_err_msg") driver_packed = params.get("driver_packed", "on") with_packed = "yes" == params.get("with_packed", "no") expect_xml_line = params.get("expect_xml_line") expect_qemu_line = params.get("expect_qemu_line") vm = env.get_vm(vm_name) # Back up domain XML vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) backup_xml = vmxml.copy() if with_packed and not libvirt_version.version_compare(6, 3, 0): test.cancel("The virtio packed attribute is not supported in" " current libvirt version.") vmosxml = vmxml.os need_mkswap = False if manipulate_action in ['s3', 's4']: vm.destroy() BIOS_BIN = "/usr/share/seabios/bios.bin" if os.path.isfile(BIOS_BIN): vmosxml.loader = BIOS_BIN vmxml.os = vmosxml vmxml.sync() else: logging.error("Not find %s on host", BIOS_BIN) vmxml.set_pm_suspend(vm_name, "yes", "yes") vm.prepare_guest_agent() if manipulate_action == "s4": need_mkswap = not vm.has_swap() if need_mkswap: logging.debug("Creating swap partition") vm.create_swap_partition() memballoon_model = params.get("memballoon_model", "") if memballoon_model: vm.destroy() vmxml.del_device('memballoon', by_tag=True) memballoon_xml = vmxml.get_device_class('memballoon')() memballoon_xml.model = memballoon_model if with_packed: memballoon_xml.driver_packed = driver_packed vmxml.add_device(memballoon_xml) logging.info(memballoon_xml) vmxml.sync() vm.start() # Check guest dumpxml and qemu command in with_packed attribute if with_packed: expect_xml_line = expect_xml_line % driver_packed if utils_misc.compare_qemu_version(6, 2, 0, is_rhev=False): expect_qemu_line = expect_qemu_line % "true" else: expect_qemu_line = expect_qemu_line % driver_packed libvirt.check_dumpxml(vm, expect_xml_line) libvirt.check_qemu_cmd_line(expect_qemu_line) remove_balloon_driver = "yes" == params.get("remove_balloon_driver", "no") if remove_balloon_driver: if not vm.is_alive(): logging.error("Can't remove module as guest not running") else: session = vm.wait_for_login() cmd = "rmmod virtio_balloon" s_rmmod, o_rmmod = session.cmd_status_output(cmd) if s_rmmod != 0: logging.error( "Fail to remove module virtio_balloon in guest:\n%s", o_rmmod) session.close() # Get original data domid = vm.get_id() domuuid = vm.get_uuid() uri = vm.connect_uri if not vm.is_alive(): vm.start() session = vm.wait_for_login() if session.cmd_status('dmidecode'): # The physical memory size is in vm xml, use it when dmidecode not # supported unusable_mem = int(vmxml.max_mem) - get_vm_usable_mem(session) else: unusable_mem = vm_unusable_mem(session) original_outside_mem = vm.get_used_mem() original_inside_mem = get_vm_usable_mem(session) session.close() # Prepare VM state if not start_vm: vm.destroy() else: if paused_after_start_vm: vm.pause() old_libvirt = is_old_libvirt() if old_libvirt: logging.info("Running test on older libvirt") use_kilobytes = True else: logging.info("Running test on newer libvirt") use_kilobytes = False # Argument pattern is complex, build with dargs dargs = { 'flagstr': flags, 'use_kilobytes': use_kilobytes, 'uri': uri, 'ignore_status': True, "debug": True, 'readonly': readonly } dargs.update(make_domref(domarg, vm_ref, domid, vm_name, domuuid)) dargs.update(make_sizeref(sizearg, mem_ref, original_outside_mem)) # Prepare libvirtd status libvirtd = utils_libvirtd.Libvirtd() if libvirt_status == "off": libvirtd.stop() else: if not libvirtd.is_running(): libvirtd.start() if status_error or (old_libvirt_fail & old_libvirt): logging.info("Error Test: Expecting an error to occur!") try: memory_change = True if manipulate_dom_before_setmem: manipulate_domain(test, vm_name, manipulate_action) if manipulate_action in ['save', 'managedsave', 's4']: memory_change = False result = virsh.setmem(**dargs) status = result.exit_status if status is 0: logging.info("Waiting %d seconds for VM memory to settle", quiesce_delay) # It takes time for kernel to settle on new memory # and current clean pages is not predictable. Therefore, # extremely difficult to determine quiescence, so # sleep one second per error percent is reasonable option. time.sleep(quiesce_delay) if manipulate_dom_before_setmem: manipulate_domain(test, vm_name, manipulate_action, True) if manipulate_dom_after_setmem: manipulate_domain(test, vm_name, manipulate_action) manipulate_domain(test, vm_name, manipulate_action, True) # Recover libvirtd status if libvirt_status == "off": libvirtd.start() # Gather stats if not running error test if not status_error and not old_libvirt_fail: # Expected results for both inside and outside if remove_balloon_driver: expected_mem = original_outside_mem else: if not memory_change: expected_mem = original_inside_mem elif sizearg == "yes": expected_mem = int(dargs["sizearg"]) else: expected_mem = int(dargs["size"]) if memory_change: # Should minus unusable memory for inside memory check expected_inside_mem = expected_mem - unusable_mem expected_outside_mem = expected_mem else: expected_inside_mem = expected_mem expected_outside_mem = original_outside_mem def get_vm_mem(): """ Test results for both inside and outside :return: Get vm memory for both inside and outside """ if not memory_change: test_inside_mem = original_inside_mem test_outside_mem = original_outside_mem else: if vm.state() == "shut off": vm.start() elif vm.state() == "paused": # Make sure it's never paused vm.resume() session = vm.wait_for_login() # Actual results test_inside_mem = get_vm_usable_mem(session) session.close() test_outside_mem = vm.get_used_mem() return (test_inside_mem, test_outside_mem) # Don't care about memory comparison on error test def verify_outside_result(): _, test_outside_mem = get_vm_mem() return (cal_deviation(test_outside_mem, expected_outside_mem) <= delta_percentage) def verify_inside_result(): test_inside_mem, _ = get_vm_mem() return (cal_deviation(test_inside_mem, expected_inside_mem) <= delta_percentage) msg = "test conditions not met: " error_flag = 0 if status is not 0: error_flag = 1 msg += "Non-zero virsh setmem exit code. " if not utils_misc.wait_for(verify_outside_result, timeout=240): error_flag = 1 msg += "Outside memory deviated. " if not utils_misc.wait_for(verify_inside_result, timeout=240): error_flag = 1 msg += "Inside memory deviated. " test_inside_mem, test_outside_mem = get_vm_mem() print_debug_stats(original_inside_mem, original_outside_mem, test_inside_mem, test_outside_mem, expected_outside_mem, expected_inside_mem, delta_percentage, unusable_mem) if error_flag: test.fail(msg) elif not status_error and old_libvirt_fail: if status is 0: if old_libvirt: test.fail("Error test did not result in an error") else: if not old_libvirt: test.fail("Newer libvirt failed when it should not") else: # Verify an error test resulted in error if status is 0: test.fail("Error test did not result in an error") if expect_msg: libvirt.check_result(result, expect_msg.split(';')) finally: if need_mkswap: vm.cleanup_swap() vm.destroy() backup_xml.sync()
def run(test, params, env): """ Test memory management of nvdimm """ vm_name = params.get('main_vm') check = params.get('check', '') qemu_checks = params.get('qemu_checks', '') def mount_hugepages(page_size): """ To mount hugepages :param page_size: unit is kB, it can be 4,2048,1048576,etc """ if page_size == 4: perm = "" else: perm = "pagesize=%dK" % page_size tlbfs_status = utils_misc.is_mounted("hugetlbfs", "/dev/hugepages", "hugetlbfs") if tlbfs_status: utils_misc.umount("hugetlbfs", "/dev/hugepages", "hugetlbfs") utils_misc.mount("hugetlbfs", "/dev/hugepages", "hugetlbfs", perm) def setup_hugepages(page_size=2048, shp_num=4000): """ To setup hugepages :param page_size: unit is kB, it can be 4,2048,1048576,etc :param shp_num: number of hugepage, string type """ mount_hugepages(page_size) utils_memory.set_num_huge_pages(shp_num) config.hugetlbfs_mount = ["/dev/hugepages"] utils_libvirtd.libvirtd_restart() def restore_hugepages(page_size=4): """ To recover hugepages :param page_size: unit is kB, it can be 4,2048,1048576,etc """ mount_hugepages(page_size) config.restore() utils_libvirtd.libvirtd_restart() def create_mbxml(): """ Create memoryBacking xml for test """ mb_params = {k: v for k, v in params.items() if k.startswith('mbxml_')} logging.debug(mb_params) mb_xml = vm_xml.VMMemBackingXML() mb_xml.xml = "<memoryBacking></memoryBacking>" for attr_key in mb_params: val = mb_params[attr_key] logging.debug('Set mb params') setattr(mb_xml, attr_key.replace('mbxml_', ''), eval(val) if ':' in val else val) logging.debug(mb_xml) return mb_xml.copy() def create_cpuxml(): """ Create cpu xml for test """ cpu_params = { k: v for k, v in params.items() if k.startswith('cpuxml_') } logging.debug(cpu_params) cpu_xml = vm_xml.VMCPUXML() cpu_xml.xml = "<cpu><numa/></cpu>" if 'cpuxml_numa_cell' in cpu_params: cpu_params['cpuxml_numa_cell'] = cpu_xml.dicts_to_cells( eval(cpu_params['cpuxml_numa_cell'])) for attr_key in cpu_params: val = cpu_params[attr_key] logging.debug('Set cpu params') setattr(cpu_xml, attr_key.replace('cpuxml_', ''), eval(val) if ':' in val else val) logging.debug(cpu_xml) return cpu_xml.copy() def create_dimm_xml(**mem_param): """ Create xml of dimm memory device """ mem_xml = utils_hotplug.create_mem_xml( pg_size=int(mem_param['source_pagesize']), tg_size=mem_param['target_size'], tg_sizeunit=mem_param['target_size_unit'], tg_node=mem_param['target_node'], mem_model="dimm") logging.debug(mem_xml) return mem_xml.copy() huge_pages = [ ast.literal_eval(x) for x in params.get("huge_pages", "").split() ] config = utils_config.LibvirtQemuConfig() page_size = params.get("page_size") discard = params.get("discard") setup_hugepages(int(page_size)) bkxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) try: vm = env.get_vm(vm_name) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Set cpu according to params cpu_xml = create_cpuxml() vmxml.cpu = cpu_xml # Set memoryBacking according to params mb_xml = create_mbxml() vmxml.mb = mb_xml # Update other vcpu, memory info according to params update_vm_args = { k: params[k] for k in params if k.startswith('setvm_') } logging.debug(update_vm_args) for key, value in list(update_vm_args.items()): attr = key.replace('setvm_', '') logging.debug('Set %s = %s', attr, value) setattr(vmxml, attr, int(value) if value.isdigit() else value) vmxml.sync() logging.debug(virsh.dumpxml(vm_name)) # hugepages setting if huge_pages: membacking = vm_xml.VMMemBackingXML() hugepages = vm_xml.VMHugepagesXML() pagexml_list = [] for i in range(len(huge_pages)): pagexml = hugepages.PageXML() pagexml.update(huge_pages[i]) pagexml_list.append(pagexml) hugepages.pages = pagexml_list membacking.hugepages = hugepages vmxml.mb = membacking logging.debug(virsh.dumpxml(vm_name)) if check == "mem_dev" or check == "hot_plug": # Add dimm mem device to vm xml dimm_params = { k.replace('dimmxml_', ''): v for k, v in params.items() if k.startswith('dimmxml_') } dimm_xml = create_dimm_xml(**dimm_params) if params.get('dimmxml_mem_access'): dimm_xml.mem_access = dimm_params['mem_access'] vmxml.add_device(dimm_xml) logging.debug(virsh.dumpxml(vm_name)) test_vm = env.get_vm(vm_name) vmxml.sync() if test_vm.is_alive(): test_vm.destroy() virsh.start(vm_name, debug=True, ignore_status=False) test_vm.wait_for_login() if check == 'numa_cell' or check == 'mem_dev': # Check qemu command line one by one logging.debug("enter check") if discard == 'yes': libvirt.check_qemu_cmd_line(qemu_checks) elif libvirt.check_qemu_cmd_line(qemu_checks, True): test.fail("The unexpected [%s] exist in qemu cmd" % qemu_checks) if check == 'hot_plug': # Add dimm device to vm xml dimm_params2 = { k.replace('dimmxml2_', ''): v for k, v in params.items() if k.startswith('dimmxml2_') } dimm_xml2 = create_dimm_xml(**dimm_params2) if params.get('dimmxml2_mem_access'): dimm_xml2.mem_access = dimm_params2['mem_access'] result = virsh.attach_device(vm_name, dimm_xml2.xml, debug=True) ori_devices = vm_xml.VMXML.new_from_dumpxml(vm_name).get_devices( 'memory') logging.debug('Starts with %d memory devices', len(ori_devices)) result = virsh.attach_device(vm_name, dimm_xml2.xml, debug=True) libvirt.check_exit_status(result) # After attach, there should be a memory device added devices_after_attach = vm_xml.VMXML.new_from_dumpxml( vm_name).get_devices('memory') logging.debug('After detach, vm has %d memory devices', len(devices_after_attach)) if len(ori_devices) != len(devices_after_attach) - 1: test.fail( 'Number of memory devices after attach is %d, should be %d' % (len(devices_after_attach), len(ori_devices) + 1)) alive_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) dimm_detach = alive_vmxml.get_devices('memory')[-1] logging.debug(dimm_detach) # Hot-unplug dimm device result = virsh.detach_device(vm_name, dimm_detach.xml, debug=True) libvirt.check_exit_status(result) left_devices = vm_xml.VMXML.new_from_dumpxml(vm_name).get_devices( 'memory') logging.debug(left_devices) if len(left_devices) != len(ori_devices): time.sleep(60) test.fail( 'Number of memory devices after detach is %d, should be %d' % (len(left_devices), len(ori_devices))) except virt_vm.VMStartError as e: test.fail("VM failed to start." "Error: %s" % str(e)) finally: if vm.is_alive(): vm.destroy(gracefully=False) bkxml.sync()
def run(test, params, env): """ Test extended TSEG on Q35 machine types <smm state='on'> <tseg unit='MiB'>48</tseg> </smm> Steps: 1) Edit VM xml for smm or tseg sub element 2) Verify if Guest can boot as expected 3) On i440 machine types, the property does not support. On Q35 machine types, both Seabios and OVMF Guest can bootup """ vm_name = params.get("main_vm", "") vm = env.get_vm(vm_name) smm_state = params.get("smm_state", "off") unit = params.get("tseg_unit") size = params.get("tseg_size") boot_type = params.get("boot_type", "") loader_type = params.get("loader_type") loader = params.get("loader") err_msg = params.get("error_msg", "") vm_arch_name = params.get("vm_arch_name", "x86_64") status_error = ("yes" == params.get("status_error", "no")) if not libvirt_version.version_compare(4, 5, 0): test.cancel("TSEG does not support in " "current libvirt version") if (boot_type == "seabios" and not utils_package.package_install('seabios-bin')): test.cancel("Failed to install Seabios") if (boot_type == 'ovmf' and not utils_package.package_install('OVMF')): test.cancel("Failed to install OVMF") # Back VM XML v_xml_backup = vm_xml.VMXML.new_from_dumpxml(vm_name) v_xml = vm_xml.VMXML.new_from_dumpxml(vm_name) try: # Specify boot loader for OVMF if boot_type == 'ovmf': os_xml = v_xml.os os_xml.loader_type = loader_type os_xml.loader = loader os_xml.loader_readonly = "yes" v_xml.os = os_xml try: features_xml = v_xml.features except xcepts.LibvirtXMLNotFoundError: if vm_arch_name == 'x86_64': # ACPI is required for UEFI on x86_64 v_xml.xmltreefile.create_by_xpath("/features/acpi") features_xml = v_xml.features else: features_xml = vm_xml.VMFeaturesXML() features_xml.smm = smm_state if unit and size: features_xml.smm_tseg_unit = unit features_xml.smm_tseg = size v_xml.features = features_xml logging.debug("New VM XML is:\n%s", v_xml) ret = virsh.define(v_xml.xml) utlv.check_result(ret, expected_fails=err_msg) # Check result if not status_error: vm.start() if unit and size: # If tseg unit is KiB, convert it to MiB # as vm dumpxml convert it automatically if unit == 'KiB': unit, size = unify_to_MiB(unit, size) expect_line = "<tseg unit=\"%s\">%s</tseg>" % (unit, size) utlv.check_dumpxml(vm, expect_line) # Qemu cmdline use mbytes unit, tseg_mbytes = unify_to_MiB(unit, size) expect_line = '-global mch.extended-tseg-mbytes=%s' % size utlv.check_qemu_cmd_line(expect_line) finally: logging.debug("Restore the VM XML") if vm.is_alive(): vm.destroy() # OVMF enable nvram by default v_xml_backup.sync(options="--nvram")
def run(test, params, env): """ Test vm features """ vm_name = params.get('main_vm') vm = env.get_vm(vm_name) hyperv_attr = eval(params.get('hyperv_attr', '{}')) pmu_attr = eval(params.get('pmu_attr', '{}')) pvspinlock_attr = eval(params.get('pvspinlock_attr', '{}')) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bkxml = vmxml.copy() try: # Set hyperv attribs if there're attribs to set if hyperv_attr: if set(hyperv_attr.keys()).intersection(('tlbflush', 'frequencies', 'reenlightenment')): # Compare libvirt version to decide if test is valid if not libvirt_version.version_compare(5, 0, 0): test.cancel('This version of libvirt does\'nt support ' 'the setting: %r' % hyperv_attr) vm_xml.VMXML.set_vm_features( vm_name, **{'hyperv_%s_state' % key: value for key, value in hyperv_attr.items()} ) if pmu_attr: vm_xml.VMXML.set_vm_features( vm_name, **{'pmu': pmu_attr['pmu']} ) if pvspinlock_attr: vm_xml.VMXML.set_vm_features( vm_name, **{'pvspinlock_state': pvspinlock_attr['pvspinlock_state']} ) # Test vm start try: ret = virsh.start(vm_name, debug=True) libvirt.check_exit_status(ret) except exceptions.TestFail as details: if re.search(r"host doesn\'t support paravirtual spinlocks", str(details)): test.cancel("This host doesn't support paravirtual spinlocks.") else: test.fail('VM failed to start:\n%s' % details) vm.wait_for_login().close() if hyperv_attr: # Check hyperv settings in qemu command line for attr in hyperv_attr: if libvirt_version.version_compare(5, 6, 0): exp_str = 'hv-' + attr else: exp_str = 'hv_' + attr if hyperv_attr[attr] == 'off': if libvirt.check_qemu_cmd_line(exp_str, True): test.fail("Unexpected '%s' was found in " "qemu command line" % exp_str) else: libvirt.check_qemu_cmd_line(exp_str) if pmu_attr: libvirt.check_qemu_cmd_line('pmu=' + pmu_attr['pmu']) if pvspinlock_attr: if distro.detect().name == 'rhel' and int(distro.detect().version) < 8: if pvspinlock_attr['pvspinlock_state'] == 'on': exp_str = r'\+kvm_pv_unhalt' else: exp_str = r'\-kvm_pv_unhalt' else: exp_str = 'kvm-pv-unhalt=' + pvspinlock_attr['pvspinlock_state'] libvirt.check_qemu_cmd_line(exp_str) finally: bkxml.sync()
def run(test, params, env): """ Test memory management of nvdimm """ vm_name = params.get('main_vm') nvdimm_file = params.get('nvdimm_file') check = params.get('check', '') status_error = "yes" == params.get('status_error', 'no') error_msg = params.get('error_msg', '') qemu_checks = params.get('qemu_checks', '').split('`') test_str = 'This is a test' def check_boot_config(session): """ Check /boot/config-$KVER file """ check_list = [ 'CONFIG_LIBNVDIMM=m', 'CONFIG_BLK_DEV_PMEM=m', 'CONFIG_ACPI_NFIT=m' ] current_boot = session.cmd('uname -r').strip() content = session.cmd('cat /boot/config-%s' % current_boot).strip() for item in check_list: if item in content: logging.info(item) else: logging.error(item) test.fail('/boot/config content not correct') def check_file_in_vm(session, path, expect=True): """ Check whether the existance of file meets expectation """ exist = session.cmd_status('ls %s' % path) logging.debug(exist) exist = True if exist == 0 else False status = '' if exist else 'NOT' logging.info('File %s does %s exist', path, status) if exist != expect: err_msg = 'Existance doesn\'t meet expectation: %s ' % path if expect: err_msg += 'should exist.' else: err_msg += 'should not exist' test.fail(err_msg) def create_cpuxml(): """ Create cpu xml for test """ cpu_params = { k: v for k, v in params.items() if k.startswith('cpuxml_') } logging.debug(cpu_params) cpu_xml = vm_xml.VMCPUXML() cpu_xml.xml = "<cpu><numa/></cpu>" for attr_key in cpu_params: val = cpu_params[attr_key] logging.debug('Set cpu params') setattr(cpu_xml, attr_key.replace('cpuxml_', ''), eval(val) if ':' in val else val) logging.debug(cpu_xml) return cpu_xml.copy() def create_nvdimm_xml(**mem_param): """ Create xml of nvdimm memory device """ mem_xml = utils_hotplug.create_mem_xml( tg_size=mem_param['target_size'], mem_addr={'slot': mem_param['address_slot']}, tg_sizeunit=mem_param['target_size_unit'], tg_node=mem_param['target_node'], mem_discard=mem_param.get('discard'), mem_model="nvdimm", lb_size=mem_param.get('label_size'), lb_sizeunit=mem_param.get('label_size_unit'), mem_access=mem_param['mem_access']) source_xml = memory.Memory.Source() source_xml.path = mem_param['source_path'] mem_xml.source = source_xml logging.debug(mem_xml) return mem_xml.copy() def check_nvdimm_file(file_name): """ check if the file exists in nvdimm memory device :param file_name: the file name in nvdimm device """ vm_session = vm.wait_for_login() if test_str not in vm_session.cmd('cat /mnt/%s ' % file_name): test.fail('"%s" should be in output' % test_str) bkxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) if 'ppc64le' in platform.machine().lower(): if not libvirt_version.version_compare(6, 2, 0): test.cancel('Libvirt version should be > 6.2.0' ' to support nvdimm on pseries') try: vm = env.get_vm(vm_name) # Create nvdimm file on the host process.run('truncate -s 512M %s' % nvdimm_file, verbose=True) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Set cpu according to params cpu_xml = create_cpuxml() vmxml.cpu = cpu_xml # Update other vcpu, memory info according to params update_vm_args = { k: params[k] for k in params if k.startswith('setvm_') } logging.debug(update_vm_args) for key, value in list(update_vm_args.items()): attr = key.replace('setvm_', '') logging.debug('Set %s = %s', attr, value) setattr(vmxml, attr, int(value) if value.isdigit() else value) logging.debug(virsh.dumpxml(vm_name)) # Add an nvdimm mem device to vm xml nvdimm_params = { k.replace('nvdimmxml_', ''): v for k, v in params.items() if k.startswith('nvdimmxml_') } nvdimm_xml = create_nvdimm_xml(**nvdimm_params) vmxml.add_device(nvdimm_xml) if check in ['ppc_no_label', 'discard']: result = virsh.define(vmxml.xml, debug=True) libvirt.check_result(result, expected_fails=[error_msg]) return vmxml.sync() logging.debug(virsh.dumpxml(vm_name)) virsh.start(vm_name, debug=True, ignore_status=False) # Check qemu command line one by one map(libvirt.check_qemu_cmd_line, qemu_checks) alive_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) # Check if the guest support NVDIMM: # check /boot/config-$KVER file vm_session = vm.wait_for_login() check_boot_config(vm_session) # check /dev/pmem0 existed inside guest check_file_in_vm(vm_session, '/dev/pmem0') if check == 'back_file': # Create a file system on /dev/pmem0 if platform.platform().count('el8'): vm_session.cmd('mkfs.xfs -f /dev/pmem0 -m reflink=0') else: vm_session.cmd('mkfs.xfs -f /dev/pmem0') vm_session.cmd('mount -o dax /dev/pmem0 /mnt') vm_session.cmd('echo \"%s\" >/mnt/foo' % test_str) vm_session.cmd('umount /mnt') vm_session.close() # Shutdown the guest, then start it, remount /dev/pmem0, # check if the test file is still on the file system vm.destroy() vm.start() vm_session = vm.wait_for_login() vm_session.cmd('mount -o dax /dev/pmem0 /mnt') if test_str not in vm_session.cmd('cat /mnt/foo'): test.fail('\"%s\" should be in /mnt/foo' % test_str) # From the host, check the file has changed: host_output = process.run('hexdump -C /tmp/nvdimm', shell=True, verbose=True).stdout_text if test_str not in host_output: test.fail('\"%s\" should be in output' % test_str) # Shutdown the guest, and edit the xml, # include: access='private' vm_session.close() vm.destroy() vm_devices = vmxml.devices nvdimm_device = vm_devices.by_device_tag('memory')[0] nvdimm_index = vm_devices.index(nvdimm_device) vm_devices[nvdimm_index].mem_access = 'private' vmxml.devices = vm_devices vmxml.sync() # Login to the guest, mount the /dev/pmem0 and . # create a file: foo-private vm.start() vm_session = vm.wait_for_login() libvirt.check_qemu_cmd_line('mem-path=/tmp/nvdimm,share=no') private_str = 'This is a test for foo-private' vm_session.cmd('mount -o dax /dev/pmem0 /mnt/') file_private = 'foo-private' vm_session.cmd("echo '%s' >/mnt/%s" % (private_str, file_private)) if private_str not in vm_session.cmd('cat /mnt/%s' % file_private): test.fail('"%s" should be in output' % private_str) # Shutdown the guest, then start it, # check the file: foo-private is no longer existed vm_session.close() vm.destroy() vm.start() vm_session = vm.wait_for_login() vm_session.cmd('mount -o dax /dev/pmem0 /mnt/') if file_private in vm_session.cmd('ls /mnt/'): test.fail('%s should not exist, for it was ' 'created when access=private' % file_private) if check == 'label_back_file': # Create an xfs file system on /dev/pmem0 if platform.platform().count('el8'): vm_session.cmd( 'mkfs.xfs -f -b size=4096 /dev/pmem0 -m reflink=0') else: vm_session.cmd('mkfs.xfs -f -b size=4096 /dev/pmem0') # Mount the file system with DAX enabled for page cache bypass output = vm_session.cmd_output('mount -o dax /dev/pmem0 /mnt/') logging.info(output) # Create a file on the nvdimm device. test_str = 'This is a test with label' vm_session.cmd('echo "%s" >/mnt/foo-label' % test_str) if test_str not in vm_session.cmd('cat /mnt/foo-label '): test.fail('"%s" should be in the output of cat cmd' % test_str) # Reboot the guest, and remount the nvdimm device in the guest. # Check the file foo-label is exited vm_session.close() virsh.reboot(vm_name, debug=True) vm_session = vm.wait_for_login() vm_session.cmd('mount -o dax /dev/pmem0 /mnt') if test_str not in vm_session.cmd('cat /mnt/foo-label '): test.fail('"%s" should be in output' % test_str) if params.get('check_life_cycle', 'no') == 'yes': virsh.managedsave(vm_name, ignore_status=False, debug=True) vm.start() check_nvdimm_file('foo-label') vm_s1 = vm_name + ".s1" virsh.save(vm_name, vm_s1, ignore_status=False, debug=True) virsh.restore(vm_s1, ignore_status=False, debug=True) check_nvdimm_file('foo-label') virsh.snapshot_create_as(vm_name, vm_s1, ignore_status=False, debug=True) virsh.snapshot_revert(vm_name, vm_s1, ignore_status=False, debug=True) virsh.snapshot_delete(vm_name, vm_s1, ignore_status=False, debug=True) if check == 'hot_plug': # Create file for 2nd nvdimm device nvdimm_file_2 = params.get('nvdimm_file_2') process.run('truncate -s 512M %s' % nvdimm_file_2) # Add 2nd nvdimm device to vm xml nvdimm2_params = { k.replace('nvdimmxml2_', ''): v for k, v in params.items() if k.startswith('nvdimmxml2_') } nvdimm2_xml = create_nvdimm_xml(**nvdimm2_params) ori_devices = vm_xml.VMXML.new_from_dumpxml(vm_name).get_devices( 'memory') logging.debug('Starts with %d memory devices', len(ori_devices)) result = virsh.attach_device(vm_name, nvdimm2_xml.xml, debug=True) libvirt.check_exit_status(result) # After attach, there should be an extra memory device devices_after_attach = vm_xml.VMXML.new_from_dumpxml( vm_name).get_devices('memory') logging.debug('After detach, vm has %d memory devices', len(devices_after_attach)) if len(ori_devices) != len(devices_after_attach) - 1: test.fail( 'Number of memory devices after attach is %d, should be %d' % (len(devices_after_attach), len(ori_devices) + 1)) time.sleep(5) check_file_in_vm(vm_session, '/dev/pmem1') nvdimm_detach = alive_vmxml.get_devices('memory')[-1] logging.debug(nvdimm_detach) # Hot-unplug nvdimm device result = virsh.detach_device(vm_name, nvdimm_detach.xml, debug=True) libvirt.check_exit_status(result) vm_session.close() vm_session = vm.wait_for_login() virsh.dumpxml(vm_name, debug=True) left_devices = vm_xml.VMXML.new_from_dumpxml(vm_name).get_devices( 'memory') logging.debug(left_devices) if len(left_devices) != len(ori_devices): test.fail( 'Number of memory devices after detach is %d, should be %d' % (len(left_devices), len(ori_devices))) time.sleep(5) check_file_in_vm(vm_session, '/dev/pmem1', expect=False) finally: if vm.is_alive(): vm.destroy(gracefully=False) bkxml.sync() os.remove(nvdimm_file)
def run(test, params, env): """ Test misc tests of virtual cpu features 1) check dumpxml after snapshot-create/revert 2) check vendor_id 3) check maximum vcpus with topology settings :param test: test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ def update_cpu_xml(): """ Update cpu xml for test """ vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Create cpu xml for test if vmxml.xmltreefile.find('cpu'): cpu_xml = vmxml.cpu else: cpu_xml = vm_xml.VMCPUXML() if customize_cpu_features: for idx in range(len(cpu_xml.get_feature_list()) - 1, -1, -1): cpu_xml.remove_feature(idx) domcapa_xml = domcapability_xml.DomCapabilityXML() features = domcapa_xml.get_additional_feature_list( 'host-model', ignore_features=None) for feature in features: for feature_name, feature_policy in feature.items(): # For host-passthrough mode, adding "invtsc" requires # more settings, so it will be ignored. if feature_name != "invtsc": cpu_xml.add_feature(feature_name, feature_policy) if cpu_mode: cpu_xml.mode = cpu_mode if cpu_vendor_id: cpu_xml.vendor_id = cpu_vendor_id # Update vm's cpu vmxml.cpu = cpu_xml vmxml.sync() if vcpu_max: if with_topology: vm_xml.VMXML.set_vm_vcpus(vm_name, int(vcpu_max), cores=int(vcpu_max), sockets=1, threads=1, add_topology=with_topology, topology_correction=with_topology) else: vm_xml.VMXML.set_vm_vcpus(vm_name, int(vcpu_max)) def do_snapshot(vm_name, expected_str): """ Run snapshot related commands: snapshot-create-as, snapshot-list snapshot-dumpxml, snapshot-revert :param vm_name: vm name :param expected_str: expected string in snapshot-dumpxml :raise: test.fail if virsh command failed """ snapshot_name = vm_name + "-snap" virsh_dargs = {'debug': True} cmd_result = virsh.snapshot_create_as(vm_name, snapshot_name, **virsh_dargs) libvirt.check_exit_status(cmd_result) try: snapshots = virsh.snapshot_list(vm_name, **virsh_dargs) except process.CmdError: test.fail("Failed to get snapshots list for %s" % vm_name) if snapshot_name not in snapshots: test.fail("The snapshot '%s' was not in snapshot-list." % snapshot_name) cmd_result = virsh.snapshot_dumpxml(vm_name, snapshot_name, **virsh_dargs) libvirt.check_result(cmd_result, expected_match=expected_str) cmd_result = virsh.snapshot_revert(vm_name, "", "--current", **virsh_dargs) libvirt.check_exit_status(cmd_result) def check_feature_list(vm, original_dict): """ Compare new cpu feature list and original cpu :param vm: VM object :original_dict: Cpu feature dict , {"name1":"policy1","name2":"policy2"} """ new_cpu_xml = vm_xml.VMXML.new_from_dumpxml(vm.name).cpu new_feature_dict = new_cpu_xml.get_dict_type_feature() if new_feature_dict != original_dict: test.fail('CPU feature lists are different, original is :%s,' ' new is %s:' % (original_dict, new_feature_dict)) libvirt_version.is_libvirt_feature_supported(params) vm_name = params.get('main_vm') vm = env.get_vm(vm_name) cpu_mode = params.get('cpu_mode') vcpu_max = params.get('vcpu_max') expected_str_before_startup = params.get("expected_str_before_startup") expected_str_after_startup = params.get("expected_str_after_startup") test_operations = params.get("test_operations") check_vendor_id = "yes" == params.get("check_vendor_id", "no") virsh_edit_cmd = params.get("virsh_edit_cmd") with_topology = "yes" == params.get("with_topology", "no") status_error = "yes" == params.get("status_error", "no") err_msg = params.get("err_msg") cpu_vendor_id = None expected_qemuline = None cmd_in_guest = params.get("cmd_in_guest") customize_cpu_features = "yes" == params.get("customize_cpu_features", "no") bkxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) managed_save_file = "/var/lib/libvirt/qemu/save/%s.save" % vm_name try: if check_vendor_id: output = virsh.capabilities(debug=True) host_vendor = re.findall(r'<vendor>(\w+)<', output)[0] cpu_vendor_id = 'GenuineIntel' if host_vendor != "Intel": cpu_vendor_id = 'AuthenticAMD' logging.debug("Set cpu vendor_id to %s on this host.", cpu_vendor_id) expected_qemuline = "vendor=" + cpu_vendor_id cmd_in_guest = ("cat /proc/cpuinfo | grep vendor_id | grep {}". format(cpu_vendor_id)) # Update xml for test update_cpu_xml() vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) logging.debug("Pre-test xml is %s", vmxml.xmltreefile) cpu_xml = vmxml.cpu feature_dict = cpu_xml.get_dict_type_feature() if expected_str_before_startup: libvirt.check_dumpxml(vm, expected_str_before_startup) if test_operations: for action in test_operations.split(","): if action == "do_snapshot": do_snapshot(vm_name, expected_str_before_startup) if virsh_edit_cmd: status = libvirt.exec_virsh_edit(vm_name, virsh_edit_cmd.split(",")) if status == status_error: test.fail("Virsh edit got unexpected result.") # Check if vm could start successfully if not status_error: result = virsh.start(vm_name, debug=True) libvirt.check_exit_status(result) if expected_str_after_startup: libvirt.check_dumpxml(vm, expected_str_after_startup) if expected_qemuline: libvirt.check_qemu_cmd_line(expected_qemuline) if cmd_in_guest: vm_session = vm.wait_for_login() status, output = vm_session.cmd_status_output(cmd_in_guest) if status: vm_session.close() test.fail("Failed to run '{}' in vm with " "messages:\n{}".format(cmd_in_guest, output)) vm_session.close() if cpu_mode == 'maximum': check_vm_cpu_model(output.strip(), cmd_in_guest, test) # Add case: Check cpu xml after domain Managedsaved and restored if test_operations: for item in test_operations.split(','): if item == "managedsave_restore": # (1)Domain Manage saved virsh.managedsave(vm_name, ignore_status=False, debug=True) check_feature_list(vm, feature_dict) # (2)Domain Restore virsh.restore(managed_save_file, ignore_status=False, debug=True) # (5)Check mode and feature list here libvirt.check_dumpxml(vm, cpu_mode) check_feature_list(vm, feature_dict) finally: logging.debug("Recover test environment") if os.path.exists(managed_save_file): virsh.managedsave_remove(vm_name, debug=True) if vm.is_alive(): vm.destroy() libvirt.clean_up_snapshots(vm_name, domxml=bkxml) bkxml.sync()
def run(test, params, env): """ Test misc tests of virtual cpu features 1) check dumpxml after snapshot-create/revert 2) check vendor_id 3) check maximum vcpus with topology settings :param test: test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ def update_cpu_xml(): """ Update cpu xml for test """ vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Create cpu xml for test if vmxml.xmltreefile.find('cpu'): cpu_xml = vmxml.cpu else: cpu_xml = vm_xml.VMCPUXML() if cpu_mode: cpu_xml.mode = cpu_mode if cpu_vendor_id: cpu_xml.vendor_id = cpu_vendor_id # Update vm's cpu vmxml.cpu = cpu_xml vmxml.sync() if vcpu_max: if with_topology: vm_xml.VMXML.set_vm_vcpus(vm_name, int(vcpu_max), cores=int(vcpu_max), sockets=1, threads=1, add_topology=with_topology, topology_correction=with_topology) else: vm_xml.VMXML.set_vm_vcpus(vm_name, int(vcpu_max)) def do_snapshot(vm_name, expected_str): """ Run snapshot related commands: snapshot-create-as, snapshot-list snapshot-dumpxml, snapshot-revert :param vm_name: vm name :param expected_str: expected string in snapshot-dumpxml :raise: test.fail if virsh command failed """ snapshot_name = vm_name + "-snap" virsh_dargs = {'debug': True} cmd_result = virsh.snapshot_create_as(vm_name, snapshot_name, **virsh_dargs) libvirt.check_exit_status(cmd_result) try: snapshots = virsh.snapshot_list(vm_name, **virsh_dargs) except process.CmdError: test.fail("Failed to get snapshots list for %s" % vm_name) if snapshot_name not in snapshots: test.fail("The snapshot '%s' was not in snapshot-list." % snapshot_name) cmd_result = virsh.snapshot_dumpxml(vm_name, snapshot_name, **virsh_dargs) libvirt.check_result(cmd_result, expected_match=expected_str) cmd_result = virsh.snapshot_revert(vm_name, "", "--current", **virsh_dargs) libvirt.check_exit_status(cmd_result) libvirt_version.is_libvirt_feature_supported(params) vm_name = params.get('main_vm') vm = env.get_vm(vm_name) cpu_mode = params.get('cpu_mode') vcpu_max = params.get('vcpu_max') expected_str_before_startup = params.get("expected_str_before_startup") expected_str_after_startup = params.get("expected_str_after_startup") test_operations = params.get("test_operations") check_vendor_id = "yes" == params.get("check_vendor_id", "no") virsh_edit_cmd = params.get("virsh_edit_cmd") with_topology = "yes" == params.get("with_topology", "no") status_error = "yes" == params.get("status_error", "no") err_msg = params.get("err_msg") cpu_vendor_id = None expected_qemuline = None cmd_in_guest = params.get("cmd_in_guest") bkxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) try: if check_vendor_id: output = virsh.capabilities(debug=True) host_vendor = re.findall(r'<vendor>(\w+)<', output)[0] cpu_vendor_id = 'GenuineIntel' if host_vendor != "Intel": cpu_vendor_id = 'AuthenticAMD' logging.debug("Set cpu vendor_id to %s on this host.", cpu_vendor_id) expected_qemuline = "vendor=" + cpu_vendor_id cmd_in_guest = ("cat /proc/cpuinfo | grep vendor_id | grep {}". format(cpu_vendor_id)) # Update xml for test update_cpu_xml() vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) logging.debug("Pre-test xml is %s", vmxml.xmltreefile) if expected_str_before_startup: libvirt.check_dumpxml(vm, expected_str_before_startup) if test_operations: for action in test_operations.split(","): if action == "do_snapshot": do_snapshot(vm_name, expected_str_before_startup) if virsh_edit_cmd: status = libvirt.exec_virsh_edit(vm_name, virsh_edit_cmd.split(",")) if status == status_error: test.fail("Virsh edit got unexpected result.") # Check if vm could start successfully if not status_error: result = virsh.start(vm_name, debug=True) libvirt.check_exit_status(result) if expected_str_after_startup: libvirt.check_dumpxml(vm, expected_str_after_startup) if expected_qemuline: libvirt.check_qemu_cmd_line(expected_qemuline) if cmd_in_guest: vm_session = vm.wait_for_login() status, output = vm_session.cmd_status_output(cmd_in_guest) if status: vm_session.close() test.fail("Failed to run '{}' in vm with " "messages:\n{}".format(cmd_in_guest, output)) vm_session.close() if cpu_mode == 'maximum': check_vm_cpu_model(output.strip(), cmd_in_guest, test) finally: logging.debug("Recover test environment") if vm.is_alive(): vm.destroy() libvirt.clean_up_snapshots(vm_name, domxml=bkxml) bkxml.sync()
def run(test, params, env): """ Test misc tests of virtual cpu features 1) check dumpxml after snapshot-create/revert :param test: test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ def do_snapshot(vm_name, expected_str): """ Run snapshot related commands: snapshot-create-as, snapshot-list snapshot-dumpxml, snapshot-revert :param vm_name: vm name :param expected_str: expected string in snapshot-dumpxml :raise: test.fail if virsh command failed """ snapshot_name = vm_name + "-snap" virsh_dargs = {'debug': True} cmd_result = virsh.snapshot_create_as(vm_name, snapshot_name, **virsh_dargs) libvirt.check_exit_status(cmd_result) try: snapshots = virsh.snapshot_list(vm_name, **virsh_dargs) except process.CmdError: test.fail("Failed to get snapshots list for %s" % vm_name) if snapshot_name not in snapshots: test.fail("The snapshot '%s' was not in snapshot-list." % snapshot_name) cmd_result = virsh.snapshot_dumpxml(vm_name, snapshot_name, **virsh_dargs) libvirt.check_result(cmd_result, expected_match=expected_str) cmd_result = virsh.snapshot_revert(vm_name, "", "--current", **virsh_dargs) libvirt.check_exit_status(cmd_result) vm_name = params.get('main_vm') vm = env.get_vm(vm_name) cpu_mode = params.get('cpu_mode') cpu_vendor_id = params.get("vendor_id") expected_str_before_startup = params.get("expected_str_before_startup") expected_str_after_startup = params.get("expected_str_after_startup") expected_qemuline = params.get("expected_qemuline") cmd_in_guest = params.get("cmd_in_guest") test_operations = params.get("test_operations") status_error = "yes" == params.get("status_error", "no") err_msg = params.get("err_msg") bkxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) try: if cpu_vendor_id: output = virsh.capabilities(debug=True) host_vendor = re.findall(r'<vendor>(\w+)<', output)[0] if not re.search(host_vendor, cpu_vendor_id, re.IGNORECASE): test.cancel("Not supported cpu vendor_id {} on this host." .format(cpu_vendor_id)) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Create cpu xml for test if vmxml.xmltreefile.find('cpu'): cpu_xml = vmxml.cpu else: cpu_xml = vm_xml.VMCPUXML() if cpu_mode: cpu_xml.mode = cpu_mode if cpu_vendor_id: cpu_xml.vendor_id = cpu_vendor_id # Update vm's cpu vmxml.cpu = cpu_xml vmxml.sync() if expected_str_before_startup: libvirt.check_dumpxml(vm, expected_str_before_startup) if test_operations: for action in test_operations.split(","): if action == "do_snapshot": do_snapshot(vm_name, expected_str_before_startup) # Check if vm could start successfully result = virsh.start(vm_name, debug=True) libvirt.check_exit_status(result) if expected_str_after_startup: libvirt.check_dumpxml(vm, expected_str_after_startup) if expected_qemuline: libvirt.check_qemu_cmd_line(expected_qemuline) if cmd_in_guest: vm_session = vm.wait_for_login() if vm_session.cmd_status(cmd_in_guest): vm_session.close() test.fail("Failed to run '%s' in vm." % cmd_in_guest) vm_session.close() finally: logging.debug("Recover test environment") if vm.is_alive(): vm.destroy() libvirt.clean_up_snapshots(vm_name, domxml=bkxml) bkxml.sync()
def run(test, params, env): """ Test hpt resizing """ vm_name = params.get('main_vm') vm = env.get_vm(vm_name) status_error = 'yes' == params.get('status_error', 'no') error_msg = eval(params.get('error_msg', '[]')) hpt_attrs = eval(params.get('hpt_attrs', '{}')) hpt_order_path = params.get('hpt_order_path', '') cpu_attrs = eval(params.get('cpu_attrs', '{}')) numa_cell = eval(params.get('numa_cell', '{}')) hugepage = 'yes' == params.get('hugepage', 'no') maxpagesize = int(params.get('maxpagesize', 0)) check_hp = 'yes' == params.get('check_hp', 'no') qemu_check = params.get('qemu_check', '') skip_p8 = 'yes' == params.get('skip_p8', 'no') def set_hpt(vmxml, sync, **attrs): """ Set resizing value to vm xml :param vmxml: xml of vm to be manipulated :param sync: whether to sync vmxml after :param attrs: attrs to set to hpt xml """ if vmxml.xmltreefile.find('/features'): features_xml = vmxml.features else: features_xml = vm_xml.VMFeaturesXML() hpt_xml = vm_xml.VMFeaturesHptXML() for attr in attrs: setattr(hpt_xml, attr, attrs[attr]) features_xml.hpt = hpt_xml vmxml.features = features_xml logging.debug(vmxml) if sync: vmxml.sync() def set_cpu(vmxml, **attrs): """ Set cpu attrs for vmxml according to given attrs :param vmxml: xml of vm to be manipulated :param attrs: attrs to set to cpu xml """ if vmxml.xmltreefile.find('cpu'): cpu = vmxml.cpu else: cpu = vm_xml.VMCPUXML() if 'numa_cell' in attrs: cpu.xmltreefile.create_by_xpath('/numa') cpu.numa_cell = attrs['numa_cell'] for key in attrs: setattr(cpu, key, attrs[key]) vmxml.cpu = cpu vmxml.sync() def set_memory(vmxml): """ Set memory attributes in vm xml """ vmxml.max_mem_rt = int(params.get('max_mem_rt', 30670848)) vmxml.max_mem_rt_slots = int(params.get('max_mem_rt_slots', 16)) vmxml.max_mem_rt_unit = params.get('max_mem_rt_unit', 'KiB') logging.debug(numa_cell) if numa_cell: # Remove cpu topology to avoid that it doesn't match vcpu count if vmxml.get_cpu_topology(): new_cpu = vmxml.cpu new_cpu.del_topology() vmxml.cpu = new_cpu vmxml.vcpu = max([int(cell['cpus'][-1]) for cell in numa_cell]) + 1 vmxml.sync() def check_hpt_order(session, resizing=''): """ Return htp order in hpt_order file by default If 'resizing' is disabled, test updating htp_order """ if not hpt_order_path: test.cancel('No hpt order path provided.') hpt_order = session.cmd_output('cat %s' % hpt_order_path).strip() hpt_order = int(hpt_order) logging.info('Current hpt_order is %d', hpt_order) if resizing == 'disabled': cmd_result = session.cmd_status_output( 'echo %d > %s' % (hpt_order + 1, hpt_order_path)) result = process.CmdResult(stderr=cmd_result[1], exit_status=cmd_result[0]) libvirt.check_exit_status(result, True) libvirt.check_result(result, error_msg) return hpt_order def check_hp_in_vm(session, page_size): """ Check if hugepage size is correct inside vm :param session: the session of the running vm :param page_size: the expected pagesize to be checked inside vm """ expect = False if int(page_size) == 65536 else True meminfo = session.cmd_output('cat /proc/meminfo|grep Huge') logging.info('meminfo: \n%s', meminfo) pattern = 'Hugepagesize:\s+%d\s+kB' % int(page_size / 1024) logging.info('"%s" should %s be found in meminfo output', pattern, '' if expect else 'not') result = expect == bool(re.search(pattern, meminfo)) if not result: test.fail('meminfo output not meet expectation') # Check PAGE_SIZE in another way if not expect: conf_page_size = session.cmd_output('getconf PAGE_SIZE') logging.debug('Output of "getconf PAGE_SIZE": %s', conf_page_size) if int(conf_page_size) != int(page_size): test.fail( 'PAGE_SIZE not correct, should be %r, actually is %r' % (page_size, conf_page_size)) bk_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) try: arch = platform.machine() vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) resizing = hpt_attrs.get('resizing') # Test on ppc64le hosts if arch.lower() == 'ppc64le': cpu_arch = cpu.get_cpu_arch() logging.debug('cpu_arch is: %s', cpu_arch) if skip_p8 and cpu_arch == 'power8': test.cancel('This case is not for POWER8') if maxpagesize and not utils_misc.compare_qemu_version(3, 1, 0): test.cancel('Qemu version is too low, ' 'does not support maxpagesize setting') if maxpagesize == 16384 and cpu_arch == 'power9': test.cancel('Power9 does not support 16M pagesize.') set_hpt(vmxml, True, **hpt_attrs) if cpu_attrs or numa_cell: if numa_cell: cpu_attrs['numa_cell'] = numa_cell set_cpu(vmxml, **cpu_attrs) if hugepage: vm_mem = vmxml.max_mem host_hp_size = utils_memory.get_huge_page_size() # Make 100m extra memory just to be safe hp_count = max((vm_mem + 102400) // host_hp_size, 1200) vm_xml.VMXML.set_memoryBacking_tag(vm_name, hpgs=True) # Set up hugepage env mnt_source, hp_path, fstype = 'hugetlbfs', '/dev/hugepages', 'hugetlbfs' if not os.path.isdir(hp_path): process.run('mkdir %s' % hp_path, verbose=True) utils_memory.set_num_huge_pages(hp_count) if utils_misc.is_mounted(mnt_source, hp_path, fstype, verbose=True): utils_misc.umount(mnt_source, hp_path, fstype, verbose=True) utils_misc.mount(mnt_source, hp_path, fstype, verbose=True) # Restart libvirtd service to make sure mounted hugepage # be recognized utils_libvirtd.libvirtd_restart() if resizing == 'enabled': set_memory(vmxml) logging.debug('vmxml: \n%s', vmxml) # Start vm and check if start succeeds result = virsh.start(vm_name, debug=True) libvirt.check_exit_status(result, expect_error=status_error) # if vm is not suposed to start, terminate test if status_error: libvirt.check_result(result, error_msg) return libvirt.check_qemu_cmd_line(qemu_check) session = vm.wait_for_login() hpt_order = check_hpt_order(session, resizing) # Check hugepage inside vm if check_hp: check_hp_in_vm(session, maxpagesize * 1024) if resizing == 'enabled': mem_xml = utils_hotplug.create_mem_xml( tg_size=int(params.get('mem_size', 2048000)), tg_sizeunit=params.get('size_unit', 'KiB'), tg_node=int(params.get('mem_node', 0)), mem_model=params.get('mem_model', 'dimm')) logging.debug(mem_xml) # Attach memory device to the guest for 12 times # that will reach the maxinum memory limitation for i in range(12): virsh.attach_device(vm_name, mem_xml.xml, debug=True, ignore_status=False) xml_after_attach = vm_xml.VMXML.new_from_dumpxml(vm_name) logging.debug(xml_after_attach) # Check dumpxml of the guest, # check if each device has its alias for i in range(12): pattern = "alias\s+name=[\'\"]dimm%d[\'\"]" % i logging.debug('Searching for %s', pattern) if not re.search(pattern, str( xml_after_attach.xmltreefile)): test.fail('Missing memory alias: %s' % pattern) # Test on non-ppc64le hosts else: set_hpt(vmxml, sync=False, **hpt_attrs) result = virsh.define(vmxml.xml) libvirt.check_exit_status(result, status_error) libvirt.check_result(result, error_msg) finally: bk_xml.sync() if hugepage: utils_misc.umount('hugetlbfs', '/dev/hugepages', 'hugetlbfs') utils_memory.set_num_huge_pages(0)
def test_no_label(vm, params, test): """ Test nvdimm without label setting :param vm: vm object :param params: dict, test parameters :param test: test object :raises: test.fail if checkpoints fail """ test_str = params.get('test_str') vm_session = vm.wait_for_login() # Create a file system on /dev/pmem0 create_file_within_nvdimm_disk(vm_session, 'foo', test_str, test) vm_session.close() # Shutdown the guest, then start it, remount /dev/pmem0, # check if the test file is still on the file system vm.destroy() vm.start() vm_session = vm.wait_for_login() vm_session.cmd('mount -o dax /dev/pmem0 /mnt') check_nvdimm_file(test_str, 'foo', vm_session, test) # From the host, check the file has changed: host_output = process.run('hexdump -C /tmp/nvdimm', shell=True, verbose=True).stdout_text if test_str not in host_output: test.fail('\"%s\" should be in output' % test_str) # Shutdown the guest, and edit the xml, # include: access='private' vm_session.close() vm.destroy() guest_xml = vm_xml.VMXML.new_from_dumpxml(params.get('main_vm')) vm_devices = guest_xml.devices nvdimm_device = vm_devices.by_device_tag('memory')[0] nvdimm_index = vm_devices.index(nvdimm_device) vm_devices[nvdimm_index].mem_access = 'private' guest_xml.devices = vm_devices guest_xml.sync() # Login to the guest, mount the /dev/pmem0 and . # create a file: foo-private vm.start() vm_session = vm.wait_for_login() IS_PPC_TEST = 'ppc64le' in platform.machine().lower() if IS_PPC_TEST: libvirt.check_qemu_cmd_line('mem-path=/tmp/nvdimm,share=no') private_str = 'This is a test for foo-private' vm_session.cmd('mount -o dax /dev/pmem0 /mnt/') file_private = 'foo-private' vm_session.cmd("echo '%s' >/mnt/%s" % (private_str, file_private)) check_nvdimm_file(private_str, file_private, vm_session, test) # Shutdown the guest, then start it, # check the file: foo-private is no longer existed vm_session.close() vm.destroy() vm.start() vm_session = vm.wait_for_login() vm_session.cmd('mount -o dax /dev/pmem0 /mnt/') if file_private in vm_session.cmd('ls /mnt/'): test.fail('%s should not exist, for it was ' 'created when access=private' % file_private)