From 0ec592d68f6b67d4634bcb54e3d795af7deb3d32 Mon Sep 17 00:00:00 2001 From: Meina Li Date: Fri, 9 Jan 2026 03:11:53 -0500 Subject: [PATCH] Virtual disk: add migration case with vhostuser disk Automate case: RHEL-200524: Migrate VM with a vhostuser disk Signed-off-by: Meina Li --- .../migration_with_vhostuser.cfg | 36 ++++++ .../migration_with_vhostuser.py | 117 ++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 libvirt/tests/cfg/migration/migration_with_disk/migration_with_vhostuser.cfg create mode 100644 libvirt/tests/src/migration/migration_with_disk/migration_with_vhostuser.py diff --git a/libvirt/tests/cfg/migration/migration_with_disk/migration_with_vhostuser.cfg b/libvirt/tests/cfg/migration/migration_with_disk/migration_with_vhostuser.cfg new file mode 100644 index 0000000000..a62c07a833 --- /dev/null +++ b/libvirt/tests/cfg/migration/migration_with_disk/migration_with_vhostuser.cfg @@ -0,0 +1,36 @@ +- migration.migration_with_disk.migration_with_vhostuser: + type = migration_with_vhostuser + start_vm = "no" + 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 + virsh_migrate_connect_uri = "qemu:///system" + virsh_migrate_dest_state = "running" + virsh_migrate_src_state = "shut off" + server_ip = "${migrate_dest_host}" + server_user = "root" + server_pwd = "${migrate_dest_pwd}" + client_ip = "${migrate_source_host}" + client_pwd = "${migrate_source_pwd}" + migrate_desturi_port = "22" + migrate_desturi_type = "ssh" + virsh_migrate_desturi = "qemu+ssh://${migrate_dest_host}/system" + func_supported_since_libvirt_ver = (7, 0, 0) + vm_attrs = {"mb": {"source_type":"memfd", "access_mode": "shared"}} + source_file = "/tmp/vhost.sock" + queues = 1 + disk_dict = {"type_name": "vhostuser", "device": "disk", "driver": {"name": "qemu", "type": "raw", "queues": ${queues}}, "source": {"attrs": {"type": "unix", "path": "${source_file}"}}, "target": {"dev": "vdb", "bus": "virtio"}} + check_disk_after_mig = "yes" + no ppc64le + variants: + - with_precopy: diff --git a/libvirt/tests/src/migration/migration_with_disk/migration_with_vhostuser.py b/libvirt/tests/src/migration/migration_with_disk/migration_with_vhostuser.py new file mode 100644 index 0000000000..139b7b1018 --- /dev/null +++ b/libvirt/tests/src/migration/migration_with_disk/migration_with_vhostuser.py @@ -0,0 +1,117 @@ +import os +import ast + +from virttest import libvirt_version +from virttest import remote +from virttest import virsh +from virttest import data_dir + +from virttest.libvirt_xml import vm_xml +from virttest.utils_libvirt import libvirt_vmxml + +from provider.migration import base_steps + + +def start_vhost_sock_service(start_sock_service_cmd, image_path, params, runner): + """ + Prepare and start vhost sock service in local/remote host. + + :param start_sock_service_cmd: command to start vhost service. + :param image_path: image file path. + :param params: the parameter for executing + :param runner: a runner object on local/remote host. + """ + sock_path = params.get("source_file", "/tmp/vhost.sock") + remote.run_remote_cmd(f"mkdir -p {os.path.dirname(image_path)}", params, runner, ignore_status=True) + remote_create_cmd = f"dd if=/dev/zero of={image_path} bs=1M count=100 && chown qemu:qemu {image_path}" + remote.run_remote_cmd(remote_create_cmd, params, runner, ignore_status=False) + remote.run_remote_cmd(start_sock_service_cmd, params, runner, ignore_status=False) + remote_selinux_cmd = f"chcon -t svirt_image_t {sock_path} && setsebool domain_can_mmap_files 1" + remote.run_remote_cmd(remote_selinux_cmd, params, runner, ignore_status=False) + + +def remove_vhost_sock_service(image_path, params, runner): + """ + Remove the vhost sock service. + """ + sock_path = params.get("source_file", "/tmp/vhost.sock") + remote.run_remote_cmd("pkill -f qemu-storage-daemon", params, runner, ignore_status=True) + remote.run_remote_cmd(f"rm -rf {sock_path} {image_path}", params, runner, ignore_status=True) + + +def run(test, params, env): + """ + Test vhostuser disk migration. + + 1.Prepare vhostuser disk and start the domain. + 2.Perform migration operation. + 3.Verify vhostuser disk after migration. + """ + + def setup_test(): + """ + Setup steps before migration + """ + test.log.info("Setup steps for vhostuser disk migration.") + sock_path = params.get("source_file", "/tmp/vhost.sock") + disk_dict = ast.literal_eval(params.get("disk_dict", "{}")) + vm_attrs = ast.literal_eval(params.get("vm_attrs", "{}")) + + start_sock_service_cmd = ( + 'systemd-run --uid qemu --gid qemu /usr/bin/qemu-storage-daemon' + ' --blockdev \'{"driver":"file","filename":"%s","node-name":"libvirt-1-storage","auto-read-only":true,"discard":"unmap"}\'' + ' --blockdev \'{"node-name":"libvirt-1-format","read-only":false,"driver":"raw","file":"libvirt-1-storage"}\'' + ' --export vhost-user-blk,id=vhost-user-blk0,node-name=libvirt-1-format,addr.type=unix,addr.path=%s,writable=on' + ' --chardev stdio,mux=on,id=char0; sleep 3' + % (image_path, sock_path)) + + start_vhost_sock_service(start_sock_service_cmd, image_path, params, local_runner) + start_vhost_sock_service(start_sock_service_cmd, image_path, params, remote_runner) + migration_obj.setup_connection() + + vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) + vmxml.setup_attrs(**vm_attrs) + disk_obj = libvirt_vmxml.create_vm_device_by_type("disk", disk_dict) + test.log.debug("vhostuser disk xml is:\n%s" % disk_obj) + vmxml.add_device(disk_obj) + vmxml.sync() + base_steps.sync_cpu_for_mig(params) + vm.start() + vm.wait_for_login().close() + + if "vhostuser" not in virsh.dumpxml(vm_name).stdout_text: + test.fail("Check vhostuser disk in VM failed") + test.log.info("Setup completed successfully.") + + def cleanup_test(): + """ + Cleanup steps for cases + + """ + test.log.info("Cleanup steps for vhostuser disk migration.") + migration_obj.cleanup_connection() + remove_vhost_sock_service(image_path, params, local_runner) + remove_vhost_sock_service(image_path, params, remote_runner) + test.log.info("Cleanup completed successfully.") + + libvirt_version.is_libvirt_feature_supported(params) + vm_name = params.get("migrate_main_vm") + vm = env.get_vm(vm_name) + client_ip = params.get("client_ip") + client_pwd = params.get("client_pwd") + server_ip = params.get("server_ip") + server_pwd = params.get("server_pwd") + server_user = params.get("server_user") + image_path = data_dir.get_data_dir() + '/test.img' + + migration_obj = base_steps.MigrationBase(test, vm, params) + local_runner = remote.RemoteRunner(host=client_ip, username=server_user, password=client_pwd) + remote_runner = remote.RemoteRunner(host=server_ip, username=server_user, password=server_pwd) + + try: + setup_test() + migration_obj.run_migration() + migration_obj.verify_default() + + finally: + cleanup_test()