Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

migration: Add case to test migrate vm between 2 hosts with special CPU #5856

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

cliping
Copy link
Contributor

@cliping cliping commented Aug 26, 2024

XXX-301817 - [VM migration] migrate vm between 2 hosts with special CPU

@cliping cliping force-pushed the l2vm branch 2 times, most recently from ee49b3f to 7c4e69a Compare August 26, 2024 11:31
@cliping
Copy link
Contributor Author

cliping commented Aug 26, 2024

Depends on: avocado-framework/avocado-vt#3978

Test results:

(1/8) type_specific.io-github-autotest-libvirt.migration.migration_misc.migration_with_special_cpu.with_precopy.p2p.cpu_disable_vmx_apicv_register: PASS (425.92 s)
(2/8) type_specific.io-github-autotest-libvirt.migration.migration_misc.migration_with_special_cpu.with_precopy.p2p.cpu: PASS (436.74 s)
(3/8) type_specific.io-github-autotest-libvirt.migration.migration_misc.migration_with_special_cpu.with_precopy.non_p2p.cpu_disable_vmx_apicv_register: PASS (436.90 s)
(4/8) type_specific.io-github-autotest-libvirt.migration.migration_misc.migration_with_special_cpu.with_precopy.non_p2p.cpu: PASS (442.41 s)
(5/8) type_specific.io-github-autotest-libvirt.migration.migration_misc.migration_with_special_cpu.with_postcopy.p2p.cpu_disable_vmx_apicv_register: PASS (435.79 s)
(6/8) type_specific.io-github-autotest-libvirt.migration.migration_misc.migration_with_special_cpu.with_postcopy.p2p.cpu: PASS (445.51 s)
(7/8) type_specific.io-github-autotest-libvirt.migration.migration_misc.migration_with_special_cpu.with_postcopy.non_p2p.cpu_disable_vmx_apicv_register: PASS (474.25 s)
(8/8) type_specific.io-github-autotest-libvirt.migration.migration_misc.migration_with_special_cpu.with_postcopy.non_p2p.cpu: PASS (437.04 s)

@cliping cliping changed the title migration: Add case to test migrate to between 2 hosts with special CPU migration: Add case to test migrate vm between 2 hosts with special CPU Aug 26, 2024
@Yingshun Yingshun added the depend on The PR has dependency on other PRs label Aug 27, 2024
Copy link
Contributor

@Yingshun Yingshun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plz upload test results, thx!

l2vm_name = "l2vm"
variants:
- cpu_disable_vmx_apicv_register:
l1vm_feature_list = {"vmx": "require", "vmx-apicv-register": "disable"}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this test work for multi archs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only tested it on x86_64. Not sure if vmx/vmx-apicv-register is supported on other archs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Yingshun
I understood , that vmx CPU capabilities are specific for x86_64, therefore it will not be available on ARM??
I didn't find any particular info, but here: https://qemu-project.gitlab.io/qemu/system/arm/cpu-features.html there are listed only other.

