From dd66dc8e02941e5d1bcebb66281dab1089d7dc83 Mon Sep 17 00:00:00 2001 From: Sebastian Mitterle Date: Tue, 13 May 2025 10:58:43 -0400 Subject: [PATCH] migration/destructive_operations: kill virtiofsd on source Add test for killing virtiofsd during migration perform phase with external virtiofsd. Signed-off-by: Sebastian Mitterle --- .../kill_virtiofsd_during_performphase.cfg | 49 ++++++++ .../kill_virtiofsd_during_performphase.py | 110 ++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 libvirt/tests/cfg/migration/destructive_operations_around_live_migration/kill_virtiofsd_during_performphase.cfg create mode 100644 libvirt/tests/src/migration/destructive_operations_around_live_migration/kill_virtiofsd_during_performphase.py diff --git a/libvirt/tests/cfg/migration/destructive_operations_around_live_migration/kill_virtiofsd_during_performphase.cfg b/libvirt/tests/cfg/migration/destructive_operations_around_live_migration/kill_virtiofsd_during_performphase.cfg new file mode 100644 index 00000000000..5e7e0ce63e0 --- /dev/null +++ b/libvirt/tests/cfg/migration/destructive_operations_around_live_migration/kill_virtiofsd_during_performphase.cfg @@ -0,0 +1,49 @@ +- migration.destructive_operations_around_live_migration.kill_virtiofsd_during_performphase: + type = kill_virtiofsd_during_performphase + migration_setup = 'yes' + storage_type = 'nfs' + setup_local_nfs = 'yes' + disk_type = "file" + disk_source_protocol = "netfs" + mnt_path_name = ${nfs_mount_dir} + # Console output can only be monitored via virsh console output + only_pty = True + take_regular_screendumps = no + # Extra options to pass after + virsh_migrate_extra = '' + # SSH connection time out + ssh_timeout = 60 + # Local URI + virsh_migrate_connect_uri = 'qemu:///system' + virsh_migrate_dest_state = "running" + virsh_migrate_src_state = "shut off" + image_convert = 'no' + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + status_error = "no" + migrate_desturi_port = "22" + migrate_desturi_type = "ssh" + virsh_migrate_desturi = "qemu+ssh://${migrate_dest_host}/system" + func_supported_since_libvirt_ver = (10, 5, 0) + vm_attrs = {'mb': {"source_type":"file", 'access_mode': 'shared'}} + socket_path = "/vm001-vhost-fs.sock" + dev_type = "filesystem" + mount_tag = "mount_tag1" + mount_dir = "/mnt/${mount_tag}" + fs_dict = {'accessmode':'passthrough', 'type_name': 'mount', 'driver': {'type': 'virtiofs', 'queue':'1024'}, 'source':{'socket': '${socket_path}'}, "target": {'dir': '${mount_tag}'}} + expect_str = "${mount_tag}.*${mount_dir}" + variants: + - with_precopy: + status_error = "yes" + service_name = "virtiofsd" + migrate_speed = "1000" + virsh_migrate_options = '--live --verbose' + variants: + - kill_src_virtiofsd: + expected_dest_state = "nonexist" + expected_src_state = "running" + action_during_mig = '[{"func": "libvirt_service.kill_service", "after_event": "migration-iteration", "func_param": "params"}]' + err_msg = "load of migration failed: Input/output error|operation failed" + variants: + - external: diff --git a/libvirt/tests/src/migration/destructive_operations_around_live_migration/kill_virtiofsd_during_performphase.py b/libvirt/tests/src/migration/destructive_operations_around_live_migration/kill_virtiofsd_during_performphase.py new file mode 100644 index 00000000000..6d80ddcded3 --- /dev/null +++ b/libvirt/tests/src/migration/destructive_operations_around_live_migration/kill_virtiofsd_during_performphase.py @@ -0,0 +1,110 @@ +import re + +from avocado.utils import process + +from virttest import libvirt_version +from virttest import remote +from virttest import virsh +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml +from virttest.utils_test import libvirt + +from provider.migration import base_steps + + +def run(test, params, env): + """ + This case is to verify that if killing virtiofsd process during PerformPhase of + migration, migration will fail. If dst virtiofsd is killed, src virtiofsd will keep + running. If src virtiofsd is killed, dst virtiofsd will be closed. + + :param test: test object + :param params: Dictionary with the test parameters + :param env: Dictionary with test environment. + """ + + def setup_test(): + """ + Setup steps + + """ + test.log.info("Setup steps.") + mnt_path_name = params.get("mnt_path_name") + socket_path = params.get("socket_path") + vm_attrs = eval(params.get("vm_attrs", "{}")) + fs_dict = eval(params.get("fs_dict", "{}")) + dev_type = params.get("dev_type") + mount_tag = params.get("mount_tag") + mount_dir = params.get("mount_dir") + expect_str = params.get("expect_str") + + cmd1 = f"chcon -t virtd_exec_t /usr/libexec/virtiofsd" + cmd2 = f"mkdir -p {mnt_path_name}" + cmd3 = f"systemd-run /usr/libexec/virtiofsd --socket-path={socket_path} -o source={mnt_path_name}" + multi_cmd1 = f"{cmd1}; {cmd2}; {cmd3}" + process.run(multi_cmd1, shell=True, ignore_status=False) + remote.run_remote_cmd(multi_cmd1, params, ignore_status=False) + cmd4 = f"chcon -t svirt_image_t {socket_path}" + cmd5 = f"chown qemu:qemu {socket_path}" + multi_cmd2 = f"{cmd4}; {cmd5}" + process.run(multi_cmd2, shell=True, ignore_status=False) + remote.run_remote_cmd(multi_cmd2, params, ignore_status=False) + + migration_obj.setup_connection() + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) + vmxml.setup_attrs(**vm_attrs) + vmxml.remove_all_device_by_type("tpm") + vmxml.sync() + if not vm.is_alive(): + vm.start() + fs = libvirt_vmxml.create_vm_device_by_type(dev_type, fs_dict) + virsh.attach_device(vm_name, fs.xml, debug=True, ignore_status=False) + + vm_session = vm.wait_for_login() + vm_session.cmd_output_safe(f"mkdir {mount_dir}") + vm_session.cmd_output_safe(f"mount -t virtiofs {mount_tag} {mount_dir}") + output = vm_session.cmd_output("df -h") + vm_session.close() + test.log.debug("output: %s", output) + if not re.search(expect_str, output): + test.fail(f'Expect content "{expect_str}" not in output: {output}') + + def verify_test(): + """ + Verify migration result + + """ + dest_uri = params.get("virsh_migrate_desturi") + expected_src_state = params.get("expected_src_state") + expected_dest_state = params.get("expected_dest_state") + + func_returns = dict(migration_obj.migration_test.func_ret) + migration_obj.migration_test.func_ret.clear() + test.log.debug("Migration returns function results: %s", func_returns) + virsh.domstate(vm_name, uri=migration_obj.src_uri, debug=True) + if expected_src_state: + if not libvirt.check_vm_state( + vm.name, expected_src_state, uri=migration_obj.src_uri + ): + test.fail( + "Migrated VM failed to be in %s state at source." + % expected_src_state + ) + if expected_dest_state and expected_dest_state == "nonexist": + virsh.domstate(vm_name, uri=dest_uri, debug=True) + if virsh.domain_exists(vm_name, uri=dest_uri): + test.fail("The domain on target host is found, but expected not") + + libvirt_version.is_libvirt_feature_supported(params) + vm_name = params.get("migrate_main_vm") + + vm = env.get_vm(vm_name) + migration_obj = base_steps.MigrationBase(test, vm, params) + + try: + setup_test() + migration_obj.run_migration() + verify_test() + finally: + migration_obj.cleanup_connection()