diff --git a/libvirt/tests/cfg/virtual_disks/virtual_disks_discard_no_unref.cfg b/libvirt/tests/cfg/virtual_disks/virtual_disks_discard_no_unref.cfg new file mode 100644 index 00000000000..060210a8a68 --- /dev/null +++ b/libvirt/tests/cfg/virtual_disks/virtual_disks_discard_no_unref.cfg @@ -0,0 +1,42 @@ +- virtual_disks.discard_no_unref: + type = virtual_disks_discard_no_unref + start_vm = "no" + status_error = "no" + func_supported_since_libvirt_ver = (9, 5, 0) + target_dev = "vdb" + + variants: + - file_disk: + disk_type = "file" + - block_disk: + disk_type = "block" + variants: + - with_discard_unmap: + discard = "unmap" + - with_discard_ignore: + discard = "ignore" + variants: + - enable: + discard_no_unref = "on" + qemu_output = "true" + - disable: + discard_no_unref = "off" + qemu_output = "false" + variants test_scenario: + - start_vm: + check_qemu_pattern = '"discard":"${discard}","driver":"qcow2","discard-no-unref":${qemu_output}' + expect_xml_line = 'discard_no_unref="${discard_no_unref}"' + - define_invalid: + only enable..with_discard_unmap.file_disk + status_error = "yes" + variants: + - raw_format: + invalid_format = "yes" + expect_error = "unsupported configuration: 'discard_no_unref' only works with qcow2 disk format" + - readonly_mode: + expect_error = "unsupported configuration: 'discard_no_unref' is not compatible with read-only disk" + - hotplug_disk: + only enable..with_discard_unmap.file_disk + hotplug = "yes" + check_libvirtd_log = '"driver":"qcow2","discard-no-unref":true' + disk_dict = {'type_name': '${disk_type}', 'driver': {'name': 'qemu', 'type': 'qcow2', 'discard': '${discard}', 'discard_no_unref': '${discard_no_unref}'}, 'target': {'dev': '${target_dev}'}} diff --git a/libvirt/tests/src/virtual_disks/virtual_disks_discard_no_unref.py b/libvirt/tests/src/virtual_disks/virtual_disks_discard_no_unref.py new file mode 100644 index 00000000000..882157c0041 --- /dev/null +++ b/libvirt/tests/src/virtual_disks/virtual_disks_discard_no_unref.py @@ -0,0 +1,173 @@ +# Copyright Red Hat +# SPDX-License-Identifier: GPL-2.0 +# Author: Meina Li + +import os + +from avocado.utils import process + +from virttest import libvirt_version +from virttest import virsh +from virttest.libvirt_xml import vm_xml, xcepts +from virttest.utils_test import libvirt + +from provider.virtual_disk import disk_base + + +def result_check(vm, params, test): + """ + Check the dumpxml/qemu command line and read/write data in guest + 1) Check the guest dumpxml with expected driver attribute. + 2) Check the qemu command line after starting the guest. + 3) Read/write the data in guest. + + :param vm: vm instance + :param params: dict, test parameters + :param test: test object + """ + check_qemu_pattern = params.get("check_qemu_pattern", "") + expect_xml_line = params.get("expect_xml_line", "") + check_libvirtd_log = params.get("check_libvirtd_log", "") + target_dev = params.get("target_dev") + hotplug = "yes" == params.get("hotplug", "no") + test.log.info("Check the dumpxml.") + libvirt.check_dumpxml(vm, expect_xml_line) + if check_qemu_pattern: + test.log.info("Check the qemu command line.") + libvirt.check_qemu_cmd_line(check_qemu_pattern) + if hotplug: + test.log.info("Check the libvirtd log.") + libvirtd_log_file = os.path.join(test.debugdir, "libvirtd.log") + libvirt.check_logfile(check_libvirtd_log, libvirtd_log_file) + test.log.info("Check read/write in guest.") + session = vm.wait_for_login() + session.cmd("mkfs.ext4 /dev/%s && mount /dev/%s /mnt" % (target_dev, target_dev)) + status, output = session.cmd_status_output("dd if=/dev/zero of=/mnt/file bs=1M count=10") + if status: + test.error("Failed to read/write in guest: %s" % output) + else: + test.log.debug("Read/write in guest successfully") + session.close() + + +def run_test_start_vm(vm, params, test): + """ + Scenario: start guest with discard_no_unref attribute + + :param vm: vm instance + :param params: dict, test parameters + :param test: test object + """ + vm_name = params.get("main_vm") + disk_dict = eval(params.get("disk_dict", "{}")) + disk_type = params.get("disk_type") + disk_obj = disk_base.DiskBase(test, vm, params) + + test.log.info("STEP1: prepare the guest xml.") + new_image_path = disk_obj.add_vm_disk(disk_type, disk_dict) + if disk_type == "block": + cmd = "qemu-img create -f qcow2 %s 50M" % new_image_path + process.run(cmd, shell=True, ignore_status=False) + test.log.info("STEP2: start the guest.") + virsh.start(vm_name, debug=True, ignore_status=False) + test.log.debug("The current guest xml is: %s" % virsh.dumpxml(vm_name).stdout_text) + test.log.info("STEP3: check the dumpxml and the qemu command line and read/write in guest.") + result_check(vm, params, test) + + +def run_test_define_invalid(vm, params, test): + """ + Scenario: start guest with invalid discard_no_unref configuration + + :param vm: vm instance + :param params: dict, test parameters + :param test: test object + """ + status_error = "yes" == params.get("status_error", "no") + invalid_format = "yes" == params.get("invalid_format", "no") + expect_error = params.get("expect_error") + disk_dict = eval(params.get("disk_dict", "{}")) + disk_type = params.get("disk_type") + disk_obj = disk_base.DiskBase(test, vm, params) + if status_error: + if invalid_format: + disk_dict['driver']['type'] = 'raw' + else: + disk_dict.update({'readonly': True}) + try: + disk_obj.add_vm_disk(disk_type, disk_dict) + except xcepts.LibvirtXMLError as xml_error: + if not status_error: + test.fail("Failed to define VM:\n%s" % str(xml_error)) + else: + test.log.debug("Get expecct error message:\n%s" % expect_error) + + +def run_test_hotplug_disk(vm, params, test): + """ + Scenario: hotplug/unplug disk with discard_no_unref enabled + + :param vm: vm instance + :param params: dict, test parameters + :param test: test object + """ + vm_name = params.get("main_vm") + disk_type = params.get("disk_type") + target_dev = params.get("target_dev") + disk_dict = eval(params.get("disk_dict", "{}")) + disk_obj = disk_base.DiskBase(test, vm, params) + + test.log.debug("STEP1&2: prepare hotplugged disk image and xml.") + disk_xml, _ = disk_obj.prepare_disk_obj(disk_type, disk_dict) + if not vm.is_alive(): + vm.start() + test.log.debug("STEP3: attach disk xml.") + virsh.attach_device(vm_name, disk_xml.xml, debug=True, ignore_status=False) + test.log.debug("STEP4: check the result.") + result_check(vm, params, test) + test.log.debug("STEP5: detach disk.") + virsh.detach_device(vm_name, disk_xml.xml, debug=True, ignore_status=False) + domblklist_result = virsh.domblklist(vm_name, debug=True).stdout_text.strip() + if target_dev in domblklist_result: + test.fail("The target disk % can't be detached in guest." % target_dev) + + +def teardown_test(vm, vmxml, params, test): + """ + :param vm: vm instance + :params vmxml: the guest xml + :param params: dict, test parameters + :param test: test object + """ + disk_type = params.get("disk_type") + if vm.is_alive(): + vm.destroy() + vmxml.sync() + disk_obj = disk_base.DiskBase(test, vm, params) + disk_obj.cleanup_disk_preparation(disk_type) + + +def run(test, params, env): + """ + Test driver attribute: discard_no_unref + + Scenarios: + 1) Start guest with disk discard_no_unref attrribute.n + 2) Define guest with invalid disk discard_no_unref attribute. + 3) Hotplug disk with discard_no_unref attrribute. + """ + vm_name = params.get("main_vm") + libvirt_version.is_libvirt_feature_supported(params) + + vm = env.get_vm(vm_name) + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + bkxml = vmxml.copy() + test_scenario = params.get("test_scenario") + case_name = "run_test_%s" % test_scenario + run_test_case = eval(case_name) + try: + if vm.is_alive(): + vm.destroy() + run_test_case(vm, params, test) + finally: + teardown_test(vm, bkxml, params, test)