Also in the test design there are mentioned only the Intel CPUs ... I think this should be specified in the configuration, so the test will not run on other then x86_64 machines. (not clear how to specify that only on machines, that has required vmx-* capabilities.

Another question is, if there are other same/similar types for ARM, that has to be tested same way.

try:
vmx_index = cpu_xml.get_feature_index(key)
except Exception as detail:
test.log.debug("Got a exception: %s" % detail)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

% -> ,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, thanks.

else:
cpu_xml.set_feature(vmx_index, name=key, policy=value)
vm_xml.cpu = cpu_xml
test.log.debug("cpu xml: %s" % vm_xml.cpu)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

% -> ,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, thanks.

XXX-301817 - [VM migration] migrate vm between 2 hosts with special CPU

Signed-off-by: lcheng <[email protected]>
"""
test.log.info("Setup steps for cases.")

server_ip = params.get("server_ip")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

variables server_ip, client_ip and mount_src are not used in this method().

Copy link
Contributor

@hholoubk hholoubk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @cliping,
Sorry for so long review, you did good work, only for me as a newcomer are some part not so well readable and I believe just reordering or putting some duplicated code inside a separated method would really help me.

Please let me know in case you want to discuss anything.
BR.H.H.

mount_src = params.get("nfs_mount_src")
mount_dir = params.get("nfs_mount_dir")

prepare_vm(params, vm1, vm2, vm1_xml, vm2_xml, test)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the method name is misleading .. as there are two VMs prepared ... probably would be worth to rename to
prepare_both_vms()

vm2_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm2_name)
bak_vm2_xml = vm2_xml.copy()

l2vm_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm1_name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not fully aware what all is done in the "new_from_inactive_dumpxml) .. but probably it would be worth to jus do the "copy of vm1_xml" .. than call it again?
i.e. do the
l2vm_xml = vm1_xml.copy() as in case of bak_vm2_xml above ...

params.update({"server_ip": migrate_dest_host})
params.update({"client_ip": migrate_source_host})

vms = params.get("vms").split()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be "safe" I would recommend here to add some check that the vms parameter is set properly.
something like: (is it correct to use test.error instead of test.fail, as it is issue of the test script and not issue of tested feature)

vms = params.get("vms", "").split()
if len(vms) >=2:
vm1_name = vms[0]
vm2_name = vms[1]
else:
test.error("Wrong test configuration, there should be defined two VM names.")

shutil.copyfile(vm1_img_bak, vm1_img)
os.remove(vm1_img_bak)

params.update({"server_ip": migrate_dest_host})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for better readability, I would recommend to put the hosts get param and update together .. moving rows 298,2-- .. (as variables are not used), or put it together .. but it will be worse for readability.

        # set server/client IP back to configured values
        migrate_dest_host = params.get("migrate_dest_host")
        params.update({"server_ip": migrate_dest_host})

        migrate_source_host = params.get("migrate_source_host")
        params.update({"client_ip": migrate_source_host})
    or 
        #set server/client IP back to configured values
        params.update({"server_ip": params.get("migrate_dest_host")}) 
        params.update({"client_ip": params.get("migrate_source_host")})  

Comment on lines +307 to +318
if vm2.is_alive():
vm2.destroy(gracefully=False)
if vm1.is_alive():
vm1.destroy(gracefully=False)

bak_vm2_xml.sync()
if os.path.exists(l2vm_img):
os.remove(l2vm_img)
shutil.copyfile(vm2_img_bak, vm2_img)
os.remove(vm2_img_bak)
shutil.copyfile(vm1_img_bak, vm1_img)
os.remove(vm1_img_bak)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According best practices in development it is recommended to not duplicate the code, and introduce a method instead.

def revert_vm_setup(vm, vm_img, vm_img,bak):
    if vm.is_alive():
            vm.destroy(gracefully=False)
    shutil.copyfile(vm_img_bak, vm_img) 
    os.remove(vm_img_bak)

# and do the remaining code, that was between, am just not sure,
# if it should be before or after the revert, or it is not important
bak_vm2_xml.sync()
if os.path.exists(l2vm_img):
    os.remove(l2vm_img)
revert_vm_setup(vm1, vm1_img, vm1_img,bak):
revert_vm_setup(vm2, vm2_img, vm2_img,bak):

options = params.get("virsh_migrate_options")

test.log.debug("Run migration.")
vm1_ip = vm1.get_address()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getting IP addresses doesn't need to be requested again if they will be returned in setup_test()

utils_net.map_hostname_ipaddress(hosts_dict, vm2_session)
vm1_session.close()
vm2_session.close()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to return IP addresses here from the method, so other methods doesn't need to call get_address again ... it will be available in the "run" method.

return vm1_ip, vm2_ip

Comment on lines +152 to +155
server_ip = params.get("server_ip")
server_user = params.get("server_user", "root")
server_pwd = params.get("server_pwd")
client_ip = params.get("client_ip")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

variables server_ip and client_ip are not used in this method, so they doesn't need to be retrieved here.
Or did I miss something?

cpu_mode = params.get("cpu_mode")
l1vm_feature_list = eval(params.get("l1vm_feature_list"))

vm1_xml = update_cpu_xml(vm1_xml, cpu_mode, test, l1vm_feature_list)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According best coding practices this code should not be duplicated, but moved into some method .. in this case inner, so it will be able to use parameters got above.

e.g :

    def prepare_single_vm(vm, vm_xml, vm_hostname, test):
        vm_xml = update_cpu_xml(vm_xml, cpu_mode, test, l1vm_feature_list)
        prepare_package_in_vm(vm)
        prepare_env_in_vm(vm, vm_hostname, mount_src, mount_dir, desturi_port)
        return vm.get_address()

    # ... params.get part should be here ?? 

    vm1_ip = prepare_single_vm(vm1, vm1_xml, vm1_hostname, test)
    vm2_ip = prepare_single_vm(vm2, vm2_xml, vm2_hostname, test)

test.log.debug("Prepare nfs server in %s.", vm1_ip)
prepare_nfs_server_in_vm(vm1_ip, params)

mount_in_vm(vm1, (vm1_ip + ":" + mount_src), mount_dir)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the vm.session is called also inside the mount_in_vm .. then closed and opened here again.

I am not sure, if the session should be brought outside .. or the map_hostnam_ipaddress should be put inside the mount_in_vm.

Both has it's pros and cons.

But I guess the variant here will be better readable - even it will remove the mount_in_vm method itself

hosts_dict = {"%s" % vm1_hostname: "%s" % vm1_ip, "%s" % vm2_hostname: "%s" % vm2_ip}
mount_src = vm1_ip + ":" + mount_src
for vm in (vm1,vm2):
    vm_session = vm.wait_for_login()
    utils_disk.mount(mount_src, mount_dir, fstype="nfs", session=vm_session)
    utils_net.map_hostname_ipaddress(hosts_dict, vm_session)
    vm_session.close()

shutil.copyfile(vm2_img, vm2_img_bak)

try:
setup_test()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the test is focused on special CPU capabilities, there are requirements for the hardware.
I believe here should be also some prerequisites check, and the test should fail with error
test.error(f"tested CPU capability {l1vm_feature_list} not available on host")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
depend on The PR has dependency on other PRs
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants