diff --git a/libvirt/tests/cfg/memory/memory_devices/invalid_nvdimm_memory_device_config.cfg b/libvirt/tests/cfg/memory/memory_devices/invalid_nvdimm_memory_device_config.cfg new file mode 100644 index 0000000000..0a6fb1b468 --- /dev/null +++ b/libvirt/tests/cfg/memory/memory_devices/invalid_nvdimm_memory_device_config.cfg @@ -0,0 +1,69 @@ +- memory.devices.invalid_nvdimm: + type = invalid_nvdimm_memory_device_config + nvdimm_file_size = "512M" + target_size = 524288 + guest_node = 0 + slot = 0 + addr_type = 'dimm' + addr_base = '0x100000000' + nvdimm_path = "/tmp/nvdimm" + alignsize = 2048 + label_size = 128 + discard_attr = "" + label_attrs = "" + align_attrs = "'alignsize':${alignsize},'alignsize_unit': 'KiB'" + label_attrs = "'label':{'size_unit':'KiB','size':${label_size}}" + addr_attrs = "'address':{'attrs': {'type': '${addr_type}', 'base': '${addr_base}', 'slot': '${slot}'}}" + variants invalid_setting: + - exceed_slot: + slot = '4294967295' + define_error = "memory device slot '${slot}' exceeds slots count" + - max_addr: + addr_base = '0xffffffffffffffff' + start_vm_error = "address must be aligned to" + attach_error = "nvdimm is not enabled: missing 'nvdimm' in '-M'" + aarch64: + attach_error = "nvdimm is not enabled: add 'nvdimm=on' to '-M'" + - unexisted_node: + guest_node = '6' + start_vm_error = "can't add memory backend for guest node '${guest_node}' as the guest has only '2' NUMA nodes configured" + - unexisted_path: + nvdimm_path = "/tmp/nonexist.file" + start_vm_error = "No such file or directory" + - invalid_alignsize: + alignsize = '2' + align_attrs = "'alignsize':${alignsize},'alignsize_unit': 'KiB'" + start_vm_error = "must be multiples of page size 0x1000" + - invalid_addr_type: + addr_type = 'fakedimm' + define_error = "Invalid value for attribute 'type' in element 'address': '${addr_type}'" + define_error_8 = "unknown address type '${addr_type}'" + attach_error_8 = "unknown address type '${addr_type}'" + - small_label: + label_size = 100 + label_attrs = "'label':{'size_unit':'KiB','size':${label_size}}" + define_error ="nvdimm label must be at least 128KiB" + - bigger_label: + label_size = 524289 + label_attrs = "'label':{'size_unit':'KiB','size':${label_size}}" + define_error ="label size must be smaller than NVDIMM size" + - bigger_target_memory: + target_size = 1048576 + start_vm_error = "backing store size 0x20000000 does not match 'size' option 0x40000000" + - with_discard: + mem_discard = "yes" + discard_attr = " 'mem_discard':'${mem_discard}'," + define_error = "discard is not supported for nvdimms" + addr_attrs = "'address':{'attrs': {'type': '${addr_type}', 'base': '${addr_base}', 'slot': '${slot}'}}" + source_attrs = "'source': {${align_attrs},'path': '${nvdimm_path}'}" + target_attrs = "'target': {'size': ${target_size},'size_unit': 'KiB','node':${guest_node}, ${label_attrs}}" + nvdimm_dict = {'mem_model':'nvdimm', ${source_attrs}, ${target_attrs},${addr_attrs},${discard_attr}} + variants: + - with_numa: + no s390-virtio + mem_value = 2097152 + current_mem = 2097152 + numa_mem = 1048576 + max_dict = '"max_mem_rt": 10485760, "max_mem_rt_slots":16, "max_mem_rt_unit": "KiB"' + numa_attrs = "'vcpu': 4,'cpu': {'numa_cell': [{'id': '0', 'cpus': '0-1', 'memory': '${numa_mem}', 'unit': 'KiB'},{'id':'1','cpus': '2-3','memory':'${numa_mem}','unit':'KiB'}]}" + vm_attrs = {${numa_attrs}, ${max_dict}, 'memory_unit':'KiB','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':"KiB"} diff --git a/libvirt/tests/src/memory/memory_devices/invalid_nvdimm_memory_device_config.py b/libvirt/tests/src/memory/memory_devices/invalid_nvdimm_memory_device_config.py new file mode 100644 index 0000000000..dda407db1e --- /dev/null +++ b/libvirt/tests/src/memory/memory_devices/invalid_nvdimm_memory_device_config.py @@ -0,0 +1,151 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright Redhat +# +# SPDX-License-Identifier: GPL-2.0 + +# Author: Nannan Li +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import os + +from avocado.utils import process + +from virttest import libvirt_version +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_test import libvirt + +from provider.memory import memory_base + + +def define_guest(test, params): + """ + Define guest. + + :param test: test object. + :param params: dict, test parameters. + """ + vm_name = params.get("main_vm") + vm_attrs = eval(params.get("vm_attrs")) + nvdimm_dict = eval(params.get("nvdimm_dict")) + invalid_setting = params.get("invalid_setting") + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vmxml.setup_attrs(**vm_attrs) + mem_obj = memory_base.prepare_mem_obj(nvdimm_dict) + vmxml.devices = vmxml.devices.append(mem_obj) + test.log.debug("Define vm with %s." % vmxml) + + # Check libvirt version + if libvirt_version.version_compare(9, 0, 0) and \ + invalid_setting == "unexisted_node": + define_error = params.get("start_vm_error") + elif not libvirt_version.version_compare(9, 9, 0) and \ + invalid_setting == "invalid_addr_type": + define_error = params.get("define_error_8") + else: + define_error = params.get("define_error") + + # Redefine define_error for checking start_vm_error + params.update({"define_error": define_error}) + + try: + vmxml.sync() + except Exception as e: + if define_error: + if define_error not in str(e): + test.fail("Expect to get '%s' error, but got '%s'" % (define_error, e)) + else: + test.fail("Expect define successfully, but failed with '%s'" % e) + + +def run(test, params, env): + """ + Verify error messages prompt with invalid nvdimm memory device configs + + 1.invalid value: + exceed slot number, max address base, nonexistent guest node + nonexistent path, invalid pagesize, invalid address type, small label size + label size bigger than memory size, :memory size bigger than backing file size + discard. + 2.memory setting: with numa + """ + + def setup_test(): + """ + Create file backend for nvdimm device. + """ + test.log.info("Setup env.") + if invalid_setting != "unexisted_path": + process.run('truncate -s %s %s' % (nvdimm_file_size, nvdimm_path), + verbose=True, shell=True) + + def run_test(): + """ + Define vm with nvdimm and Start vm. + Hotplug nvdimm. + """ + test.log.info("TEST_STEP1: Define vm and check result") + define_guest(test, params) + + test.log.info("TEST_STEP2: Start guest ") + start_result = virsh.start(vm_name, debug=True, ignore_status=True) + if start_vm_error: + libvirt.check_result(start_result, start_vm_error) + else: + libvirt.check_exit_status(start_result) + + test.log.info("TEST_STEP3: Define guest without nvdimm devices") + original_xml.setup_attrs(**vm_attrs) + test.log.debug("Define vm without nvdimm by '%s' \n", original_xml) + original_xml.sync() + virsh.start(vm_name, debug=True, ignore_status=False) + vm.wait_for_login().close() + + test.log.info("TEST_STEP4: Hotplug nvdimm memory device") + mem_obj = memory_base.prepare_mem_obj(nvdimm_dict) + result = virsh.attach_device(vm_name, mem_obj.xml, debug=True).stderr_text + if attach_error not in result: + test.fail("Expected get error '%s', but got '%s'" % (attach_error, result)) + + def teardown_test(): + """ + Clean data. + """ + test.log.info("TEST_TEARDOWN: Clean up env.") + bkxml.sync() + if os.path.exists(nvdimm_path): + os.remove(nvdimm_path) + + vm_name = params.get("main_vm") + vm = env.get_vm(vm_name) + original_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = original_xml.copy() + invalid_setting = params.get("invalid_setting") + nvdimm_file_size = params.get("nvdimm_file_size") + nvdimm_path = params.get("nvdimm_path") + nvdimm_dict = eval(params.get("nvdimm_dict")) + vm_attrs = eval(params.get("vm_attrs")) + # Get start vm error + if libvirt_version.version_compare(9, 0, 0) and \ + invalid_setting == "unexisted_node": + start_vm_error = "" + else: + start_vm_error = params.get("start_vm_error") + + # Get attach error + if invalid_setting == "max_addr": + attach_error = params.get('attach_error') + elif not libvirt_version.version_compare(9, 9, 0) and \ + invalid_setting == "invalid_addr_type": + attach_error = params.get('attach_error_8') + else: + attach_error = params.get("start_vm_error", params.get("define_error")) + + try: + setup_test() + run_test() + + finally: + teardown_test() diff --git a/provider/memory/memory_base.py b/provider/memory/memory_base.py index 8032a7ba3f..5500110e1e 100644 --- a/provider/memory/memory_base.py +++ b/provider/memory/memory_base.py @@ -3,6 +3,7 @@ from virttest import libvirt_version from virttest import utils_misc +from virttest.libvirt_xml.devices import memory from virttest.utils_version import VersionInterval from avocado.core import exceptions @@ -76,3 +77,15 @@ def check_supported_version(params, test, vm): if vm_kerv not in VersionInterval(guest_required_kernel): test.cancel("Got guest kernel version:%s, which is not in %s" % (vm_kerv, guest_required_kernel)) + + +def prepare_mem_obj(dest_dict): + """ + Prepare memory object + :param dest_dict: dimm memory dict. + :return mem_obj, memory object. + """ + mem_obj = memory.Memory() + mem_obj.setup_attrs(**dest_dict) + + return mem_obj